From 259fa20ed535a770247fe86e087740b49c2aba4c Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Wed, 3 Apr 2019 09:05:55 -0400 Subject: [PATCH] Get exception content according to request format --- src/Symfony/Component/Debug/CHANGELOG.md | 2 + .../Component/Debug/ExceptionHandler.php | 155 ++++++++++++++++++ .../Debug/Tests/ExceptionHandlerTest.php | 24 +++ .../EventListener/ExceptionListener.php | 4 +- .../Component/HttpKernel/composer.json | 1 + 5 files changed, 184 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Debug/CHANGELOG.md b/src/Symfony/Component/Debug/CHANGELOG.md index 367e834f01e7e..a13563f61a379 100644 --- a/src/Symfony/Component/Debug/CHANGELOG.md +++ b/src/Symfony/Component/Debug/CHANGELOG.md @@ -8,6 +8,8 @@ CHANGELOG * added `Exception\FlattenException::getAsString` and `Exception\FlattenException::getTraceAsString` to increase compatibility to php exception objects +* added `ExceptionHandler::getFormattedContent()` to get the exception content +according to given format (html, json, xml, txt) 4.0.0 ----- diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index 18d56f3469eb7..403997557e0fb 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -13,6 +13,7 @@ use Symfony\Component\Debug\Exception\FlattenException; use Symfony\Component\Debug\Exception\OutOfMemoryException; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; /** @@ -189,6 +190,160 @@ public function sendPhpResponse($exception) echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception)); } + /** + * Gets the content associated with the given exception. + * + * @param \Exception|FlattenException $exception An \Exception or FlattenException instance + * @param string $format The request format (html, json, xml, txt) + * + * @return string The formatted content as a string + */ + public function getFormattedContent($exception, string $format): string + { + switch ($format) { + case 'json': + return $this->getJson($exception); + case 'xml': + case 'rdf': + return $this->getXml($exception); + case 'txt': + return $this->getTxt($exception); + default: + return $this->getHtml($exception); + } + } + + /** + * Gets the JSON content associated with the given exception. + * + * @param \Exception|FlattenException $exception An \Exception or FlattenException instance + * + * @return string The JSON content as a string + */ + public function getJson($exception): string + { + if (!$exception instanceof FlattenException) { + $exception = FlattenException::create($exception); + } + + if (404 === $statusCode = $exception->getStatusCode()) { + $title = 'Not Found'; + } elseif (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) { + $title = Response::$statusTexts[$statusCode]; + } else { + $title = 'Internal Server Error'; + } + + $content = [ + 'title' => $title, + 'status' => $statusCode, + 'detail' => $this->escapeHtml($exception->getMessage()), + ]; + + if ($this->debug) { + $content['exceptions'] = $exception->toArray(); + } + + return (string) json_encode($content); + } + + /** + * Gets the XML content associated with the given exception. + * + * @param \Exception|FlattenException $exception An \Exception or FlattenException instance + * + * @return string The XML content as a string + */ + public function getXml($exception): string + { + if (!$exception instanceof FlattenException) { + $exception = FlattenException::create($exception); + } + + if (404 === $statusCode = $exception->getStatusCode()) { + $title = 'Not Found'; + } elseif (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) { + $title = Response::$statusTexts[$statusCode]; + } else { + $title = 'Internal Server Error'; + } + $message = $this->escapeHtml($exception->getMessage()); + + $exceptions = ''; + if ($this->debug) { + $exceptions .= ''; + foreach ($exception->toArray() as $e) { + $exceptions .= sprintf('', $e['class'], $this->escapeHtml($e['message'])); + foreach ($e['trace'] as $trace) { + $exceptions .= ''; + if ($trace['function']) { + $exceptions .= sprintf('at %s%s%s(%s) ', $trace['class'], $trace['type'], $trace['function'], strip_tags($this->formatArgs($trace['args']))); + } + if (isset($trace['file'], $trace['line'])) { + $exceptions .= strip_tags($this->formatPath($trace['file'], $trace['line'])); + } + $exceptions .= ''; + } + $exceptions .= ''; + } + $exceptions .= ''; + } + + return << + + {$title} + {$statusCode} + {$message} + {$exceptions} + +EOF; + } + + /** + * Gets the TXT content associated with the given exception. + * + * @param \Exception|FlattenException $exception An \Exception or FlattenException instance + * + * @return string The TXT content as a string + */ + public function getTxt($exception): string + { + if (!$exception instanceof FlattenException) { + $exception = FlattenException::create($exception); + } + + if (404 === $statusCode = $exception->getStatusCode()) { + $title = 'Not Found'; + } elseif (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) { + $title = Response::$statusTexts[$statusCode]; + } else { + $title = 'Internal Server Error'; + } + + $content = sprintf("[title] %s\n", $title); + $content .= sprintf("[status] %s\n", $statusCode); + $content .= sprintf("[detail] %s\n", $exception->getMessage()); + + if ($this->debug) { + foreach ($exception->toArray() as $i => $e) { + $content .= sprintf("[%d] %s: %s\n", $i + 1, $e['class'], $e['message']); + + foreach ($e['trace'] as $trace) { + if ($trace['function']) { + $content .= sprintf('at %s%s%s(%s) ', $trace['class'], $trace['type'], $trace['function'], strip_tags($this->formatArgs($trace['args']))); + } + if (isset($trace['file'], $trace['line'])) { + $content .= strip_tags($this->formatPath($trace['file'], $trace['line'])); + } + $content .= "\n"; + } + } + } + + return $content; + } + /** * Gets the full HTML content associated with the given exception. * diff --git a/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php b/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php index 4910fe5ec96be..955ecdec0717f 100644 --- a/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php @@ -139,4 +139,28 @@ public function testHandleOutOfMemoryException() $handler->handle($exception); } + + public function testJsonExceptionContent() + { + $handler = new ExceptionHandler(true); + $content = $handler->getJson(new \RuntimeException('Foo')); + + $this->assertStringMatchesFormat('{"title":"Internal Server Error","status":500,"detail":"Foo","exceptions":[{"message":"Foo","class":"RuntimeException"%S}]}', $content); + } + + public function testXmlExceptionContent() + { + $handler = new ExceptionHandler(true); + $content = $handler->getXml(new \RuntimeException('Foo')); + + $this->assertStringMatchesFormat('%A%AInternal Server Error%A500%AFoo%A%A', $content); + } + + public function testTxtExceptionContent() + { + $handler = new ExceptionHandler(true); + $content = $handler->getTxt(new \RuntimeException('Foo')); + + $this->assertStringMatchesFormat("[title] Internal Server Error\n[status] 500\n[detail] Foo\n[1] RuntimeException: Foo\nin ExceptionHandlerTest.php line %A", $content); + } } diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php index 8e31ecc944e37..e32532cf0bdc4 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php @@ -151,10 +151,10 @@ protected function duplicateRequest(\Exception $exception, Request $request) { $attributes = [ 'exception' => $exception = FlattenException::create($exception), - '_controller' => $this->controller ?: function () use ($exception) { + '_controller' => $this->controller ?: function () use ($exception, $request) { $handler = new ExceptionHandler($this->debug, $this->charset, $this->fileLinkFormat); - return new Response($handler->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders()); + return new Response($handler->getFormattedContent($exception, $request->getRequestFormat()), $exception->getStatusCode(), $exception->getHeaders()); }, 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, ]; diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index ca818d16707ab..25ce022c749ef 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -48,6 +48,7 @@ "conflict": { "symfony/browser-kit": "<4.3", "symfony/config": "<3.4", + "symfony/debug": "<4.3", "symfony/dependency-injection": "<4.2", "symfony/translation": "<4.2", "symfony/var-dumper": "<4.1.1", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy