Completed
Push — 3.x ( c13855...2f189b )
by Sam
04:02
created

Error::renderHtmlExceptionOrError()   C

Complexity

Conditions 8
Paths 33

Size

Total Lines 31
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 31
rs 5.3846
c 1
b 0
f 0
cc 8
eloc 16
nc 33
nop 1
1
<?php
2
/**
3
 * Slim Framework (https://slimframework.com)
4
 *
5
 * @link      https://github.com/slimphp/Slim
6
 * @copyright Copyright (c) 2011-2017 Josh Lockhart
7
 * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
8
 */
9
namespace Slim\Handlers;
10
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Slim\Http\Body;
14
use UnexpectedValueException;
15
16
/**
17
 * Default Slim application error handler
18
 *
19
 * It outputs the error message and diagnostic information in either JSON, XML,
20
 * or HTML based on the Accept header.
21
 */
22
class Error extends AbstractError
23
{
24
    /**
25
     * Invoke error handler
26
     *
27
     * @param ServerRequestInterface $request   The most recent Request object
28
     * @param ResponseInterface      $response  The most recent Response object
29
     * @param \Exception             $exception The caught Exception object
30
     *
31
     * @return ResponseInterface
32
     * @throws UnexpectedValueException
33
     */
34
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, \Exception $exception)
35
    {
36
        $contentType = $this->determineContentType($request);
37
        switch ($contentType) {
38
            case 'application/json':
39
                $output = $this->renderJsonErrorMessage($exception);
40
                break;
41
42
            case 'text/xml':
43
            case 'application/xml':
44
                $output = $this->renderXmlErrorMessage($exception);
45
                break;
46
47
            case 'text/html':
48
                $output = $this->renderHtmlErrorMessage($exception);
49
                break;
50
51
            default:
52
                throw new UnexpectedValueException('Cannot render unknown content type ' . $contentType);
53
        }
54
55
        $this->writeToErrorLog($exception);
56
57
        $body = new Body(fopen('php://temp', 'r+'));
58
        $body->write($output);
59
60
        return $response
61
                ->withStatus(500)
62
                ->withHeader('Content-type', $contentType)
63
                ->withBody($body);
64
    }
65
66
    /**
67
     * Render HTML error page
68
     *
69
     * @param  \Exception $exception
70
     *
71
     * @return string
72
     */
73
    protected function renderHtmlErrorMessage(\Exception $exception)
74
    {
75
        $title = 'Slim Application Error';
76
77
        if ($this->displayErrorDetails) {
78
            $html = '<p>The application could not run because of the following error:</p>';
79
            $html .= '<h2>Details</h2>';
80
            $html .= $this->renderHtmlException($exception);
81
82
            while ($exception = $exception->getPrevious()) {
83
                $html .= '<h2>Previous exception</h2>';
84
                $html .= $this->renderHtmlExceptionOrError($exception);
85
            }
86
        } else {
87
            $html = '<p>A website error has occurred. Sorry for the temporary inconvenience.</p>';
88
        }
89
90
        $output = sprintf(
91
            "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>" .
92
            "<title>%s</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana," .
93
            "sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{" .
94
            "display:inline-block;width:65px;}</style></head><body><h1>%s</h1>%s</body></html>",
95
            $title,
96
            $title,
97
            $html
98
        );
99
100
        return $output;
101
    }
102
103
    /**
104
     * Render exception as HTML.
105
     *
106
     * Provided for backwards compatibility; use renderHtmlExceptionOrError().
107
     *
108
     * @param \Exception $exception
109
     *
110
     * @return string
111
     */
112
    protected function renderHtmlException(\Exception $exception)
113
    {
114
        return $this->renderHtmlExceptionOrError($exception);
115
    }
116
117
    /**
118
     * Render exception or error as HTML.
119
     *
120
     * @param \Exception|\Error $exception
121
     *
122
     * @return string
123
     */
124
    protected function renderHtmlExceptionOrError($exception)
125
    {
126
        if (!$exception instanceof \Exception && !$exception instanceof \Error) {
0 ignored issues
show
Bug introduced by
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
127
            throw new \RuntimeException("Unexpected type. Expected Exception or Error.");
128
        }
129
130
        $html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
131
132
        if (($code = $exception->getCode())) {
133
            $html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
134
        }
135
136
        if (($message = $exception->getMessage())) {
137
            $html .= sprintf('<div><strong>Message:</strong> %s</div>', htmlentities($message));
138
        }
139
140
        if (($file = $exception->getFile())) {
141
            $html .= sprintf('<div><strong>File:</strong> %s</div>', $file);
142
        }
143
144
        if (($line = $exception->getLine())) {
145
            $html .= sprintf('<div><strong>Line:</strong> %s</div>', $line);
146
        }
147
148
        if (($trace = $exception->getTraceAsString())) {
149
            $html .= '<h2>Trace</h2>';
150
            $html .= sprintf('<pre>%s</pre>', htmlentities($trace));
151
        }
152
153
        return $html;
154
    }
155
156
    /**
157
     * Render JSON error
158
     *
159
     * @param \Exception $exception
160
     *
161
     * @return string
162
     */
163
    protected function renderJsonErrorMessage(\Exception $exception)
164
    {
165
        $error = [
166
            'message' => 'Slim Application Error',
167
        ];
168
169
        if ($this->displayErrorDetails) {
170
            $error['exception'] = [];
171
172
            do {
173
                $error['exception'][] = [
174
                    'type' => get_class($exception),
175
                    'code' => $exception->getCode(),
176
                    'message' => $exception->getMessage(),
177
                    'file' => $exception->getFile(),
178
                    'line' => $exception->getLine(),
179
                    'trace' => explode("\n", $exception->getTraceAsString()),
180
                ];
181
            } while ($exception = $exception->getPrevious());
182
        }
183
184
        return json_encode($error, JSON_PRETTY_PRINT);
185
    }
186
187
    /**
188
     * Render XML error
189
     *
190
     * @param \Exception $exception
191
     *
192
     * @return string
193
     */
194
    protected function renderXmlErrorMessage(\Exception $exception)
195
    {
196
        $xml = "<error>\n  <message>Slim Application Error</message>\n";
197
        if ($this->displayErrorDetails) {
198
            do {
199
                $xml .= "  <exception>\n";
200
                $xml .= "    <type>" . get_class($exception) . "</type>\n";
201
                $xml .= "    <code>" . $exception->getCode() . "</code>\n";
202
                $xml .= "    <message>" . $this->createCdataSection($exception->getMessage()) . "</message>\n";
203
                $xml .= "    <file>" . $exception->getFile() . "</file>\n";
204
                $xml .= "    <line>" . $exception->getLine() . "</line>\n";
205
                $xml .= "    <trace>" . $this->createCdataSection($exception->getTraceAsString()) . "</trace>\n";
206
                $xml .= "  </exception>\n";
207
            } while ($exception = $exception->getPrevious());
208
        }
209
        $xml .= "</error>";
210
211
        return $xml;
212
    }
213
214
    /**
215
     * Returns a CDATA section with the given content.
216
     *
217
     * @param  string $content
218
     * @return string
219
     */
220
    private function createCdataSection($content)
221
    {
222
        return sprintf('<![CDATA[%s]]>', str_replace(']]>', ']]]]><![CDATA[>', $content));
223
    }
224
}
225