Skip to content

Commit a2077a2

Browse files
committed
Registers basic exception handler to handle early failures
1 parent a2ef397 commit a2077a2

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

src/Symfony/Component/ErrorHandler/ErrorHandler.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
use Symfony\Component\ErrorHandler\FatalErrorHandler\FatalErrorHandlerInterface;
2222
use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
2323
use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
24+
use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer;
25+
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
2426

2527
/**
2628
* A generic ErrorHandler for the PHP engine.
@@ -144,6 +146,8 @@ public static function register(self $handler = null, bool $replace = true): sel
144146
$handler->setExceptionHandler($p);
145147
$prev[0]->setExceptionHandler($p);
146148
}
149+
} elseif (null === $prev && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
150+
$handler->setExceptionHandler([$handler, 'sendPhpResponse']);
147151
} else {
148152
$handler->setExceptionHandler($prev);
149153
}
@@ -320,7 +324,7 @@ public function throwAt(int $levels, bool $replace = false): int
320324
public function scopeAt(int $levels, bool $replace = false): int
321325
{
322326
$prev = $this->scopedErrors;
323-
$this->scopedErrors = (int) $levels;
327+
$this->scopedErrors = $levels;
324328
if (!$replace) {
325329
$this->scopedErrors |= $prev;
326330
}
@@ -358,7 +362,7 @@ public function traceAt(int $levels, bool $replace = false): int
358362
public function screamAt(int $levels, bool $replace = false): int
359363
{
360364
$prev = $this->screamedErrors;
361-
$this->screamedErrors = (int) $levels;
365+
$this->screamedErrors = $levels;
362366
if (!$replace) {
363367
$this->screamedErrors |= $prev;
364368
}
@@ -683,6 +687,29 @@ public static function handleFatalError(array $error = null): void
683687
}
684688
}
685689

690+
/**
691+
* Sends the error associated with the given Exception as a plain PHP response.
692+
*
693+
* As this method is mainly called during Kernel boot, where nothing is yet
694+
* available, the Response content is always HTML.
695+
*/
696+
private function sendPhpResponse(\Throwable $exception)
697+
{
698+
$charset = ini_get('default_charset') ?: 'UTF-8';
699+
700+
if (!headers_sent()) {
701+
header('HTTP/1.0 500');
702+
header(sprintf('Content-Type: text/html; charset=%s', $charset));
703+
}
704+
705+
if (class_exists(HtmlErrorRenderer::class)) {
706+
echo (new HtmlErrorRenderer(true))->render(FlattenException::createFromThrowable($exception));
707+
} else {
708+
$message = htmlspecialchars($exception->getMessage(), ENT_COMPAT | ENT_SUBSTITUTE, $charset);
709+
echo sprintf('<!DOCTYPE html><html><head><meta charset="%s" /><meta name="robots" content="noindex,nofollow" /></head><body>%s</body></html>', $charset, $message);
710+
}
711+
}
712+
686713
/**
687714
* Gets the fatal error handlers.
688715
*

src/Symfony/Component/ErrorHandler/composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
"require-dev": {
2323
"symfony/http-kernel": "^3.4|^4.0|^5.0"
2424
},
25+
"suggest": {
26+
"symfony/error-renderer": "For better error rendering"
27+
},
2528
"conflict": {
2629
"symfony/http-kernel": "<3.4"
2730
},

0 commit comments

Comments
 (0)