Summary:
Ref T12855. PHP7 introduced "Throwables", which are sort of like super exceptions. Some errors that PHP raises at runtime have become Throwables instead of old-school errors now.
The major effect this has is blank pages during development under PHP7 for certain classes of errors: they skip all the nice "show a pretty error" handlers and
This isn't a compelete fix, but catches the most common classes of unexpected Throwable and sends them through the normal machinery. Principally, it shows a nice stack trace again instead of a blank page for a larger class of typos and minor mistakes.
Test Plan:
Before: blank page. After:
{F5007979}
Reviewers: chad, amckinley
Reviewed By: chad
Maniphest Tasks: T12855
Differential Revision: https://secure.phabricator.com/D18136
87 lines
2.2 KiB
PHP
87 lines
2.2 KiB
PHP
<?php
|
|
|
|
final class PhabricatorDefaultRequestExceptionHandler
|
|
extends PhabricatorRequestExceptionHandler {
|
|
|
|
public function getRequestExceptionHandlerPriority() {
|
|
return 900000;
|
|
}
|
|
|
|
public function getRequestExceptionHandlerDescription() {
|
|
return pht('Handles all other exceptions.');
|
|
}
|
|
|
|
public function canHandleRequestThrowable(
|
|
AphrontRequest $request,
|
|
$throwable) {
|
|
|
|
if (!$this->isPhabricatorSite($request)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function handleRequestThrowable(
|
|
AphrontRequest $request,
|
|
$throwable) {
|
|
|
|
$viewer = $this->getViewer($request);
|
|
|
|
// Some types of uninteresting request exceptions don't get logged, usually
|
|
// because they are caused by the background radiation of bot traffic on
|
|
// the internet. These include requests with bad CSRF tokens and
|
|
// questionable "Host" headers.
|
|
$should_log = true;
|
|
if ($throwable instanceof AphrontMalformedRequestException) {
|
|
$should_log = !$throwable->getIsUnlogged();
|
|
}
|
|
|
|
if ($should_log) {
|
|
phlog($throwable);
|
|
}
|
|
|
|
$class = get_class($throwable);
|
|
$message = $throwable->getMessage();
|
|
|
|
if ($throwable instanceof AphrontSchemaQueryException) {
|
|
$message .= "\n\n".pht(
|
|
"NOTE: This usually indicates that the MySQL schema has not been ".
|
|
"properly upgraded. Run '%s' to ensure your schema is up to date.",
|
|
'bin/storage upgrade');
|
|
}
|
|
|
|
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
|
$trace = id(new AphrontStackTraceView())
|
|
->setUser($viewer)
|
|
->setTrace($throwable->getTrace());
|
|
} else {
|
|
$trace = null;
|
|
}
|
|
|
|
$content = phutil_tag(
|
|
'div',
|
|
array('class' => 'aphront-unhandled-exception'),
|
|
array(
|
|
phutil_tag('div', array('class' => 'exception-message'), $message),
|
|
$trace,
|
|
));
|
|
|
|
$dialog = new AphrontDialogView();
|
|
$dialog
|
|
->setTitle(pht('Unhandled Exception ("%s")', $class))
|
|
->setClass('aphront-exception-dialog')
|
|
->setUser($viewer)
|
|
->appendChild($content);
|
|
|
|
if ($request->isAjax()) {
|
|
$dialog->addCancelButton('/', pht('Close'));
|
|
}
|
|
|
|
return id(new AphrontDialogResponse())
|
|
->setDialog($dialog)
|
|
->setHTTPResponseCode(500);
|
|
}
|
|
|
|
}
|