/api/Slim/Handlers/Error.php
PHP | 239 lines | 139 code | 31 blank | 69 comment | 14 complexity | b89d1a148091d875b901b91688da417e MD5 | raw file
- <?php
- /**
- * Slim Framework (http://slimframework.com)
- *
- * @link https://github.com/slimphp/Slim
- * @copyright Copyright (c) 2011-2015 Josh Lockhart
- * @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
- */
- namespace Slim\Handlers;
- use Exception;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use Slim\Http\Body;
- /**
- * Default Slim application error handler
- *
- * It outputs the error message and diagnostic information in either JSON, XML,
- * or HTML based on the Accept header.
- */
- class Error
- {
- protected $displayErrorDetails;
- /**
- * Known handled content types
- *
- * @var array
- */
- protected $knownContentTypes = [
- 'application/json',
- 'application/xml',
- 'text/xml',
- 'text/html',
- ];
- /**
- * Constructor
- *
- * @param boolean $displayErrorDetails Set to true to display full details
- */
- public function __construct($displayErrorDetails = false)
- {
- $this->displayErrorDetails = (bool)$displayErrorDetails;
- }
- /**
- * Invoke error handler
- *
- * @param ServerRequestInterface $request The most recent Request object
- * @param ResponseInterface $response The most recent Response object
- * @param Exception $exception The caught Exception object
- *
- * @return ResponseInterface
- */
- public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Exception $exception)
- {
- $contentType = $this->determineContentType($request);
- switch ($contentType) {
- case 'application/json':
- $output = $this->renderJsonErrorMessage($exception);
- break;
- case 'text/xml':
- case 'application/xml':
- $output = $this->renderXmlErrorMessage($exception);
- break;
- case 'text/html':
- $output = $this->renderHtmlErrorMessage($exception);
- break;
- }
- $body = new Body(fopen('php://temp', 'r+'));
- $body->write($output);
- return $response
- ->withStatus(500)
- ->withHeader('Content-type', $contentType)
- ->withBody($body);
- }
- /**
- * Render HTML error page
- *
- * @param Exception $exception
- * @return string
- */
- protected function renderHtmlErrorMessage(Exception $exception)
- {
- $title = 'Slim Application Error';
- if ($this->displayErrorDetails) {
- $html = '<p>The application could not run because of the following error:</p>';
- $html .= '<h2>Details</h2>';
- $html .= $this->renderHtmlException($exception);
- while ($exception = $exception->getPrevious()) {
- $html .= '<h2>Previous exception</h2>';
- $html .= $this->renderHtmlException($exception);
- }
- } else {
- $html = '<p>A website error has occurred. Sorry for the temporary inconvenience.</p>';
- }
- $output = sprintf(
- "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>" .
- "<title>%s</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana," .
- "sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{" .
- "display:inline-block;width:65px;}</style></head><body><h1>%s</h1>%s</body></html>",
- $title,
- $title,
- $html
- );
- return $output;
- }
- /**
- * Render exception as HTML.
- *
- * @param Exception $exception
- *
- * @return string
- */
- protected function renderHtmlException(Exception $exception)
- {
- $html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
- if (($code = $exception->getCode())) {
- $html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
- }
- if (($message = $exception->getMessage())) {
- $html .= sprintf('<div><strong>Message:</strong> %s</div>', htmlentities($message));
- }
- if (($file = $exception->getFile())) {
- $html .= sprintf('<div><strong>File:</strong> %s</div>', $file);
- }
- if (($line = $exception->getLine())) {
- $html .= sprintf('<div><strong>Line:</strong> %s</div>', $line);
- }
- if (($trace = $exception->getTraceAsString())) {
- $html .= '<h2>Trace</h2>';
- $html .= sprintf('<pre>%s</pre>', htmlentities($trace));
- }
- return $html;
- }
- /**
- * Render JSON error
- *
- * @param Exception $exception
- * @return string
- */
- protected function renderJsonErrorMessage(Exception $exception)
- {
- $error = [
- 'message' => 'Slim Application Error',
- ];
- if ($this->displayErrorDetails) {
- $error['exception'] = [];
- do {
- $error['exception'][] = [
- 'type' => get_class($exception),
- 'code' => $exception->getCode(),
- 'message' => $exception->getMessage(),
- 'file' => $exception->getFile(),
- 'line' => $exception->getLine(),
- 'trace' => explode("\n", $exception->getTraceAsString()),
- ];
- } while ($exception = $exception->getPrevious());
- }
- return json_encode($error, JSON_PRETTY_PRINT);
- }
- /**
- * Render XML error
- *
- * @param Exception $exception
- * @return string
- */
- protected function renderXmlErrorMessage(Exception $exception)
- {
- $xml = "<error>\n <message>Slim Application Error</message>\n";
- if ($this->displayErrorDetails) {
- do {
- $xml .= " <exception>\n";
- $xml .= " <type>" . get_class($exception) . "</type>\n";
- $xml .= " <code>" . $exception->getCode() . "</code>\n";
- $xml .= " <message>" . $this->createCdataSection($exception->getMessage()) . "</message>\n";
- $xml .= " <file>" . $exception->getFile() . "</file>\n";
- $xml .= " <line>" . $exception->getLine() . "</line>\n";
- $xml .= " <trace>" . $this->createCdataSection($exception->getTraceAsString()) . "</trace>\n";
- $xml .= " </exception>\n";
- } while ($exception = $exception->getPrevious());
- }
- $xml .= "</error>";
- return $xml;
- }
- /**
- * Returns a CDATA section with the given content.
- *
- * @param string $content
- * @return string
- */
- private function createCdataSection($content)
- {
- return sprintf('<![CDATA[%s]]>', str_replace(']]>', ']]]]><![CDATA[>', $content));
- }
- /**
- * Determine which content type we know about is wanted using Accept header
- *
- * @param ServerRequestInterface $request
- * @return string
- */
- private function determineContentType(ServerRequestInterface $request)
- {
- $acceptHeader = $request->getHeaderLine('Accept');
- $selectedContentTypes = array_intersect(explode(',', $acceptHeader), $this->knownContentTypes);
- if (count($selectedContentTypes)) {
- return $selectedContentTypes[0];
- }
- return 'text/html';
- }
- }