|
21 | 21 | use Symfony\Component\ErrorHandler\FatalErrorHandler\FatalErrorHandlerInterface;
|
22 | 22 | use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
|
23 | 23 | use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
|
| 24 | +use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; |
| 25 | +use Symfony\Component\ErrorRenderer\Exception\FlattenException; |
24 | 26 |
|
25 | 27 | /**
|
26 | 28 | * A generic ErrorHandler for the PHP engine.
|
@@ -144,6 +146,8 @@ public static function register(self $handler = null, bool $replace = true): sel
|
144 | 146 | $handler->setExceptionHandler($p);
|
145 | 147 | $prev[0]->setExceptionHandler($p);
|
146 | 148 | }
|
| 149 | + } elseif (null === $prev && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { |
| 150 | + $handler->setExceptionHandler([$handler, 'sendPhpResponse']); |
147 | 151 | } else {
|
148 | 152 | $handler->setExceptionHandler($prev);
|
149 | 153 | }
|
@@ -320,7 +324,7 @@ public function throwAt(int $levels, bool $replace = false): int
|
320 | 324 | public function scopeAt(int $levels, bool $replace = false): int
|
321 | 325 | {
|
322 | 326 | $prev = $this->scopedErrors;
|
323 |
| - $this->scopedErrors = (int) $levels; |
| 327 | + $this->scopedErrors = $levels; |
324 | 328 | if (!$replace) {
|
325 | 329 | $this->scopedErrors |= $prev;
|
326 | 330 | }
|
@@ -358,7 +362,7 @@ public function traceAt(int $levels, bool $replace = false): int
|
358 | 362 | public function screamAt(int $levels, bool $replace = false): int
|
359 | 363 | {
|
360 | 364 | $prev = $this->screamedErrors;
|
361 |
| - $this->screamedErrors = (int) $levels; |
| 365 | + $this->screamedErrors = $levels; |
362 | 366 | if (!$replace) {
|
363 | 367 | $this->screamedErrors |= $prev;
|
364 | 368 | }
|
@@ -683,6 +687,32 @@ public static function handleFatalError(array $error = null): void
|
683 | 687 | }
|
684 | 688 | }
|
685 | 689 |
|
| 690 | + /** |
| 691 | + * Sends the error associated with the given Exception as a plain PHP response. |
| 692 | + * |
| 693 | + * This method uses plain PHP functions like header() and echo to output |
| 694 | + * the response. |
| 695 | + * |
| 696 | + * As this method is mainly called during Kernel boot, where nothing is yet |
| 697 | + * available, the Response content is always HTML. |
| 698 | + */ |
| 699 | + private function sendPhpResponse(\Throwable $exception) |
| 700 | + { |
| 701 | + $charset = ini_get('default_charset') ?: 'UTF-8'; |
| 702 | + |
| 703 | + if (!headers_sent()) { |
| 704 | + header('HTTP/1.0 500'); |
| 705 | + header(sprintf('Content-Type: text/html; charset=%s', $charset)); |
| 706 | + } |
| 707 | + |
| 708 | + if (class_exists(HtmlErrorRenderer::class)) { |
| 709 | + echo (new HtmlErrorRenderer(true))->render(FlattenException::createFromThrowable($exception)); |
| 710 | + } else { |
| 711 | + $message = htmlspecialchars($exception->getMessage(), ENT_COMPAT | ENT_SUBSTITUTE, $charset); |
| 712 | + echo sprintf('<!DOCTYPE html><html><head><meta charset="%s" /><meta name="robots" content="noindex,nofollow" /></head><body>%s</body></html>', $charset, $message); |
| 713 | + } |
| 714 | + } |
| 715 | + |
686 | 716 | /**
|
687 | 717 | * Gets the fatal error handlers.
|
688 | 718 | *
|
|
0 commit comments