feature #33327 [ErrorHandler] Registering basic exception handler for late failures (yceruto)

This PR was merged into the 4.4 branch.

Discussion
----------

[ErrorHandler] Registering basic exception handler for late failures

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

Follow-up https://github.com/symfony/symfony/pull/33260 but when all handlers fail.

It'll becomes common since 4.4 where the user has control over the error rendering mechanism. If they make a mistake, we have a support page to show it, currently a blank page is displayed.

Commits
-------

ffab734615 registering basic exception handler for late failures
This commit is contained in:
Fabien Potencier 2019-09-03 18:17:34 +02:00
commit bb3652a37c
2 changed files with 34 additions and 8 deletions

View File

@ -592,7 +592,11 @@ class ErrorHandler
}
}
$exceptionHandler = $this->exceptionHandler;
$this->exceptionHandler = null;
if ((!\is_array($exceptionHandler) || !$exceptionHandler[0] instanceof self || 'sendPhpResponse' !== $exceptionHandler[1]) && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
$this->exceptionHandler = [$this, 'sendPhpResponse'];
} else {
$this->exceptionHandler = null;
}
try {
if (null !== $exceptionHandler) {
return $exceptionHandler($exception);
@ -696,18 +700,28 @@ class ErrorHandler
private function sendPhpResponse(\Throwable $exception)
{
$charset = ini_get('default_charset') ?: 'UTF-8';
if (!headers_sent()) {
header('HTTP/1.0 500');
header(sprintf('Content-Type: text/html; charset=%s', $charset));
}
$statusCode = 500;
$headers = [];
if (class_exists(HtmlErrorRenderer::class)) {
echo (new HtmlErrorRenderer(true))->render(FlattenException::createFromThrowable($exception));
$exception = FlattenException::createFromThrowable($exception);
$statusCode = $exception->getStatusCode();
$headers = $exception->getHeaders();
$response = (new HtmlErrorRenderer(true))->render($exception);
} else {
$message = htmlspecialchars($exception->getMessage(), ENT_COMPAT | ENT_SUBSTITUTE, $charset);
echo sprintf('<!DOCTYPE html><html><head><meta charset="%s" /><meta name="robots" content="noindex,nofollow" /></head><body>%s</body></html>', $charset, $message);
$response = sprintf('<!DOCTYPE html><html><head><meta charset="%s" /><meta name="robots" content="noindex,nofollow" /></head><body>%s</body></html>', $charset, $message);
}
if (!headers_sent()) {
header(sprintf('HTTP/1.0 %s', $statusCode));
foreach ($headers as $name => $value) {
header($name.': '.$value, false);
}
header('Content-Type: text/html; charset='.$charset);
}
echo $response;
}
/**

View File

@ -557,6 +557,18 @@ class ErrorHandlerTest extends TestCase
$handler->handleException(new \Exception());
}
public function testSendPhpResponse()
{
$handler = new ErrorHandler();
$handler->setExceptionHandler([$handler, 'sendPhpResponse']);
ob_start();
$handler->handleException(new \RuntimeException('Class Foo not found'));
$response = ob_get_clean();
self::assertStringContainsString('Class Foo not found', $response);
}
/**
* @dataProvider errorHandlerWhenLoggingProvider
*/