1 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,466 +0,0 @@ |
1 |
-<?php |
|
2 |
- |
|
3 |
-/* |
|
4 |
- * This file is part of the Symfony package. |
|
5 |
- * |
|
6 |
- * (c) Fabien Potencier <fabien@symfony.com> |
|
7 |
- * |
|
8 |
- * For the full copyright and license information, please view the LICENSE |
|
9 |
- * file that was distributed with this source code. |
|
10 |
- */ |
|
11 |
- |
|
12 |
-namespace Symfony\Component\Debug; |
|
13 |
- |
|
14 |
-use Symfony\Component\Debug\Exception\FlattenException; |
|
15 |
-use Symfony\Component\Debug\Exception\OutOfMemoryException; |
|
16 |
-use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; |
|
17 |
- |
|
18 |
-/** |
|
19 |
- * ExceptionHandler converts an exception to a Response object. |
|
20 |
- * |
|
21 |
- * It is mostly useful in debug mode to replace the default PHP/XDebug |
|
22 |
- * output with something prettier and more useful. |
|
23 |
- * |
|
24 |
- * As this class is mainly used during Kernel boot, where nothing is yet |
|
25 |
- * available, the Response content is always HTML. |
|
26 |
- * |
|
27 |
- * @author Fabien Potencier <fabien@symfony.com> |
|
28 |
- * @author Nicolas Grekas <p@tchwork.com> |
|
29 |
- * |
|
30 |
- * @final since Symfony 4.3 |
|
31 |
- */ |
|
32 |
-class ExceptionHandler |
|
33 |
-{ |
|
34 |
- private const GHOST_ADDONS = [ |
|
35 |
- '02-14' => self::GHOST_HEART, |
|
36 |
- '02-29' => self::GHOST_PLUS, |
|
37 |
- '10-18' => self::GHOST_GIFT, |
|
38 |
- ]; |
|
39 |
- |
|
40 |
- private const GHOST_GIFT = 'M124.005 5.36c.396-.715 1.119-1.648-.124-1.873-.346-.177-.692-.492-1.038-.141-.769.303-1.435.728-.627 1.523.36.514.685 1.634 1.092 1.758.242-.417.47-.842.697-1.266zm-1.699 1.977c-.706-1.26-1.274-2.612-2.138-3.774-1.051-1.123-3.122-.622-3.593.825-.625 1.431.724 3.14 2.251 2.96 1.159.02 2.324.072 3.48-.011zm5.867.043c1.502-.202 2.365-2.092 1.51-3.347-.757-1.34-2.937-1.387-3.698-.025-.659 1.1-1.23 2.25-1.835 3.38 1.336.077 2.686.06 4.023-.008zm2.487 1.611c.512-.45 2.494-.981.993-1.409-.372-.105-.805-.59-1.14-.457-.726.902-1.842 1.432-3.007 1.376-.228.075-1.391-.114-1.077.1.822.47 1.623.979 2.474 1.395.595-.317 1.173-.667 1.757-1.005zm-11.696.255l1.314-.765c-1.338-.066-2.87.127-3.881-.95-.285-.319-.559-.684-.954-.282-.473.326-1.929.66-.808 1.058.976.576 1.945 1.167 2.946 1.701.476-.223.926-.503 1.383-.762zm6.416 2.846c.567-.456 1.942-.89 1.987-1.38-1.282-.737-2.527-1.56-3.87-2.183-.461-.175-.835.094-1.207.328-1.1.654-2.225 1.267-3.288 1.978 1.39.86 2.798 1.695 4.219 2.504.725-.407 1.44-.83 2.16-1.247zm5.692 1.423l1.765-1.114c-.005-1.244.015-2.488-.019-3.732a77.306 77.306 0 0 0-3.51 2.084c-.126 1.282-.062 2.586-.034 3.876.607-.358 1.2-.741 1.798-1.114zm-13.804-.784c.06-1.06.19-2.269-1.09-2.583-.807-.376-1.926-1.341-2.548-1.332-.02 1.195-.01 2.39-.011 3.585 1.192.744 2.364 1.524 3.582 2.226.119-.616.041-1.269.067-1.896zm8.541 4.105l2.117-1.336c-.003-1.284.05-2.57-.008-3.853-.776.223-1.662.91-2.48 1.337l-1.834 1.075c.012 1.37-.033 2.744.044 4.113.732-.427 1.443-.887 2.161-1.336zm-2.957-.72v-2.057c-1.416-.828-2.828-1.664-4.25-2.482-.078 1.311-.033 2.627-.045 3.94 1.416.887 2.817 1.798 4.25 2.655.057-.683.036-1.372.045-2.057zm8.255 2.755l1.731-1.153c-.024-1.218.06-2.453-.062-3.658-1.2.685-2.358 1.464-3.537 2.195.028 1.261-.058 2.536.072 3.786.609-.373 1.2-.777 1.796-1.17zm-13.851-.683l-.014-1.916c-1.193-.746-2.37-1.517-3.58-2.234-.076 1.224-.033 2.453-.044 3.679 1.203.796 2.392 1.614 3.61 2.385.048-.636.024-1.276.028-1.914zm8.584 4.199l2.102-1.396c-.002-1.298.024-2.596-.01-3.893-1.427.88-2.843 1.775-4.25 2.686-.158 1.253-.055 2.545-.056 3.811.437.266 1.553-.912 2.214-1.208zm-2.988-.556c-.085-.894.365-2.154-.773-2.5-1.146-.727-2.288-1.46-3.45-2.163-.17 1.228.008 2.508-.122 3.751a79.399 79.399 0 0 0 4.278 2.885c.117-.641.044-1.32.067-1.973zm-4.872-.236l-5.087-3.396c.002-3.493-.047-6.988.015-10.48.85-.524 1.753-.954 2.627-1.434-.564-1.616.25-3.58 1.887-4.184 1.372-.563 3.025-.055 3.9 1.13l1.906-.978 1.916.987c.915-1.086 2.483-1.706 3.842-1.097 1.631.573 2.52 2.532 1.936 4.145.88.497 1.837.886 2.644 1.492.036 3.473 0 6.946-.003 10.419-3.374 2.233-6.693 4.55-10.122 6.699-.997 0-1.858-1.083-2.783-1.522a735.316 735.316 0 0 1-2.678-1.781z'; |
|
41 |
- private const GHOST_HEART = 'M125.914 8.305c3.036-8.71 14.933 0 0 11.2-14.932-11.2-3.036-19.91 0-11.2z'; |
|
42 |
- private const GHOST_PLUS = 'M111.368 8.97h7.324V1.645h7.512v7.323h7.324v7.513h-7.324v7.323h-7.512v-7.323h-7.324z'; |
|
43 |
- |
|
44 |
- private $debug; |
|
45 |
- private $charset; |
|
46 |
- private $handler; |
|
47 |
- private $caughtBuffer; |
|
48 |
- private $caughtLength; |
|
49 |
- private $fileLinkFormat; |
|
50 |
- |
|
51 |
- public function __construct(bool $debug = true, string $charset = null, $fileLinkFormat = null) |
|
52 |
- { |
|
53 |
- $this->debug = $debug; |
|
54 |
- $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8'; |
|
55 |
- $this->fileLinkFormat = $fileLinkFormat; |
|
56 |
- } |
|
57 |
- |
|
58 |
- /** |
|
59 |
- * Registers the exception handler. |
|
60 |
- * |
|
61 |
- * @param bool $debug Enable/disable debug mode, where the stack trace is displayed |
|
62 |
- * @param string|null $charset The charset used by exception messages |
|
63 |
- * @param string|null $fileLinkFormat The IDE link template |
|
64 |
- * |
|
65 |
- * @return static |
|
66 |
- */ |
|
67 |
- public static function register($debug = true, $charset = null, $fileLinkFormat = null) |
|
68 |
- { |
|
69 |
- $handler = new static($debug, $charset, $fileLinkFormat); |
|
70 |
- |
|
71 |
- $prev = set_exception_handler([$handler, 'handle']); |
|
72 |
- if (\is_array($prev) && $prev[0] instanceof ErrorHandler) { |
|
73 |
- restore_exception_handler(); |
|
74 |
- $prev[0]->setExceptionHandler([$handler, 'handle']); |
|
75 |
- } |
|
76 |
- |
|
77 |
- return $handler; |
|
78 |
- } |
|
79 |
- |
|
80 |
- /** |
|
81 |
- * Sets a user exception handler. |
|
82 |
- * |
|
83 |
- * @param callable $handler An handler that will be called on Exception |
|
84 |
- * |
|
85 |
- * @return callable|null The previous exception handler if any |
|
86 |
- */ |
|
87 |
- public function setHandler(callable $handler = null) |
|
88 |
- { |
|
89 |
- $old = $this->handler; |
|
90 |
- $this->handler = $handler; |
|
91 |
- |
|
92 |
- return $old; |
|
93 |
- } |
|
94 |
- |
|
95 |
- /** |
|
96 |
- * Sets the format for links to source files. |
|
97 |
- * |
|
98 |
- * @param string|FileLinkFormatter $fileLinkFormat The format for links to source files |
|
99 |
- * |
|
100 |
- * @return string The previous file link format |
|
101 |
- */ |
|
102 |
- public function setFileLinkFormat($fileLinkFormat) |
|
103 |
- { |
|
104 |
- $old = $this->fileLinkFormat; |
|
105 |
- $this->fileLinkFormat = $fileLinkFormat; |
|
106 |
- |
|
107 |
- return $old; |
|
108 |
- } |
|
109 |
- |
|
110 |
- /** |
|
111 |
- * Sends a response for the given Exception. |
|
112 |
- * |
|
113 |
- * To be as fail-safe as possible, the exception is first handled |
|
114 |
- * by our simple exception handler, then by the user exception handler. |
|
115 |
- * The latter takes precedence and any output from the former is cancelled, |
|
116 |
- * if and only if nothing bad happens in this handling path. |
|
117 |
- */ |
|
118 |
- public function handle(\Exception $exception) |
|
119 |
- { |
|
120 |
- if (null === $this->handler || $exception instanceof OutOfMemoryException) { |
|
121 |
- $this->sendPhpResponse($exception); |
|
122 |
- |
|
123 |
- return; |
|
124 |
- } |
|
125 |
- |
|
126 |
- $caughtLength = $this->caughtLength = 0; |
|
127 |
- |
|
128 |
- ob_start(function ($buffer) { |
|
129 |
- $this->caughtBuffer = $buffer; |
|
130 |
- |
|
131 |
- return ''; |
|
132 |
- }); |
|
133 |
- |
|
134 |
- $this->sendPhpResponse($exception); |
|
135 |
- while (null === $this->caughtBuffer && ob_end_flush()) { |
|
136 |
- // Empty loop, everything is in the condition |
|
137 |
- } |
|
138 |
- if (isset($this->caughtBuffer[0])) { |
|
139 |
- ob_start(function ($buffer) { |
|
140 |
- if ($this->caughtLength) { |
|
141 |
- // use substr_replace() instead of substr() for mbstring overloading resistance |
|
142 |
- $cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength); |
|
143 |
- if (isset($cleanBuffer[0])) { |
|
144 |
- $buffer = $cleanBuffer; |
|
145 |
- } |
|
146 |
- } |
|
147 |
- |
|
148 |
- return $buffer; |
|
149 |
- }); |
|
150 |
- |
|
151 |
- echo $this->caughtBuffer; |
|
152 |
- $caughtLength = ob_get_length(); |
|
153 |
- } |
|
154 |
- $this->caughtBuffer = null; |
|
155 |
- |
|
156 |
- try { |
|
157 |
- ($this->handler)($exception); |
|
158 |
- $this->caughtLength = $caughtLength; |
|
159 |
- } catch (\Exception $e) { |
|
160 |
- if (!$caughtLength) { |
|
161 |
- // All handlers failed. Let PHP handle that now. |
|
162 |
- throw $exception; |
|
163 |
- } |
|
164 |
- } |
|
165 |
- } |
|
166 |
- |
|
167 |
- /** |
|
168 |
- * Sends the error associated with the given Exception as a plain PHP response. |
|
169 |
- * |
|
170 |
- * This method uses plain PHP functions like header() and echo to output |
|
171 |
- * the response. |
|
172 |
- * |
|
173 |
- * @param \Exception|FlattenException $exception An \Exception or FlattenException instance |
|
174 |
- */ |
|
175 |
- public function sendPhpResponse($exception) |
|
176 |
- { |
|
177 |
- if (!$exception instanceof FlattenException) { |
|
178 |
- $exception = FlattenException::create($exception); |
|
179 |
- } |
|
180 |
- |
|
181 |
- if (!headers_sent()) { |
|
182 |
- header(sprintf('HTTP/1.0 %s', $exception->getStatusCode())); |
|
183 |
- foreach ($exception->getHeaders() as $name => $value) { |
|
184 |
- header($name.': '.$value, false); |
|
185 |
- } |
|
186 |
- header('Content-Type: text/html; charset='.$this->charset); |
|
187 |
- } |
|
188 |
- |
|
189 |
- echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception)); |
|
190 |
- } |
|
191 |
- |
|
192 |
- /** |
|
193 |
- * Gets the full HTML content associated with the given exception. |
|
194 |
- * |
|
195 |
- * @param \Exception|FlattenException $exception An \Exception or FlattenException instance |
|
196 |
- * |
|
197 |
- * @return string The HTML content as a string |
|
198 |
- */ |
|
199 |
- public function getHtml($exception) |
|
200 |
- { |
|
201 |
- if (!$exception instanceof FlattenException) { |
|
202 |
- $exception = FlattenException::create($exception); |
|
203 |
- } |
|
204 |
- |
|
205 |
- return $this->decorate($this->getContent($exception), $this->getStylesheet($exception)); |
|
206 |
- } |
|
207 |
- |
|
208 |
- /** |
|
209 |
- * Gets the HTML content associated with the given exception. |
|
210 |
- * |
|
211 |
- * @return string The content as a string |
|
212 |
- */ |
|
213 |
- public function getContent(FlattenException $exception) |
|
214 |
- { |
|
215 |
- switch ($exception->getStatusCode()) { |
|
216 |
- case 404: |
|
217 |
- $title = 'Sorry, the page you are looking for could not be found.'; |
|
218 |
- break; |
|
219 |
- default: |
|
220 |
- $title = $this->debug ? $this->escapeHtml($exception->getMessage()) : 'Whoops, looks like something went wrong.'; |
|
221 |
- } |
|
222 |
- |
|
223 |
- if (!$this->debug) { |
|
224 |
- return <<<EOF |
|
225 |
- <div class="container"> |
|
226 |
- <h1>$title</h1> |
|
227 |
- </div> |
|
228 |
-EOF; |
|
229 |
- } |
|
230 |
- |
|
231 |
- $content = ''; |
|
232 |
- try { |
|
233 |
- $count = \count($exception->getAllPrevious()); |
|
234 |
- $total = $count + 1; |
|
235 |
- foreach ($exception->toArray() as $position => $e) { |
|
236 |
- $ind = $count - $position + 1; |
|
237 |
- $class = $this->formatClass($e['class']); |
|
238 |
- $message = nl2br($this->escapeHtml($e['message'])); |
|
239 |
- $content .= sprintf(<<<'EOF' |
|
240 |
- <div class="trace trace-as-html"> |
|
241 |
- <table class="trace-details"> |
|
242 |
- <thead class="trace-head"><tr><th> |
|
243 |
- <h3 class="trace-class"> |
|
244 |
- <span class="text-muted">(%d/%d)</span> |
|
245 |
- <span class="exception_title">%s</span> |
|
246 |
- </h3> |
|
247 |
- <p class="break-long-words trace-message">%s</p> |
|
248 |
- </th></tr></thead> |
|
249 |
- <tbody> |
|
250 |
-EOF |
|
251 |
- , $ind, $total, $class, $message); |
|
252 |
- foreach ($e['trace'] as $trace) { |
|
253 |
- $content .= '<tr><td>'; |
|
254 |
- if ($trace['function']) { |
|
255 |
- $content .= sprintf('at <span class="trace-class">%s</span><span class="trace-type">%s</span><span class="trace-method">%s</span>(<span class="trace-arguments">%s</span>)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args'])); |
|
256 |
- } |
|
257 |
- if (isset($trace['file']) && isset($trace['line'])) { |
|
258 |
- $content .= $this->formatPath($trace['file'], $trace['line']); |
|
259 |
- } |
|
260 |
- $content .= "</td></tr>\n"; |
|
261 |
- } |
|
262 |
- |
|
263 |
- $content .= "</tbody>\n</table>\n</div>\n"; |
|
264 |
- } |
|
265 |
- } catch (\Exception $e) { |
|
266 |
- // something nasty happened and we cannot throw an exception anymore |
|
267 |
- if ($this->debug) { |
|
268 |
- $e = FlattenException::create($e); |
|
269 |
- $title = sprintf('Exception thrown when handling an exception (%s: %s)', $e->getClass(), $this->escapeHtml($e->getMessage())); |
|
270 |
- } else { |
|
271 |
- $title = 'Whoops, looks like something went wrong.'; |
|
272 |
- } |
|
273 |
- } |
|
274 |
- |
|
275 |
- $symfonyGhostImageContents = $this->getSymfonyGhostAsSvg(); |
|
276 |
- |
|
277 |
- return <<<EOF |
|
278 |
- <div class="exception-summary"> |
|
279 |
- <div class="container"> |
|
280 |
- <div class="exception-message-wrapper"> |
|
281 |
- <h1 class="break-long-words exception-message">$title</h1> |
|
282 |
- <div class="exception-illustration hidden-xs-down">$symfonyGhostImageContents</div> |
|
283 |
- </div> |
|
284 |
- </div> |
|
285 |
- </div> |
|
286 |
- |
|
287 |
- <div class="container"> |
|
288 |
- $content |
|
289 |
- </div> |
|
290 |
-EOF; |
|
291 |
- } |
|
292 |
- |
|
293 |
- /** |
|
294 |
- * Gets the stylesheet associated with the given exception. |
|
295 |
- * |
|
296 |
- * @return string The stylesheet as a string |
|
297 |
- */ |
|
298 |
- public function getStylesheet(FlattenException $exception) |
|
299 |
- { |
|
300 |
- if (!$this->debug) { |
|
301 |
- return <<<'EOF' |
|
302 |
- body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; } |
|
303 |
- .container { margin: 30px; max-width: 600px; } |
|
304 |
- h1 { color: #dc3545; font-size: 24px; } |
|
305 |
-EOF; |
|
306 |
- } |
|
307 |
- |
|
308 |
- return <<<'EOF' |
|
309 |
- body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; } |
|
310 |
- |
|
311 |
- a { cursor: pointer; text-decoration: none; } |
|
312 |
- a:hover { text-decoration: underline; } |
|
313 |
- abbr[title] { border-bottom: none; cursor: help; text-decoration: none; } |
|
314 |
- |
|
315 |
- code, pre { font: 13px/1.5 Consolas, Monaco, Menlo, "Ubuntu Mono", "Liberation Mono", monospace; } |
|
316 |
- |
|
317 |
- table, tr, th, td { background: #FFF; border-collapse: collapse; vertical-align: top; } |
|
318 |
- table { background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; } |
|
319 |
- table th, table td { border: solid #E0E0E0; border-width: 1px 0; padding: 8px 10px; } |
|
320 |
- table th { background-color: #E0E0E0; font-weight: bold; text-align: left; } |
|
321 |
- |
|
322 |
- .hidden-xs-down { display: none; } |
|
323 |
- .block { display: block; } |
|
324 |
- .break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; } |
|
325 |
- .text-muted { color: #999; } |
|
326 |
- |
|
327 |
- .container { max-width: 1024px; margin: 0 auto; padding: 0 15px; } |
|
328 |
- .container::after { content: ""; display: table; clear: both; } |
|
329 |
- |
|
330 |
- .exception-summary { background: #B0413E; border-bottom: 2px solid rgba(0, 0, 0, 0.1); border-top: 1px solid rgba(0, 0, 0, .3); flex: 0 0 auto; margin-bottom: 30px; } |
|
331 |
- |
|
332 |
- .exception-message-wrapper { display: flex; align-items: center; min-height: 70px; } |
|
333 |
- .exception-message { flex-grow: 1; padding: 30px 0; } |
|
334 |
- .exception-message, .exception-message a { color: #FFF; font-size: 21px; font-weight: 400; margin: 0; } |
|
335 |
- .exception-message.long { font-size: 18px; } |
|
336 |
- .exception-message a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); font-size: inherit; text-decoration: none; } |
|
337 |
- .exception-message a:hover { border-bottom-color: #ffffff; } |
|
338 |
- |
|
339 |
- .exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; } |
|
340 |
- |
|
341 |
- .trace + .trace { margin-top: 30px; } |
|
342 |
- .trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; } |
|
343 |
- |
|
344 |
- .trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; } |
|
345 |
- |
|
346 |
- .trace-file-path, .trace-file-path a { color: #222; margin-top: 3px; font-size: 13px; } |
|
347 |
- .trace-class { color: #B0413E; } |
|
348 |
- .trace-type { padding: 0 2px; } |
|
349 |
- .trace-method { color: #B0413E; font-weight: bold; } |
|
350 |
- .trace-arguments { color: #777; font-weight: normal; padding-left: 2px; } |
|
351 |
- |
|
352 |
- @media (min-width: 575px) { |
|
353 |
- .hidden-xs-down { display: initial; } |
|
354 |
- } |
|
355 |
-EOF; |
|
356 |
- } |
|
357 |
- |
|
358 |
- private function decorate($content, $css) |
|
359 |
- { |
|
360 |
- return <<<EOF |
|
361 |
-<!DOCTYPE html> |
|
362 |
-<html> |
|
363 |
- <head> |
|
364 |
- <meta charset="{$this->charset}" /> |
|
365 |
- <meta name="robots" content="noindex,nofollow" /> |
|
366 |
- <style>$css</style> |
|
367 |
- </head> |
|
368 |
- <body> |
|
369 |
- $content |
|
370 |
- </body> |
|
371 |
-</html> |
|
372 |
-EOF; |
|
373 |
- } |
|
374 |
- |
|
375 |
- private function formatClass($class) |
|
376 |
- { |
|
377 |
- $parts = explode('\\', $class); |
|
378 |
- |
|
379 |
- return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts)); |
|
380 |
- } |
|
381 |
- |
|
382 |
- private function formatPath($path, $line) |
|
383 |
- { |
|
384 |
- $file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path); |
|
385 |
- $fmt = $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); |
|
386 |
- |
|
387 |
- if (!$fmt) { |
|
388 |
- return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : ''); |
|
389 |
- } |
|
390 |
- |
|
391 |
- if (\is_string($fmt)) { |
|
392 |
- $i = strpos($f = $fmt, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f); |
|
393 |
- $fmt = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, PREG_SPLIT_DELIM_CAPTURE); |
|
394 |
- |
|
395 |
- for ($i = 1; isset($fmt[$i]); ++$i) { |
|
396 |
- if (0 === strpos($path, $k = $fmt[$i++])) { |
|
397 |
- $path = substr_replace($path, $fmt[$i], 0, \strlen($k)); |
|
398 |
- break; |
|
399 |
- } |
|
400 |
- } |
|
401 |
- |
|
402 |
- $link = strtr($fmt[0], ['%f' => $path, '%l' => $line]); |
|
403 |
- } else { |
|
404 |
- try { |
|
405 |
- $link = $fmt->format($path, $line); |
|
406 |
- } catch (\Exception $e) { |
|
407 |
- return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : ''); |
|
408 |
- } |
|
409 |
- } |
|
410 |
- |
|
411 |
- return sprintf('<span class="block trace-file-path">in <a href="%s" title="Go to source"><strong>%s</string>%s</a></span>', $this->escapeHtml($link), $file, 0 < $line ? ' line '.$line : ''); |
|
412 |
- } |
|
413 |
- |
|
414 |
- /** |
|
415 |
- * Formats an array as a string. |
|
416 |
- * |
|
417 |
- * @param array $args The argument array |
|
418 |
- * |
|
419 |
- * @return string |
|
420 |
- */ |
|
421 |
- private function formatArgs(array $args) |
|
422 |
- { |
|
423 |
- $result = []; |
|
424 |
- foreach ($args as $key => $item) { |
|
425 |
- if ('object' === $item[0]) { |
|
426 |
- $formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1])); |
|
427 |
- } elseif ('array' === $item[0]) { |
|
428 |
- $formattedValue = sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]); |
|
429 |
- } elseif ('null' === $item[0]) { |
|
430 |
- $formattedValue = '<em>null</em>'; |
|
431 |
- } elseif ('boolean' === $item[0]) { |
|
432 |
- $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>'; |
|
433 |
- } elseif ('resource' === $item[0]) { |
|
434 |
- $formattedValue = '<em>resource</em>'; |
|
435 |
- } else { |
|
436 |
- $formattedValue = str_replace("\n", '', $this->escapeHtml(var_export($item[1], true))); |
|
437 |
- } |
|
438 |
- |
|
439 |
- $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue); |
|
440 |
- } |
|
441 |
- |
|
442 |
- return implode(', ', $result); |
|
443 |
- } |
|
444 |
- |
|
445 |
- /** |
|
446 |
- * HTML-encodes a string. |
|
447 |
- */ |
|
448 |
- private function escapeHtml($str) |
|
449 |
- { |
|
450 |
- return htmlspecialchars($str, ENT_COMPAT | ENT_SUBSTITUTE, $this->charset); |
|
451 |
- } |
|
452 |
- |
|
453 |
- private function getSymfonyGhostAsSvg() |
|
454 |
- { |
|
455 |
- return '<svg viewBox="0 0 136 81" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><path d="M92.4 20.4a23.2 23.2 0 0 1 9 1.9 23.7 23.7 0 0 1 5.2 3 24.3 24.3 0 0 1 3.4 3.4 24.8 24.8 0 0 1 5 9.4c.5 1.7.8 3.4 1 5.2v14.5h.4l.5.2a7.4 7.4 0 0 0 2.5.2l.2-.2.6-.8.8-1.3-.2-.1a5.5 5.5 0 0 1-.8-.3 5.6 5.6 0 0 1-2.3-1.8 5.7 5.7 0 0 1-.9-1.6 6.5 6.5 0 0 1-.2-2.8 7.3 7.3 0 0 1 .5-2l.3-.3.8-.9.3-.3c.2-.2.5-.3.8-.3H120.7c.2 0 .3-.1.4 0h.4l.2.1.3.2.2-.4.3-.4.1-.1 1.2-1 .3-.2.4-.1.4-.1h.3l1.5.1.4.1.8.5.1.2 1 1.1v.2H129.4l.4-.2 1.4-.5h1.1c.3 0 .7.2 1 .4.2 0 .3.2.5.3l.2.2.5.3.4.6.1.3.4 1.4.1.4v.6a7.8 7.8 0 0 1-.1.6 9.9 9.9 0 0 1-.8 2.4 7.8 7.8 0 0 1-3 3.3 6.4 6.4 0 0 1-1 .5 6.1 6.1 0 0 1-.6.2l-.7.1h-.1a23.4 23.4 0 0 1-.2 1.7 14.3 14.3 0 0 1-.6 2.1l-.8 2a9.2 9.2 0 0 1-.4.6l-.7 1a9.1 9.1 0 0 1-2.3 2.2c-.9.5-2 .6-3 .7l-1.4.1h-.5l-.4.1a15.8 15.8 0 0 1-2.8-.1v4.2a9.7 9.7 0 0 1-.7 3.5 9.6 9.6 0 0 1-1.7 2.8 9.3 9.3 0 0 1-3 2.3 9 9 0 0 1-5.4.7 9 9 0 0 1-3-1 9.4 9.4 0 0 1-2.7-2.5 10 10 0 0 1-1 1.2 9.3 9.3 0 0 1-2 1.3 9 9 0 0 1-2.4 1 9 9 0 0 1-6.5-1.1A9.4 9.4 0 0 1 85 77V77a10.9 10.9 0 0 1-.6.6 9.3 9.3 0 0 1-2.7 2 9 9 0 0 1-6 .8 9 9 0 0 1-2.4-1 9.3 9.3 0 0 1-2.3-1.7 9.6 9.6 0 0 1-1.8-2.8 9.7 9.7 0 0 1-.8-3.7v-4a18.5 18.5 0 0 1-2.9.2l-1.2-.1c-1.9-.3-3.7-1-5.1-2.1A8.2 8.2 0 0 1 58 64a10.2 10.2 0 0 1-.9-1.2 15.3 15.3 0 0 1-.7-1.3 20.8 20.8 0 0 1-1.9-6.2v-.2a6.5 6.5 0 0 1-1-.3 6.1 6.1 0 0 1-.6-.3 6.6 6.6 0 0 1-.9-.5 8.2 8.2 0 0 1-2.7-3.8 10 10 0 0 1-.3-1 10.3 10.3 0 0 1-.3-1.9V47v-.4l.1-.4.6-1.4.1-.2a2 2 0 0 1 .8-.8l.3-.2.3-.2a3.2 3.2 0 0 1 1.8-.5h.4l.3.2 1.4.6.2.2.4.3.3.4.7-.7.2-.2.4-.2.6-.2h2.1l.4.2.4.2.3.2.8 1 .2-.1h.1v-.1H63l1.1.1h.3l.8.5.3.4.7 1 .2.3.1.5a11 11 0 0 1 .2 1.5c0 .8 0 1.6-.3 2.3a6 6 0 0 1-.5 1.2 5.5 5.5 0 0 1-3.3 2.5 12.3 12.3 0 0 0 1.4 3h.1l.2.1 1 .2h1.5l.5-.2H67.8l.5-.2h.1V44v-.4a26.7 26.7 0 0 1 .3-2.3 24.7 24.7 0 0 1 5.7-12.5 24.2 24.2 0 0 1 3.5-3.3 23.7 23.7 0 0 1 4.9-3 23.2 23.2 0 0 1 5.6-1.7 23.7 23.7 0 0 1 4-.3zm-.3 2a21.2 21.2 0 0 0-8 1.7 21.6 21.6 0 0 0-4.8 2.7 22.2 22.2 0 0 0-3.2 3 22.7 22.7 0 0 0-5 9.2 23.4 23.4 0 0 0-.7 4.9v15.7l-.5.1a34.3 34.3 0 0 1-1.5.3h-.2l-.4.1h-.4l-.9.2a10 10 0 0 1-1.9 0c-.5 0-1-.2-1.5-.4a1.8 1.8 0 0 1-.3-.2 2 2 0 0 1-.3-.3 5.2 5.2 0 0 1-.1-.2 9 9 0 0 1-.6-.9 13.8 13.8 0 0 1-1-2 14.3 14.3 0 0 1-.6-2 14 14 0 0 1-.1-.8v-.2h.3a12.8 12.8 0 0 0 1.4-.2 4.4 4.4 0 0 0 .3 0 3.6 3.6 0 0 0 1.1-.7 3.4 3.4 0 0 0 1.2-1.7l.2-1.2a5.1 5.1 0 0 0 0-.8 7.2 7.2 0 0 0-.1-.8l-.7-1-1.2-.2-1 .7-.1 1.3a5 5 0 0 1 .1.4v.6a1 1 0 0 1 0 .3c-.1.3-.4.4-.7.5l-1.2.4v-.7A9.9 9.9 0 0 1 60 49l.3-.6v-.2l.1-.1v-1.6l-1-1.2h-1.5l-1 1.1v.4a5.3 5.3 0 0 0-.2.6 5.5 5.5 0 0 0 0 .5c0 .7 0 1.4.3 2 0 .4.2.8.4 1.2L57 51a9.5 9.5 0 0 1-1.1-.5h-.2a2 2 0 0 1-.4-.3c-.4-.4-.5-1-.6-1.6a5.6 5.6 0 0 1 0-.5v-.5-.5l-.6-1.5-1.4-.6-.9.3s-.2 0-.3.2a2 2 0 0 1-.1 0l-.6 1.4v.7a8.5 8.5 0 0 0 .5 2c.4 1.1 1 2.1 2 2.8a4.7 4.7 0 0 0 2.1.9h1a22.8 22.8 0 0 0 .1 1 18.1 18.1 0 0 0 .8 3.8 18.2 18.2 0 0 0 1.6 3.7l1 1.3c1 1 2.3 1.6 3.7 2a11.7 11.7 0 0 0 4.8 0h.4l.5-.2.5-.1.6-.2v6.6a8 8 0 0 0 .1 1.3 7.5 7.5 0 0 0 2.4 4.3 7.2 7.2 0 0 0 2.3 1.3 7 7 0 0 0 7-1.1 7.5 7.5 0 0 0 2-2.6A7.7 7.7 0 0 0 85 72V71a8.2 8.2 0 0 0 .2 1.3c0 .7.3 1.4.6 2a7.5 7.5 0 0 0 1.7 2.3 7.3 7.3 0 0 0 2.2 1.4 7.1 7.1 0 0 0 4.6.2 7.2 7.2 0 0 0 2.4-1.2 7.5 7.5 0 0 0 2.1-2.7 7.8 7.8 0 0 0 .7-2.4V71a9.3 9.3 0 0 0 .1.6 7.6 7.6 0 0 0 .6 2.5 7.5 7.5 0 0 0 2.4 3 7.1 7.1 0 0 0 7 .8 7.3 7.3 0 0 0 2.3-1.5 7.5 7.5 0 0 0 1.6-2.3 7.6 7.6 0 0 0 .5-2l.1-1.1v-6.7l.4.1a12.2 12.2 0 0 0 2 .5 11.1 11.1 0 0 0 2.5 0h.8l1.2-.1a9.5 9.5 0 0 0 1.4-.2l.9-.3a3.5 3.5 0 0 0 .6-.4l1.2-1.4a12.2 12.2 0 0 0 .8-1.2c0-.3.2-.5.3-.7a15.9 15.9 0 0 0 .7-2l.3-1.6v-1.3l.2-.9V54.6a15.5 15.5 0 0 0 1.8 0 4.5 4.5 0 0 0 1.4-.5 5.7 5.7 0 0 0 2.5-3.2 7.6 7.6 0 0 0 .4-1.5v-.3l-.4-1.4a5.2 5.2 0 0 1-.2-.1l-.4-.4a3.8 3.8 0 0 0-.2 0 1.4 1.4 0 0 0-.5-.2l-1.4.4-.7 1.3v.7a5.7 5.7 0 0 1-.1.8l-.7 1.4a1.9 1.9 0 0 1-.5.3h-.3a9.6 9.6 0 0 1-.8.3 8.8 8.8 0 0 1-.6 0l.2-.4.2-.5.2-.3v-.4l.1-.2V50l.1-1 .1-.6v-.6a4.8 4.8 0 0 0 0-.8v-.2l-1-1.1-1.5-.2-1.1 1-.2 1.4v.1l.2.4.2.3v.4l.1 1.1v.3l.1.5v.8a9.6 9.6 0 0 1-.8-.3l-.2-.1h-.3l-.8-.1h-.2a1.6 1.6 0 0 1-.2-.2.9.9 0 0 1-.2-.2 1 1 0 0 1-.1-.5l.2-.9v-1.2l-.9-.8h-1.2l-.8.9v.3a4.8 4.8 0 0 0-.3 2l.3.9a3.5 3.5 0 0 0 1.2 1.6l1 .5.8.2 1.4.1h.4l.2.1a12.1 12.1 0 0 1-1 2.6 13.2 13.2 0 0 1-.8 1.5 9.5 9.5 0 0 1-1 1.2l-.2.3a1.7 1.7 0 0 1-.4.3 2.4 2.4 0 0 1-.7.2h-2.5a7.8 7.8 0 0 1-.6-.2l-.7-.2h-.2a14.8 14.8 0 0 1-.6-.2 23.4 23.4 0 0 1-.4-.1l-.4-.1-.3-.1V43.9a34.6 34.6 0 0 0 0-.6 23.6 23.6 0 0 0-.4-3 22.7 22.7 0 0 0-1.5-4.7 22.6 22.6 0 0 0-4.6-6.7 21.9 21.9 0 0 0-6.9-4.7 21.2 21.2 0 0 0-8.1-1.8H92zm9.1 33.7l.3.1a1 1 0 0 1 .6.8v.4a8.4 8.4 0 0 1 0 .5 8.8 8.8 0 0 1-1.6 4.2l-1 1.3A10 10 0 0 1 95 66c-1.3.3-2.7.4-4 .3a10.4 10.4 0 0 1-2.7-.8 10 10 0 0 1-3.6-2.5 9.3 9.3 0 0 1-.8-1 9 9 0 0 1-.7-1.2 8.6 8.6 0 0 1-.8-3.4V57a1 1 0 0 1 .3-.6 1 1 0 0 1 1.3-.2 1 1 0 0 1 .4.8v.4a6.5 6.5 0 0 0 .5 2.2 7 7 0 0 0 2.1 2.8l1 .6c2.6 1.6 6 1.6 8.5 0a8 8 0 0 0 1.1-.6 7.6 7.6 0 0 0 1.2-1.2 7 7 0 0 0 1-1.7 6.5 6.5 0 0 0 .4-2.5 1 1 0 0 1 .7-1h.4zM30.7 43.7c-15.5 1-28.5-6-30.1-16.4C-1.2 15.7 11.6 4 29 1.3 46.6-1.7 62.3 5.5 64 17.1c1.6 10.4-8.7 21-23.7 25a31.2 31.2 0 0 0 0 .9v.3a19 19 0 0 0 .1 1l.1.4.1.9a4.7 4.7 0 0 0 .5 1l.7 1a9.2 9.2 0 0 0 1.2 1l1.5.8.6.8-.7.6-1.1.3a11.2 11.2 0 0 1-2.6.4 8.6 8.6 0 0 1-3-.5 8.5 8.5 0 0 1-1-.4 11.2 11.2 0 0 1-1.8-1.2 13.3 13.3 0 0 1-1-1 18 18 0 0 1-.7-.6l-.4-.4a23.4 23.4 0 0 1-1.3-1.8l-.1-.1-.3-.5V45l-.3-.6v-.7zM83.1 36c3.6 0 6.5 3.2 6.5 7.1 0 4-3 7.2-6.5 7.2S76.7 47 76.7 43 79.6 36 83 36zm18 0c3.6 0 6.5 3.2 6.5 7.1 0 4-2.9 7.2-6.4 7.2S94.7 47 94.7 43s3-7.1 6.5-7.1zm-18 6.1c2 0 3.5 1.6 3.5 3.6S85 49.2 83 49.2s-3.4-1.6-3.4-3.6S81.2 42 83 42zm17.9 0c1.9 0 3.4 1.6 3.4 3.6s-1.5 3.6-3.4 3.6c-2 0-3.5-1.6-3.5-3.6S99.1 42 101 42zM17 28c-.3 1.6-1.8 5-5.2 5.8-2.5.6-4.1-.8-4.5-2.6-.4-1.9.7-3.5 2.1-4.5A3.5 3.5 0 0 1 8 24.6c-.4-2 .8-3.7 3.2-4.2 1.9-.5 3.1.2 3.4 1.5.3 1.1-.5 2.2-1.8 2.5-.9.3-1.6 0-1.7-.6a1.4 1.4 0 0 1 0-.7s.3.2 1 0c.7-.1 1-.7.9-1.2-.2-.6-1-.8-1.8-.6-1 .2-2 1-1.7 2.6.3 1 .9 1.6 1.5 1.8l.7-.2c1-.2 1.5 0 1.6.5 0 .4-.2 1-1.2 1.2a3.3 3.3 0 0 1-1.5 0c-.9.7-1.6 1.9-1.3 3.2.3 1.3 1.3 2.2 3 1.8 2.5-.7 3.8-3.7 4.2-5-.3-.5-.6-1-.7-1.6-.1-.5.1-1 .9-1.2.4 0 .7.2.8.8a2.8 2.8 0 0 1 0 1l.7 1c.6-2 1.4-4 1.7-4 .6-.2 1.5.6 1.5.6-.8.7-1.7 2.4-2.3 4.2.8.6 1.6 1 2.1 1 .5-.1.8-.6 1-1.2-.3-2.2 1-4.3 2.3-4.6.7-.2 1.3.2 1.4.8.1.5 0 1.3-.9 1.7-.2-1-.6-1.3-1-1.3-.4.1-.7 1.4-.4 2.8.2 1 .7 1.5 1.3 1.4.8-.2 1.3-1.2 1.7-2.1-.3-2.1.9-4.2 2.2-4.5.7-.2 1.2.1 1.4 1 .4 1.4-1 2.8-2.2 3.4.3.7.7 1 1.3.9 1-.3 1.6-1.5 2-2.5l-.5-3v-.3s1.6-.3 1.8.6v.1c.2-.6.7-1.2 1.3-1.4.8-.1 1.5.6 1.7 1.6.5 2.2-.5 4.4-1.8 4.7H33a31.9 31.9 0 0 0 1 5.2c-.4.1-1.8.4-2-.4l-.5-5.6c-.5 1-1.3 2.2-2.5 2.4-1 .3-1.6-.3-2-1.1-.5 1-1.3 2.1-2.4 2.4-.8.2-1.5-.1-2-1-.3.8-.9 1.5-1.5 1.7-.7.1-1.5-.3-2.4-1-.3.8-.4 1.6-.4 2.2 0 0-.7 0-.8-.4-.1-.5 0-1.5.3-2.7a10.3 10.3 0 0 1-.7-.8zm38.2-17.8l.2.9c.5 1.9.4 4.4.8 6.4 0 .6-.4 3-1.4 3.3-.2 0-.3 0-.4-.4-.1-.7 0-1.6-.3-2.6-.2-1.1-.8-1.6-1.5-1.5-.8.2-1.3 1-1.6 2l-.1-.5c-.2-1-1.8-.6-1.8-.6a6.2 6.2 0 0 1 .4 1.3l.2 1c-.2.5-.6 1-1.2 1l-.2.1a7 7 0 0 0-.1-.8c-.3-1.1-1-2-1.6-1.8a.7.7 0 0 0-.4.3c-1.3.3-2.4 2-2.1 3.9-.2.9-.6 1.7-1 1.9-.5 0-.8-.5-1.1-1.8l-.1-1.2a4 4 0 0 0 0-1.7c0-.4-.4-.7-.8-.6-.7.2-.9 1.7-.5 3.8-.2 1-.6 2-1.3 2-.4.2-.8-.2-1-1l-.2-3c1.2-.5 2-1 1.8-1.7-.1-.5-.8-.7-.8-.7s0 .7-1 1.2l-.2-1.4c-.1-.6-.4-1-1.7-.6l.4 1 .2 1.5h-1v.8c0 .3.4.3 1 .2 0 1.3 0 2.7.2 3.6.3 1.4 1.2 2 2 1.7 1-.2 1.6-1.3 2-2.3.3 1.2 1 2 1.9 1.7.7-.2 1.2-1.1 1.6-2.2.4.8 1.1 1.1 2 1 1.2-.4 1.7-1.6 1.8-2.8h.2c.6-.2 1-.6 1.3-1 0 .8 0 1.5.2 2.1.1.5.3.7.6.6.5-.1 1-.9 1-.9a4 4 0 0 1-.3-1c-.3-1.3.3-3.6 1-3.7.2 0 .3.2.5.7v.8l.2 1.5v.7c.2.7.7 1.3 1.5 1 1.3-.2 2-2.6 2.1-3.9.3.2.6.2 1 .1-.6-2.2 0-6.1-.3-7.9-.1-.4-1-.5-1.7-.5h-.4zm-21.5 12c.4 0 .7.3 1 1.1.2 1.3-.3 2.6-.9 2.8-.2 0-.7 0-1-1.2v-.4c0-1.3.4-2 1-2.2zm-5.2 1c.3 0 .6.2.6.5.2.6-.3 1.3-1.2 2-.3-1.4.1-2.3.6-2.5zm18-.4c-.5.2-1-.4-1.2-1.2-.2-1 0-2.1.7-2.5v.5c.2.7.6 1.5 1.3 1.9 0 .7-.2 1.2-.7 1.3zm10-1.6c0 .5.4.7 1 .6.8-.2 1-1 .8-1.6 0-.5-.4-1-1-.8-.5.1-1 .9-.8 1.8zm-14.3-5.5c0-.4-.5-.7-1-.5-.8.2-1 1-.9 1.5.2.6.5 1 1 .8.5 0 1.1-1 1-1.8z" fill="#fff" fill-opacity=".6"/>'.$this->addElementToGhost().'</svg>'; |
|
456 |
- } |
|
457 |
- |
|
458 |
- private function addElementToGhost() |
|
459 |
- { |
|
460 |
- if (!isset(self::GHOST_ADDONS[date('m-d')])) { |
|
461 |
- return ''; |
|
462 |
- } |
|
463 |
- |
|
464 |
- return '<path d="'.self::GHOST_ADDONS[date('m-d')].'" fill="#fff" fill-opacity="0.6"></path>'; |
|
465 |
- } |
|
466 |
-} |
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,466 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+/* |
|
4 |
+ * This file is part of the Symfony package. |
|
5 |
+ * |
|
6 |
+ * (c) Fabien Potencier <fabien@symfony.com> |
|
7 |
+ * |
|
8 |
+ * For the full copyright and license information, please view the LICENSE |
|
9 |
+ * file that was distributed with this source code. |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+namespace Symfony\Component\Debug; |
|
13 |
+ |
|
14 |
+use Symfony\Component\Debug\Exception\FlattenException; |
|
15 |
+use Symfony\Component\Debug\Exception\OutOfMemoryException; |
|
16 |
+use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; |
|
17 |
+ |
|
18 |
+/** |
|
19 |
+ * ExceptionHandler converts an exception to a Response object. |
|
20 |
+ * |
|
21 |
+ * It is mostly useful in debug mode to replace the default PHP/XDebug |
|
22 |
+ * output with something prettier and more useful. |
|
23 |
+ * |
|
24 |
+ * As this class is mainly used during Kernel boot, where nothing is yet |
|
25 |
+ * available, the Response content is always HTML. |
|
26 |
+ * |
|
27 |
+ * @author Fabien Potencier <fabien@symfony.com> |
|
28 |
+ * @author Nicolas Grekas <p@tchwork.com> |
|
29 |
+ * |
|
30 |
+ * @final since Symfony 4.3 |
|
31 |
+ */ |
|
32 |
+class ExceptionHandler |
|
33 |
+{ |
|
34 |
+ private const GHOST_ADDONS = [ |
|
35 |
+ '02-14' => self::GHOST_HEART, |
|
36 |
+ '02-29' => self::GHOST_PLUS, |
|
37 |
+ '10-18' => self::GHOST_GIFT, |
|
38 |
+ ]; |
|
39 |
+ |
|
40 |
+ private const GHOST_GIFT = 'M124.005 5.36c.396-.715 1.119-1.648-.124-1.873-.346-.177-.692-.492-1.038-.141-.769.303-1.435.728-.627 1.523.36.514.685 1.634 1.092 1.758.242-.417.47-.842.697-1.266zm-1.699 1.977c-.706-1.26-1.274-2.612-2.138-3.774-1.051-1.123-3.122-.622-3.593.825-.625 1.431.724 3.14 2.251 2.96 1.159.02 2.324.072 3.48-.011zm5.867.043c1.502-.202 2.365-2.092 1.51-3.347-.757-1.34-2.937-1.387-3.698-.025-.659 1.1-1.23 2.25-1.835 3.38 1.336.077 2.686.06 4.023-.008zm2.487 1.611c.512-.45 2.494-.981.993-1.409-.372-.105-.805-.59-1.14-.457-.726.902-1.842 1.432-3.007 1.376-.228.075-1.391-.114-1.077.1.822.47 1.623.979 2.474 1.395.595-.317 1.173-.667 1.757-1.005zm-11.696.255l1.314-.765c-1.338-.066-2.87.127-3.881-.95-.285-.319-.559-.684-.954-.282-.473.326-1.929.66-.808 1.058.976.576 1.945 1.167 2.946 1.701.476-.223.926-.503 1.383-.762zm6.416 2.846c.567-.456 1.942-.89 1.987-1.38-1.282-.737-2.527-1.56-3.87-2.183-.461-.175-.835.094-1.207.328-1.1.654-2.225 1.267-3.288 1.978 1.39.86 2.798 1.695 4.219 2.504.725-.407 1.44-.83 2.16-1.247zm5.692 1.423l1.765-1.114c-.005-1.244.015-2.488-.019-3.732a77.306 77.306 0 0 0-3.51 2.084c-.126 1.282-.062 2.586-.034 3.876.607-.358 1.2-.741 1.798-1.114zm-13.804-.784c.06-1.06.19-2.269-1.09-2.583-.807-.376-1.926-1.341-2.548-1.332-.02 1.195-.01 2.39-.011 3.585 1.192.744 2.364 1.524 3.582 2.226.119-.616.041-1.269.067-1.896zm8.541 4.105l2.117-1.336c-.003-1.284.05-2.57-.008-3.853-.776.223-1.662.91-2.48 1.337l-1.834 1.075c.012 1.37-.033 2.744.044 4.113.732-.427 1.443-.887 2.161-1.336zm-2.957-.72v-2.057c-1.416-.828-2.828-1.664-4.25-2.482-.078 1.311-.033 2.627-.045 3.94 1.416.887 2.817 1.798 4.25 2.655.057-.683.036-1.372.045-2.057zm8.255 2.755l1.731-1.153c-.024-1.218.06-2.453-.062-3.658-1.2.685-2.358 1.464-3.537 2.195.028 1.261-.058 2.536.072 3.786.609-.373 1.2-.777 1.796-1.17zm-13.851-.683l-.014-1.916c-1.193-.746-2.37-1.517-3.58-2.234-.076 1.224-.033 2.453-.044 3.679 1.203.796 2.392 1.614 3.61 2.385.048-.636.024-1.276.028-1.914zm8.584 4.199l2.102-1.396c-.002-1.298.024-2.596-.01-3.893-1.427.88-2.843 1.775-4.25 2.686-.158 1.253-.055 2.545-.056 3.811.437.266 1.553-.912 2.214-1.208zm-2.988-.556c-.085-.894.365-2.154-.773-2.5-1.146-.727-2.288-1.46-3.45-2.163-.17 1.228.008 2.508-.122 3.751a79.399 79.399 0 0 0 4.278 2.885c.117-.641.044-1.32.067-1.973zm-4.872-.236l-5.087-3.396c.002-3.493-.047-6.988.015-10.48.85-.524 1.753-.954 2.627-1.434-.564-1.616.25-3.58 1.887-4.184 1.372-.563 3.025-.055 3.9 1.13l1.906-.978 1.916.987c.915-1.086 2.483-1.706 3.842-1.097 1.631.573 2.52 2.532 1.936 4.145.88.497 1.837.886 2.644 1.492.036 3.473 0 6.946-.003 10.419-3.374 2.233-6.693 4.55-10.122 6.699-.997 0-1.858-1.083-2.783-1.522a735.316 735.316 0 0 1-2.678-1.781z'; |
|
41 |
+ private const GHOST_HEART = 'M125.914 8.305c3.036-8.71 14.933 0 0 11.2-14.932-11.2-3.036-19.91 0-11.2z'; |
|
42 |
+ private const GHOST_PLUS = 'M111.368 8.97h7.324V1.645h7.512v7.323h7.324v7.513h-7.324v7.323h-7.512v-7.323h-7.324z'; |
|
43 |
+ |
|
44 |
+ private $debug; |
|
45 |
+ private $charset; |
|
46 |
+ private $handler; |
|
47 |
+ private $caughtBuffer; |
|
48 |
+ private $caughtLength; |
|
49 |
+ private $fileLinkFormat; |
|
50 |
+ |
|
51 |
+ public function __construct(bool $debug = true, string $charset = null, $fileLinkFormat = null) |
|
52 |
+ { |
|
53 |
+ $this->debug = $debug; |
|
54 |
+ $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8'; |
|
55 |
+ $this->fileLinkFormat = $fileLinkFormat; |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ /** |
|
59 |
+ * Registers the exception handler. |
|
60 |
+ * |
|
61 |
+ * @param bool $debug Enable/disable debug mode, where the stack trace is displayed |
|
62 |
+ * @param string|null $charset The charset used by exception messages |
|
63 |
+ * @param string|null $fileLinkFormat The IDE link template |
|
64 |
+ * |
|
65 |
+ * @return static |
|
66 |
+ */ |
|
67 |
+ public static function register($debug = true, $charset = null, $fileLinkFormat = null) |
|
68 |
+ { |
|
69 |
+ $handler = new static($debug, $charset, $fileLinkFormat); |
|
70 |
+ |
|
71 |
+ $prev = set_exception_handler([$handler, 'handle']); |
|
72 |
+ if (\is_array($prev) && $prev[0] instanceof ErrorHandler) { |
|
73 |
+ restore_exception_handler(); |
|
74 |
+ $prev[0]->setExceptionHandler([$handler, 'handle']); |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ return $handler; |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ /** |
|
81 |
+ * Sets a user exception handler. |
|
82 |
+ * |
|
83 |
+ * @param callable $handler An handler that will be called on Exception |
|
84 |
+ * |
|
85 |
+ * @return callable|null The previous exception handler if any |
|
86 |
+ */ |
|
87 |
+ public function setHandler(callable $handler = null) |
|
88 |
+ { |
|
89 |
+ $old = $this->handler; |
|
90 |
+ $this->handler = $handler; |
|
91 |
+ |
|
92 |
+ return $old; |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ /** |
|
96 |
+ * Sets the format for links to source files. |
|
97 |
+ * |
|
98 |
+ * @param string|FileLinkFormatter $fileLinkFormat The format for links to source files |
|
99 |
+ * |
|
100 |
+ * @return string The previous file link format |
|
101 |
+ */ |
|
102 |
+ public function setFileLinkFormat($fileLinkFormat) |
|
103 |
+ { |
|
104 |
+ $old = $this->fileLinkFormat; |
|
105 |
+ $this->fileLinkFormat = $fileLinkFormat; |
|
106 |
+ |
|
107 |
+ return $old; |
|
108 |
+ } |
|
109 |
+ |
|
110 |
+ /** |
|
111 |
+ * Sends a response for the given Exception. |
|
112 |
+ * |
|
113 |
+ * To be as fail-safe as possible, the exception is first handled |
|
114 |
+ * by our simple exception handler, then by the user exception handler. |
|
115 |
+ * The latter takes precedence and any output from the former is cancelled, |
|
116 |
+ * if and only if nothing bad happens in this handling path. |
|
117 |
+ */ |
|
118 |
+ public function handle(\Exception $exception) |
|
119 |
+ { |
|
120 |
+ if (null === $this->handler || $exception instanceof OutOfMemoryException) { |
|
121 |
+ $this->sendPhpResponse($exception); |
|
122 |
+ |
|
123 |
+ return; |
|
124 |
+ } |
|
125 |
+ |
|
126 |
+ $caughtLength = $this->caughtLength = 0; |
|
127 |
+ |
|
128 |
+ ob_start(function ($buffer) { |
|
129 |
+ $this->caughtBuffer = $buffer; |
|
130 |
+ |
|
131 |
+ return ''; |
|
132 |
+ }); |
|
133 |
+ |
|
134 |
+ $this->sendPhpResponse($exception); |
|
135 |
+ while (null === $this->caughtBuffer && ob_end_flush()) { |
|
136 |
+ // Empty loop, everything is in the condition |
|
137 |
+ } |
|
138 |
+ if (isset($this->caughtBuffer[0])) { |
|
139 |
+ ob_start(function ($buffer) { |
|
140 |
+ if ($this->caughtLength) { |
|
141 |
+ // use substr_replace() instead of substr() for mbstring overloading resistance |
|
142 |
+ $cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength); |
|
143 |
+ if (isset($cleanBuffer[0])) { |
|
144 |
+ $buffer = $cleanBuffer; |
|
145 |
+ } |
|
146 |
+ } |
|
147 |
+ |
|
148 |
+ return $buffer; |
|
149 |
+ }); |
|
150 |
+ |
|
151 |
+ echo $this->caughtBuffer; |
|
152 |
+ $caughtLength = ob_get_length(); |
|
153 |
+ } |
|
154 |
+ $this->caughtBuffer = null; |
|
155 |
+ |
|
156 |
+ try { |
|
157 |
+ ($this->handler)($exception); |
|
158 |
+ $this->caughtLength = $caughtLength; |
|
159 |
+ } catch (\Exception $e) { |
|
160 |
+ if (!$caughtLength) { |
|
161 |
+ // All handlers failed. Let PHP handle that now. |
|
162 |
+ throw $exception; |
|
163 |
+ } |
|
164 |
+ } |
|
165 |
+ } |
|
166 |
+ |
|
167 |
+ /** |
|
168 |
+ * Sends the error associated with the given Exception as a plain PHP response. |
|
169 |
+ * |
|
170 |
+ * This method uses plain PHP functions like header() and echo to output |
|
171 |
+ * the response. |
|
172 |
+ * |
|
173 |
+ * @param \Exception|FlattenException $exception An \Exception or FlattenException instance |
|
174 |
+ */ |
|
175 |
+ public function sendPhpResponse($exception) |
|
176 |
+ { |
|
177 |
+ if (!$exception instanceof FlattenException) { |
|
178 |
+ $exception = FlattenException::create($exception); |
|
179 |
+ } |
|
180 |
+ |
|
181 |
+ if (!headers_sent()) { |
|
182 |
+ header(sprintf('HTTP/1.0 %s', $exception->getStatusCode())); |
|
183 |
+ foreach ($exception->getHeaders() as $name => $value) { |
|
184 |
+ header($name.': '.$value, false); |
|
185 |
+ } |
|
186 |
+ header('Content-Type: text/html; charset='.$this->charset); |
|
187 |
+ } |
|
188 |
+ |
|
189 |
+ echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception)); |
|
190 |
+ } |
|
191 |
+ |
|
192 |
+ /** |
|
193 |
+ * Gets the full HTML content associated with the given exception. |
|
194 |
+ * |
|
195 |
+ * @param \Exception|FlattenException $exception An \Exception or FlattenException instance |
|
196 |
+ * |
|
197 |
+ * @return string The HTML content as a string |
|
198 |
+ */ |
|
199 |
+ public function getHtml($exception) |
|
200 |
+ { |
|
201 |
+ if (!$exception instanceof FlattenException) { |
|
202 |
+ $exception = FlattenException::create($exception); |
|
203 |
+ } |
|
204 |
+ |
|
205 |
+ return $this->decorate($this->getContent($exception), $this->getStylesheet($exception)); |
|
206 |
+ } |
|
207 |
+ |
|
208 |
+ /** |
|
209 |
+ * Gets the HTML content associated with the given exception. |
|
210 |
+ * |
|
211 |
+ * @return string The content as a string |
|
212 |
+ */ |
|
213 |
+ public function getContent(FlattenException $exception) |
|
214 |
+ { |
|
215 |
+ switch ($exception->getStatusCode()) { |
|
216 |
+ case 404: |
|
217 |
+ $title = 'Sorry, the page you are looking for could not be found.'; |
|
218 |
+ break; |
|
219 |
+ default: |
|
220 |
+ $title = $this->debug ? $this->escapeHtml($exception->getMessage()) : 'Whoops, looks like something went wrong.'; |
|
221 |
+ } |
|
222 |
+ |
|
223 |
+ if (!$this->debug) { |
|
224 |
+ return <<<EOF |
|
225 |
+ <div class="container"> |
|
226 |
+ <h1>$title</h1> |
|
227 |
+ </div> |
|
228 |
+EOF; |
|
229 |
+ } |
|
230 |
+ |
|
231 |
+ $content = ''; |
|
232 |
+ try { |
|
233 |
+ $count = \count($exception->getAllPrevious()); |
|
234 |
+ $total = $count + 1; |
|
235 |
+ foreach ($exception->toArray() as $position => $e) { |
|
236 |
+ $ind = $count - $position + 1; |
|
237 |
+ $class = $this->formatClass($e['class']); |
|
238 |
+ $message = nl2br($this->escapeHtml($e['message'])); |
|
239 |
+ $content .= sprintf(<<<'EOF' |
|
240 |
+ <div class="trace trace-as-html"> |
|
241 |
+ <table class="trace-details"> |
|
242 |
+ <thead class="trace-head"><tr><th> |
|
243 |
+ <h3 class="trace-class"> |
|
244 |
+ <span class="text-muted">(%d/%d)</span> |
|
245 |
+ <span class="exception_title">%s</span> |
|
246 |
+ </h3> |
|
247 |
+ <p class="break-long-words trace-message">%s</p> |
|
248 |
+ </th></tr></thead> |
|
249 |
+ <tbody> |
|
250 |
+EOF |
|
251 |
+ , $ind, $total, $class, $message); |
|
252 |
+ foreach ($e['trace'] as $trace) { |
|
253 |
+ $content .= '<tr><td>'; |
|
254 |
+ if ($trace['function']) { |
|
255 |
+ $content .= sprintf('at <span class="trace-class">%s</span><span class="trace-type">%s</span><span class="trace-method">%s</span>(<span class="trace-arguments">%s</span>)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args'])); |
|
256 |
+ } |
|
257 |
+ if (isset($trace['file']) && isset($trace['line'])) { |
|
258 |
+ $content .= $this->formatPath($trace['file'], $trace['line']); |
|
259 |
+ } |
|
260 |
+ $content .= "</td></tr>\n"; |
|
261 |
+ } |
|
262 |
+ |
|
263 |
+ $content .= "</tbody>\n</table>\n</div>\n"; |
|
264 |
+ } |
|
265 |
+ } catch (\Exception $e) { |
|
266 |
+ // something nasty happened and we cannot throw an exception anymore |
|
267 |
+ if ($this->debug) { |
|
268 |
+ $e = FlattenException::create($e); |
|
269 |
+ $title = sprintf('Exception thrown when handling an exception (%s: %s)', $e->getClass(), $this->escapeHtml($e->getMessage())); |
|
270 |
+ } else { |
|
271 |
+ $title = 'Whoops, looks like something went wrong.'; |
|
272 |
+ } |
|
273 |
+ } |
|
274 |
+ |
|
275 |
+ $symfonyGhostImageContents = $this->getSymfonyGhostAsSvg(); |
|
276 |
+ |
|
277 |
+ return <<<EOF |
|
278 |
+ <div class="exception-summary"> |
|
279 |
+ <div class="container"> |
|
280 |
+ <div class="exception-message-wrapper"> |
|
281 |
+ <h1 class="break-long-words exception-message">$title</h1> |
|
282 |
+ <div class="exception-illustration hidden-xs-down">$symfonyGhostImageContents</div> |
|
283 |
+ </div> |
|
284 |
+ </div> |
|
285 |
+ </div> |
|
286 |
+ |
|
287 |
+ <div class="container"> |
|
288 |
+ $content |
|
289 |
+ </div> |
|
290 |
+EOF; |
|
291 |
+ } |
|
292 |
+ |
|
293 |
+ /** |
|
294 |
+ * Gets the stylesheet associated with the given exception. |
|
295 |
+ * |
|
296 |
+ * @return string The stylesheet as a string |
|
297 |
+ */ |
|
298 |
+ public function getStylesheet(FlattenException $exception) |
|
299 |
+ { |
|
300 |
+ if (!$this->debug) { |
|
301 |
+ return <<<'EOF' |
|
302 |
+ body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; } |
|
303 |
+ .container { margin: 30px; max-width: 600px; } |
|
304 |
+ h1 { color: #dc3545; font-size: 24px; } |
|
305 |
+EOF; |
|
306 |
+ } |
|
307 |
+ |
|
308 |
+ return <<<'EOF' |
|
309 |
+ body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; } |
|
310 |
+ |
|
311 |
+ a { cursor: pointer; text-decoration: none; } |
|
312 |
+ a:hover { text-decoration: underline; } |
|
313 |
+ abbr[title] { border-bottom: none; cursor: help; text-decoration: none; } |
|
314 |
+ |
|
315 |
+ code, pre { font: 13px/1.5 Consolas, Monaco, Menlo, "Ubuntu Mono", "Liberation Mono", monospace; } |
|
316 |
+ |
|
317 |
+ table, tr, th, td { background: #FFF; border-collapse: collapse; vertical-align: top; } |
|
318 |
+ table { background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; } |
|
319 |
+ table th, table td { border: solid #E0E0E0; border-width: 1px 0; padding: 8px 10px; } |
|
320 |
+ table th { background-color: #E0E0E0; font-weight: bold; text-align: left; } |
|
321 |
+ |
|
322 |
+ .hidden-xs-down { display: none; } |
|
323 |
+ .block { display: block; } |
|
324 |
+ .break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; } |
|
325 |
+ .text-muted { color: #999; } |
|
326 |
+ |
|
327 |
+ .container { max-width: 1024px; margin: 0 auto; padding: 0 15px; } |
|
328 |
+ .container::after { content: ""; display: table; clear: both; } |
|
329 |
+ |
|
330 |
+ .exception-summary { background: #B0413E; border-bottom: 2px solid rgba(0, 0, 0, 0.1); border-top: 1px solid rgba(0, 0, 0, .3); flex: 0 0 auto; margin-bottom: 30px; } |
|
331 |
+ |
|
332 |
+ .exception-message-wrapper { display: flex; align-items: center; min-height: 70px; } |
|
333 |
+ .exception-message { flex-grow: 1; padding: 30px 0; } |
|
334 |
+ .exception-message, .exception-message a { color: #FFF; font-size: 21px; font-weight: 400; margin: 0; } |
|
335 |
+ .exception-message.long { font-size: 18px; } |
|
336 |
+ .exception-message a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); font-size: inherit; text-decoration: none; } |
|
337 |
+ .exception-message a:hover { border-bottom-color: #ffffff; } |
|
338 |
+ |
|
339 |
+ .exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; } |
|
340 |
+ |
|
341 |
+ .trace + .trace { margin-top: 30px; } |
|
342 |
+ .trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; } |
|
343 |
+ |
|
344 |
+ .trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; } |
|
345 |
+ |
|
346 |
+ .trace-file-path, .trace-file-path a { color: #222; margin-top: 3px; font-size: 13px; } |
|
347 |
+ .trace-class { color: #B0413E; } |
|
348 |
+ .trace-type { padding: 0 2px; } |
|
349 |
+ .trace-method { color: #B0413E; font-weight: bold; } |
|
350 |
+ .trace-arguments { color: #777; font-weight: normal; padding-left: 2px; } |
|
351 |
+ |
|
352 |
+ @media (min-width: 575px) { |
|
353 |
+ .hidden-xs-down { display: initial; } |
|
354 |
+ } |
|
355 |
+EOF; |
|
356 |
+ } |
|
357 |
+ |
|
358 |
+ private function decorate($content, $css) |
|
359 |
+ { |
|
360 |
+ return <<<EOF |
|
361 |
+<!DOCTYPE html> |
|
362 |
+<html> |
|
363 |
+ <head> |
|
364 |
+ <meta charset="{$this->charset}" /> |
|
365 |
+ <meta name="robots" content="noindex,nofollow" /> |
|
366 |
+ <style>$css</style> |
|
367 |
+ </head> |
|
368 |
+ <body> |
|
369 |
+ $content |
|
370 |
+ </body> |
|
371 |
+</html> |
|
372 |
+EOF; |
|
373 |
+ } |
|
374 |
+ |
|
375 |
+ private function formatClass($class) |
|
376 |
+ { |
|
377 |
+ $parts = explode('\\', $class); |
|
378 |
+ |
|
379 |
+ return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts)); |
|
380 |
+ } |
|
381 |
+ |
|
382 |
+ private function formatPath($path, $line) |
|
383 |
+ { |
|
384 |
+ $file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path); |
|
385 |
+ $fmt = $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); |
|
386 |
+ |
|
387 |
+ if (!$fmt) { |
|
388 |
+ return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : ''); |
|
389 |
+ } |
|
390 |
+ |
|
391 |
+ if (\is_string($fmt)) { |
|
392 |
+ $i = strpos($f = $fmt, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f); |
|
393 |
+ $fmt = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, PREG_SPLIT_DELIM_CAPTURE); |
|
394 |
+ |
|
395 |
+ for ($i = 1; isset($fmt[$i]); ++$i) { |
|
396 |
+ if (0 === strpos($path, $k = $fmt[$i++])) { |
|
397 |
+ $path = substr_replace($path, $fmt[$i], 0, \strlen($k)); |
|
398 |
+ break; |
|
399 |
+ } |
|
400 |
+ } |
|
401 |
+ |
|
402 |
+ $link = strtr($fmt[0], ['%f' => $path, '%l' => $line]); |
|
403 |
+ } else { |
|
404 |
+ try { |
|
405 |
+ $link = $fmt->format($path, $line); |
|
406 |
+ } catch (\Exception $e) { |
|
407 |
+ return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : ''); |
|
408 |
+ } |
|
409 |
+ } |
|
410 |
+ |
|
411 |
+ return sprintf('<span class="block trace-file-path">in <a href="%s" title="Go to source"><strong>%s</string>%s</a></span>', $this->escapeHtml($link), $file, 0 < $line ? ' line '.$line : ''); |
|
412 |
+ } |
|
413 |
+ |
|
414 |
+ /** |
|
415 |
+ * Formats an array as a string. |
|
416 |
+ * |
|
417 |
+ * @param array $args The argument array |
|
418 |
+ * |
|
419 |
+ * @return string |
|
420 |
+ */ |
|
421 |
+ private function formatArgs(array $args) |
|
422 |
+ { |
|
423 |
+ $result = []; |
|
424 |
+ foreach ($args as $key => $item) { |
|
425 |
+ if ('object' === $item[0]) { |
|
426 |
+ $formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1])); |
|
427 |
+ } elseif ('array' === $item[0]) { |
|
428 |
+ $formattedValue = sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]); |
|
429 |
+ } elseif ('null' === $item[0]) { |
|
430 |
+ $formattedValue = '<em>null</em>'; |
|
431 |
+ } elseif ('boolean' === $item[0]) { |
|
432 |
+ $formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>'; |
|
433 |
+ } elseif ('resource' === $item[0]) { |
|
434 |
+ $formattedValue = '<em>resource</em>'; |
|
435 |
+ } else { |
|
436 |
+ $formattedValue = str_replace("\n", '', $this->escapeHtml(var_export($item[1], true))); |
|
437 |
+ } |
|
438 |
+ |
|
439 |
+ $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue); |
|
440 |
+ } |
|
441 |
+ |
|
442 |
+ return implode(', ', $result); |
|
443 |
+ } |
|
444 |
+ |
|
445 |
+ /** |
|
446 |
+ * HTML-encodes a string. |
|
447 |
+ */ |
|
448 |
+ private function escapeHtml($str) |
|
449 |
+ { |
|
450 |
+ return htmlspecialchars($str, ENT_COMPAT | ENT_SUBSTITUTE, $this->charset); |
|
451 |
+ } |
|
452 |
+ |
|
453 |
+ private function getSymfonyGhostAsSvg() |
|
454 |
+ { |
|
455 |
+ return '<svg viewBox="0 0 136 81" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><path d="M92.4 20.4a23.2 23.2 0 0 1 9 1.9 23.7 23.7 0 0 1 5.2 3 24.3 24.3 0 0 1 3.4 3.4 24.8 24.8 0 0 1 5 9.4c.5 1.7.8 3.4 1 5.2v14.5h.4l.5.2a7.4 7.4 0 0 0 2.5.2l.2-.2.6-.8.8-1.3-.2-.1a5.5 5.5 0 0 1-.8-.3 5.6 5.6 0 0 1-2.3-1.8 5.7 5.7 0 0 1-.9-1.6 6.5 6.5 0 0 1-.2-2.8 7.3 7.3 0 0 1 .5-2l.3-.3.8-.9.3-.3c.2-.2.5-.3.8-.3H120.7c.2 0 .3-.1.4 0h.4l.2.1.3.2.2-.4.3-.4.1-.1 1.2-1 .3-.2.4-.1.4-.1h.3l1.5.1.4.1.8.5.1.2 1 1.1v.2H129.4l.4-.2 1.4-.5h1.1c.3 0 .7.2 1 .4.2 0 .3.2.5.3l.2.2.5.3.4.6.1.3.4 1.4.1.4v.6a7.8 7.8 0 0 1-.1.6 9.9 9.9 0 0 1-.8 2.4 7.8 7.8 0 0 1-3 3.3 6.4 6.4 0 0 1-1 .5 6.1 6.1 0 0 1-.6.2l-.7.1h-.1a23.4 23.4 0 0 1-.2 1.7 14.3 14.3 0 0 1-.6 2.1l-.8 2a9.2 9.2 0 0 1-.4.6l-.7 1a9.1 9.1 0 0 1-2.3 2.2c-.9.5-2 .6-3 .7l-1.4.1h-.5l-.4.1a15.8 15.8 0 0 1-2.8-.1v4.2a9.7 9.7 0 0 1-.7 3.5 9.6 9.6 0 0 1-1.7 2.8 9.3 9.3 0 0 1-3 2.3 9 9 0 0 1-5.4.7 9 9 0 0 1-3-1 9.4 9.4 0 0 1-2.7-2.5 10 10 0 0 1-1 1.2 9.3 9.3 0 0 1-2 1.3 9 9 0 0 1-2.4 1 9 9 0 0 1-6.5-1.1A9.4 9.4 0 0 1 85 77V77a10.9 10.9 0 0 1-.6.6 9.3 9.3 0 0 1-2.7 2 9 9 0 0 1-6 .8 9 9 0 0 1-2.4-1 9.3 9.3 0 0 1-2.3-1.7 9.6 9.6 0 0 1-1.8-2.8 9.7 9.7 0 0 1-.8-3.7v-4a18.5 18.5 0 0 1-2.9.2l-1.2-.1c-1.9-.3-3.7-1-5.1-2.1A8.2 8.2 0 0 1 58 64a10.2 10.2 0 0 1-.9-1.2 15.3 15.3 0 0 1-.7-1.3 20.8 20.8 0 0 1-1.9-6.2v-.2a6.5 6.5 0 0 1-1-.3 6.1 6.1 0 0 1-.6-.3 6.6 6.6 0 0 1-.9-.5 8.2 8.2 0 0 1-2.7-3.8 10 10 0 0 1-.3-1 10.3 10.3 0 0 1-.3-1.9V47v-.4l.1-.4.6-1.4.1-.2a2 2 0 0 1 .8-.8l.3-.2.3-.2a3.2 3.2 0 0 1 1.8-.5h.4l.3.2 1.4.6.2.2.4.3.3.4.7-.7.2-.2.4-.2.6-.2h2.1l.4.2.4.2.3.2.8 1 .2-.1h.1v-.1H63l1.1.1h.3l.8.5.3.4.7 1 .2.3.1.5a11 11 0 0 1 .2 1.5c0 .8 0 1.6-.3 2.3a6 6 0 0 1-.5 1.2 5.5 5.5 0 0 1-3.3 2.5 12.3 12.3 0 0 0 1.4 3h.1l.2.1 1 .2h1.5l.5-.2H67.8l.5-.2h.1V44v-.4a26.7 26.7 0 0 1 .3-2.3 24.7 24.7 0 0 1 5.7-12.5 24.2 24.2 0 0 1 3.5-3.3 23.7 23.7 0 0 1 4.9-3 23.2 23.2 0 0 1 5.6-1.7 23.7 23.7 0 0 1 4-.3zm-.3 2a21.2 21.2 0 0 0-8 1.7 21.6 21.6 0 0 0-4.8 2.7 22.2 22.2 0 0 0-3.2 3 22.7 22.7 0 0 0-5 9.2 23.4 23.4 0 0 0-.7 4.9v15.7l-.5.1a34.3 34.3 0 0 1-1.5.3h-.2l-.4.1h-.4l-.9.2a10 10 0 0 1-1.9 0c-.5 0-1-.2-1.5-.4a1.8 1.8 0 0 1-.3-.2 2 2 0 0 1-.3-.3 5.2 5.2 0 0 1-.1-.2 9 9 0 0 1-.6-.9 13.8 13.8 0 0 1-1-2 14.3 14.3 0 0 1-.6-2 14 14 0 0 1-.1-.8v-.2h.3a12.8 12.8 0 0 0 1.4-.2 4.4 4.4 0 0 0 .3 0 3.6 3.6 0 0 0 1.1-.7 3.4 3.4 0 0 0 1.2-1.7l.2-1.2a5.1 5.1 0 0 0 0-.8 7.2 7.2 0 0 0-.1-.8l-.7-1-1.2-.2-1 .7-.1 1.3a5 5 0 0 1 .1.4v.6a1 1 0 0 1 0 .3c-.1.3-.4.4-.7.5l-1.2.4v-.7A9.9 9.9 0 0 1 60 49l.3-.6v-.2l.1-.1v-1.6l-1-1.2h-1.5l-1 1.1v.4a5.3 5.3 0 0 0-.2.6 5.5 5.5 0 0 0 0 .5c0 .7 0 1.4.3 2 0 .4.2.8.4 1.2L57 51a9.5 9.5 0 0 1-1.1-.5h-.2a2 2 0 0 1-.4-.3c-.4-.4-.5-1-.6-1.6a5.6 5.6 0 0 1 0-.5v-.5-.5l-.6-1.5-1.4-.6-.9.3s-.2 0-.3.2a2 2 0 0 1-.1 0l-.6 1.4v.7a8.5 8.5 0 0 0 .5 2c.4 1.1 1 2.1 2 2.8a4.7 4.7 0 0 0 2.1.9h1a22.8 22.8 0 0 0 .1 1 18.1 18.1 0 0 0 .8 3.8 18.2 18.2 0 0 0 1.6 3.7l1 1.3c1 1 2.3 1.6 3.7 2a11.7 11.7 0 0 0 4.8 0h.4l.5-.2.5-.1.6-.2v6.6a8 8 0 0 0 .1 1.3 7.5 7.5 0 0 0 2.4 4.3 7.2 7.2 0 0 0 2.3 1.3 7 7 0 0 0 7-1.1 7.5 7.5 0 0 0 2-2.6A7.7 7.7 0 0 0 85 72V71a8.2 8.2 0 0 0 .2 1.3c0 .7.3 1.4.6 2a7.5 7.5 0 0 0 1.7 2.3 7.3 7.3 0 0 0 2.2 1.4 7.1 7.1 0 0 0 4.6.2 7.2 7.2 0 0 0 2.4-1.2 7.5 7.5 0 0 0 2.1-2.7 7.8 7.8 0 0 0 .7-2.4V71a9.3 9.3 0 0 0 .1.6 7.6 7.6 0 0 0 .6 2.5 7.5 7.5 0 0 0 2.4 3 7.1 7.1 0 0 0 7 .8 7.3 7.3 0 0 0 2.3-1.5 7.5 7.5 0 0 0 1.6-2.3 7.6 7.6 0 0 0 .5-2l.1-1.1v-6.7l.4.1a12.2 12.2 0 0 0 2 .5 11.1 11.1 0 0 0 2.5 0h.8l1.2-.1a9.5 9.5 0 0 0 1.4-.2l.9-.3a3.5 3.5 0 0 0 .6-.4l1.2-1.4a12.2 12.2 0 0 0 .8-1.2c0-.3.2-.5.3-.7a15.9 15.9 0 0 0 .7-2l.3-1.6v-1.3l.2-.9V54.6a15.5 15.5 0 0 0 1.8 0 4.5 4.5 0 0 0 1.4-.5 5.7 5.7 0 0 0 2.5-3.2 7.6 7.6 0 0 0 .4-1.5v-.3l-.4-1.4a5.2 5.2 0 0 1-.2-.1l-.4-.4a3.8 3.8 0 0 0-.2 0 1.4 1.4 0 0 0-.5-.2l-1.4.4-.7 1.3v.7a5.7 5.7 0 0 1-.1.8l-.7 1.4a1.9 1.9 0 0 1-.5.3h-.3a9.6 9.6 0 0 1-.8.3 8.8 8.8 0 0 1-.6 0l.2-.4.2-.5.2-.3v-.4l.1-.2V50l.1-1 .1-.6v-.6a4.8 4.8 0 0 0 0-.8v-.2l-1-1.1-1.5-.2-1.1 1-.2 1.4v.1l.2.4.2.3v.4l.1 1.1v.3l.1.5v.8a9.6 9.6 0 0 1-.8-.3l-.2-.1h-.3l-.8-.1h-.2a1.6 1.6 0 0 1-.2-.2.9.9 0 0 1-.2-.2 1 1 0 0 1-.1-.5l.2-.9v-1.2l-.9-.8h-1.2l-.8.9v.3a4.8 4.8 0 0 0-.3 2l.3.9a3.5 3.5 0 0 0 1.2 1.6l1 .5.8.2 1.4.1h.4l.2.1a12.1 12.1 0 0 1-1 2.6 13.2 13.2 0 0 1-.8 1.5 9.5 9.5 0 0 1-1 1.2l-.2.3a1.7 1.7 0 0 1-.4.3 2.4 2.4 0 0 1-.7.2h-2.5a7.8 7.8 0 0 1-.6-.2l-.7-.2h-.2a14.8 14.8 0 0 1-.6-.2 23.4 23.4 0 0 1-.4-.1l-.4-.1-.3-.1V43.9a34.6 34.6 0 0 0 0-.6 23.6 23.6 0 0 0-.4-3 22.7 22.7 0 0 0-1.5-4.7 22.6 22.6 0 0 0-4.6-6.7 21.9 21.9 0 0 0-6.9-4.7 21.2 21.2 0 0 0-8.1-1.8H92zm9.1 33.7l.3.1a1 1 0 0 1 .6.8v.4a8.4 8.4 0 0 1 0 .5 8.8 8.8 0 0 1-1.6 4.2l-1 1.3A10 10 0 0 1 95 66c-1.3.3-2.7.4-4 .3a10.4 10.4 0 0 1-2.7-.8 10 10 0 0 1-3.6-2.5 9.3 9.3 0 0 1-.8-1 9 9 0 0 1-.7-1.2 8.6 8.6 0 0 1-.8-3.4V57a1 1 0 0 1 .3-.6 1 1 0 0 1 1.3-.2 1 1 0 0 1 .4.8v.4a6.5 6.5 0 0 0 .5 2.2 7 7 0 0 0 2.1 2.8l1 .6c2.6 1.6 6 1.6 8.5 0a8 8 0 0 0 1.1-.6 7.6 7.6 0 0 0 1.2-1.2 7 7 0 0 0 1-1.7 6.5 6.5 0 0 0 .4-2.5 1 1 0 0 1 .7-1h.4zM30.7 43.7c-15.5 1-28.5-6-30.1-16.4C-1.2 15.7 11.6 4 29 1.3 46.6-1.7 62.3 5.5 64 17.1c1.6 10.4-8.7 21-23.7 25a31.2 31.2 0 0 0 0 .9v.3a19 19 0 0 0 .1 1l.1.4.1.9a4.7 4.7 0 0 0 .5 1l.7 1a9.2 9.2 0 0 0 1.2 1l1.5.8.6.8-.7.6-1.1.3a11.2 11.2 0 0 1-2.6.4 8.6 8.6 0 0 1-3-.5 8.5 8.5 0 0 1-1-.4 11.2 11.2 0 0 1-1.8-1.2 13.3 13.3 0 0 1-1-1 18 18 0 0 1-.7-.6l-.4-.4a23.4 23.4 0 0 1-1.3-1.8l-.1-.1-.3-.5V45l-.3-.6v-.7zM83.1 36c3.6 0 6.5 3.2 6.5 7.1 0 4-3 7.2-6.5 7.2S76.7 47 76.7 43 79.6 36 83 36zm18 0c3.6 0 6.5 3.2 6.5 7.1 0 4-2.9 7.2-6.4 7.2S94.7 47 94.7 43s3-7.1 6.5-7.1zm-18 6.1c2 0 3.5 1.6 3.5 3.6S85 49.2 83 49.2s-3.4-1.6-3.4-3.6S81.2 42 83 42zm17.9 0c1.9 0 3.4 1.6 3.4 3.6s-1.5 3.6-3.4 3.6c-2 0-3.5-1.6-3.5-3.6S99.1 42 101 42zM17 28c-.3 1.6-1.8 5-5.2 5.8-2.5.6-4.1-.8-4.5-2.6-.4-1.9.7-3.5 2.1-4.5A3.5 3.5 0 0 1 8 24.6c-.4-2 .8-3.7 3.2-4.2 1.9-.5 3.1.2 3.4 1.5.3 1.1-.5 2.2-1.8 2.5-.9.3-1.6 0-1.7-.6a1.4 1.4 0 0 1 0-.7s.3.2 1 0c.7-.1 1-.7.9-1.2-.2-.6-1-.8-1.8-.6-1 .2-2 1-1.7 2.6.3 1 .9 1.6 1.5 1.8l.7-.2c1-.2 1.5 0 1.6.5 0 .4-.2 1-1.2 1.2a3.3 3.3 0 0 1-1.5 0c-.9.7-1.6 1.9-1.3 3.2.3 1.3 1.3 2.2 3 1.8 2.5-.7 3.8-3.7 4.2-5-.3-.5-.6-1-.7-1.6-.1-.5.1-1 .9-1.2.4 0 .7.2.8.8a2.8 2.8 0 0 1 0 1l.7 1c.6-2 1.4-4 1.7-4 .6-.2 1.5.6 1.5.6-.8.7-1.7 2.4-2.3 4.2.8.6 1.6 1 2.1 1 .5-.1.8-.6 1-1.2-.3-2.2 1-4.3 2.3-4.6.7-.2 1.3.2 1.4.8.1.5 0 1.3-.9 1.7-.2-1-.6-1.3-1-1.3-.4.1-.7 1.4-.4 2.8.2 1 .7 1.5 1.3 1.4.8-.2 1.3-1.2 1.7-2.1-.3-2.1.9-4.2 2.2-4.5.7-.2 1.2.1 1.4 1 .4 1.4-1 2.8-2.2 3.4.3.7.7 1 1.3.9 1-.3 1.6-1.5 2-2.5l-.5-3v-.3s1.6-.3 1.8.6v.1c.2-.6.7-1.2 1.3-1.4.8-.1 1.5.6 1.7 1.6.5 2.2-.5 4.4-1.8 4.7H33a31.9 31.9 0 0 0 1 5.2c-.4.1-1.8.4-2-.4l-.5-5.6c-.5 1-1.3 2.2-2.5 2.4-1 .3-1.6-.3-2-1.1-.5 1-1.3 2.1-2.4 2.4-.8.2-1.5-.1-2-1-.3.8-.9 1.5-1.5 1.7-.7.1-1.5-.3-2.4-1-.3.8-.4 1.6-.4 2.2 0 0-.7 0-.8-.4-.1-.5 0-1.5.3-2.7a10.3 10.3 0 0 1-.7-.8zm38.2-17.8l.2.9c.5 1.9.4 4.4.8 6.4 0 .6-.4 3-1.4 3.3-.2 0-.3 0-.4-.4-.1-.7 0-1.6-.3-2.6-.2-1.1-.8-1.6-1.5-1.5-.8.2-1.3 1-1.6 2l-.1-.5c-.2-1-1.8-.6-1.8-.6a6.2 6.2 0 0 1 .4 1.3l.2 1c-.2.5-.6 1-1.2 1l-.2.1a7 7 0 0 0-.1-.8c-.3-1.1-1-2-1.6-1.8a.7.7 0 0 0-.4.3c-1.3.3-2.4 2-2.1 3.9-.2.9-.6 1.7-1 1.9-.5 0-.8-.5-1.1-1.8l-.1-1.2a4 4 0 0 0 0-1.7c0-.4-.4-.7-.8-.6-.7.2-.9 1.7-.5 3.8-.2 1-.6 2-1.3 2-.4.2-.8-.2-1-1l-.2-3c1.2-.5 2-1 1.8-1.7-.1-.5-.8-.7-.8-.7s0 .7-1 1.2l-.2-1.4c-.1-.6-.4-1-1.7-.6l.4 1 .2 1.5h-1v.8c0 .3.4.3 1 .2 0 1.3 0 2.7.2 3.6.3 1.4 1.2 2 2 1.7 1-.2 1.6-1.3 2-2.3.3 1.2 1 2 1.9 1.7.7-.2 1.2-1.1 1.6-2.2.4.8 1.1 1.1 2 1 1.2-.4 1.7-1.6 1.8-2.8h.2c.6-.2 1-.6 1.3-1 0 .8 0 1.5.2 2.1.1.5.3.7.6.6.5-.1 1-.9 1-.9a4 4 0 0 1-.3-1c-.3-1.3.3-3.6 1-3.7.2 0 .3.2.5.7v.8l.2 1.5v.7c.2.7.7 1.3 1.5 1 1.3-.2 2-2.6 2.1-3.9.3.2.6.2 1 .1-.6-2.2 0-6.1-.3-7.9-.1-.4-1-.5-1.7-.5h-.4zm-21.5 12c.4 0 .7.3 1 1.1.2 1.3-.3 2.6-.9 2.8-.2 0-.7 0-1-1.2v-.4c0-1.3.4-2 1-2.2zm-5.2 1c.3 0 .6.2.6.5.2.6-.3 1.3-1.2 2-.3-1.4.1-2.3.6-2.5zm18-.4c-.5.2-1-.4-1.2-1.2-.2-1 0-2.1.7-2.5v.5c.2.7.6 1.5 1.3 1.9 0 .7-.2 1.2-.7 1.3zm10-1.6c0 .5.4.7 1 .6.8-.2 1-1 .8-1.6 0-.5-.4-1-1-.8-.5.1-1 .9-.8 1.8zm-14.3-5.5c0-.4-.5-.7-1-.5-.8.2-1 1-.9 1.5.2.6.5 1 1 .8.5 0 1.1-1 1-1.8z" fill="#fff" fill-opacity=".6"/>'.$this->addElementToGhost().'</svg>'; |
|
456 |
+ } |
|
457 |
+ |
|
458 |
+ private function addElementToGhost() |
|
459 |
+ { |
|
460 |
+ if (!isset(self::GHOST_ADDONS[date('m-d')])) { |
|
461 |
+ return ''; |
|
462 |
+ } |
|
463 |
+ |
|
464 |
+ return '<path d="'.self::GHOST_ADDONS[date('m-d')].'" fill="#fff" fill-opacity="0.6"></path>'; |
|
465 |
+ } |
|
466 |
+} |