1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Lenevor Framework |
5
|
|
|
* |
6
|
|
|
* LICENSE |
7
|
|
|
* |
8
|
|
|
* This source file is subject to the new BSD license that is bundled |
9
|
|
|
* with this package in the file license.md. |
10
|
|
|
* It is also available through the world-wide-web at this URL: |
11
|
|
|
* https://lenevor.com/license |
12
|
|
|
* If you did not receive a copy of the license and are unable to |
13
|
|
|
* obtain it through the world-wide-web, please send an email |
14
|
|
|
* to [email protected] so we can send you a copy immediately. |
15
|
|
|
* |
16
|
|
|
* @package Lenevor |
17
|
|
|
* @subpackage Base |
18
|
|
|
* @link https://lenevor.com |
19
|
|
|
* @copyright Copyright (c) 2019 - 2021 Alexander Campo <[email protected]> |
20
|
|
|
* @license https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md |
21
|
|
|
*/ |
22
|
|
|
|
23
|
|
|
namespace Syscodes\Debug; |
24
|
|
|
|
25
|
|
|
use Exception; |
26
|
|
|
use Throwable; |
27
|
|
|
use Syscodes\Debug\FatalExceptions\FlattenException; |
28
|
|
|
use Syscodes\Debug\FatalExceptions\OutOfMemoryException; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* A generic ErrorHandler for the PHP engine. |
32
|
|
|
* |
33
|
|
|
* @author Alexander Campo <[email protected]> |
34
|
|
|
*/ |
35
|
|
|
class ExceptionHandler |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* Gets caught buffer of memory. |
39
|
|
|
* |
40
|
|
|
* @var mixed $caughtBuffer |
41
|
|
|
*/ |
42
|
|
|
protected $caughtBuffer; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Gets caught lenght of buffer. |
46
|
|
|
* |
47
|
|
|
* @var int $caughtLength |
48
|
|
|
*/ |
49
|
|
|
protected $caughtLength; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Gets the charset. By default UTF-8. |
53
|
|
|
* |
54
|
|
|
* @var string $charset |
55
|
|
|
*/ |
56
|
|
|
protected $charset; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Gets activation of debugging. |
60
|
|
|
* |
61
|
|
|
* @var bool $debug |
62
|
|
|
*/ |
63
|
|
|
protected $debug; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Gets the file link format. |
67
|
|
|
* |
68
|
|
|
* @var string $fileLinkFormat |
69
|
|
|
*/ |
70
|
|
|
protected $fileLinkFormat; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Gets an error handler. |
74
|
|
|
* |
75
|
|
|
* @var string $handler |
76
|
|
|
*/ |
77
|
|
|
protected $handler; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Register the exception handler. |
81
|
|
|
* |
82
|
|
|
* @param bool $debug |
83
|
|
|
* @param string|null $charset |
84
|
|
|
* @param string|null $fileLinkformat |
85
|
|
|
* |
86
|
|
|
* @return static |
87
|
|
|
*/ |
88
|
|
|
public static function register($debug = true, $charset = null, $fileLinkFormat = null) |
89
|
|
|
{ |
90
|
|
|
$handler = new static($debug, $charset, $fileLinkFormat); |
91
|
|
|
|
92
|
|
|
set_exception_handler([$handler, 'handle']); |
93
|
|
|
|
94
|
|
|
return $handler; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Constructor. Initialize the ExceptionHandler instance. |
99
|
|
|
* |
100
|
|
|
* @param bool $debug |
101
|
|
|
* @param string|null $charset |
102
|
|
|
* @param string|null $fileLinkformat |
103
|
|
|
* |
104
|
|
|
* @return void |
105
|
|
|
*/ |
106
|
|
|
public function __construct(bool $debug = true, string $charset = null, $fileLinkFormat = null) |
107
|
|
|
{ |
108
|
|
|
$this->debug = $debug; |
109
|
|
|
$this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8'; |
110
|
|
|
$this->fileLinkFormat = $fileLinkFormat; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Sets a user exception handler. |
115
|
|
|
* |
116
|
|
|
* @param \Callable $handler |
|
|
|
|
117
|
|
|
* |
118
|
|
|
* @return \Callable|null |
119
|
|
|
*/ |
120
|
|
|
public function setHandler(Callable $handler) |
121
|
|
|
{ |
122
|
|
|
$oldHandler = $this->handler; |
123
|
|
|
$this->handler = $handler; |
|
|
|
|
124
|
|
|
|
125
|
|
|
return $oldHandler; |
|
|
|
|
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Sets the format for links to source files. |
130
|
|
|
* |
131
|
|
|
* @param string|FileLinkFormatter $fileLinkFormat |
|
|
|
|
132
|
|
|
* |
133
|
|
|
* @return string |
134
|
|
|
*/ |
135
|
|
|
public function setFileLinkFormat($fileLinkFormat) |
136
|
|
|
{ |
137
|
|
|
$oldHandler = $this->handler; |
138
|
|
|
$this->handler = $handler; |
|
|
|
|
139
|
|
|
|
140
|
|
|
return $oldHandler; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Sends a response for the given Exception. |
145
|
|
|
* |
146
|
|
|
* How does it work: |
147
|
|
|
* First, the exception is handled by system exception handler, then by the user exception handler. |
148
|
|
|
* The latter has priority and any exit from the first one is canceled. |
149
|
|
|
* |
150
|
|
|
* @param \Exception $exception |
151
|
|
|
* |
152
|
|
|
* @return void |
153
|
|
|
*/ |
154
|
|
|
public function handler(Exception $exception) |
155
|
|
|
{ |
156
|
|
|
if ($this->handler === null && $exception instanceof OutOfMemoryException) { |
157
|
|
|
$this->sendPhpResponse($exception); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
$caughtLength = $this->caughtLength = 0; |
161
|
|
|
|
162
|
|
|
ob_start(function ($buffer) { |
163
|
|
|
$this->caughtBuffer = $buffer; |
164
|
|
|
|
165
|
|
|
return ''; |
166
|
|
|
}); |
167
|
|
|
|
168
|
|
|
$this->sendPhpResponse($exception); |
169
|
|
|
|
170
|
|
|
if (isset($this->caughtBuffer[0])) { |
171
|
|
|
ob_start(function ($buffer) { |
172
|
|
|
if ($this->caughtLength) { |
173
|
|
|
$cleanBuffer = substr_replace($buffer, '', 0, $this->caughtLength); |
174
|
|
|
|
175
|
|
|
if (isset($cleanBuffer[0])) { |
176
|
|
|
$buffer = $cleanBuffer; |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
return $buffer; |
181
|
|
|
|
182
|
|
|
}); |
183
|
|
|
|
184
|
|
|
echo $this->caughtBuffer; |
185
|
|
|
// Return the length of the output buffer. |
186
|
|
|
$caughtLength = ob_get_length(); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
$this->caughtBuffer = null; |
190
|
|
|
|
191
|
|
|
try { |
192
|
|
|
($this->handler)($exception); |
193
|
|
|
$caughtLength = $this->caughtLength; |
|
|
|
|
194
|
|
|
} catch (Exception $e) { |
195
|
|
|
if ( ! $caughtLength) { |
196
|
|
|
throw $e; |
197
|
|
|
} |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Sends the error associated with the given Exception as a plain PHP response. |
203
|
|
|
* |
204
|
|
|
* This method uses plain php functions as header and echo to generate the output |
205
|
|
|
* response. |
206
|
|
|
* |
207
|
|
|
* @param \Exception|\Syscodes\Debug\FlattenExceptions\FlattenException $exception An \Exception or \FlattenException instance |
|
|
|
|
208
|
|
|
* |
209
|
|
|
* @return string The HTML content as a string |
210
|
|
|
*/ |
211
|
|
|
public function sendPhpResponse($exception) |
212
|
|
|
{ |
213
|
|
|
if ( ! $exception instanceof FlattenException) { |
214
|
|
|
$exception = FlattenException::make($exception); |
|
|
|
|
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
if ( ! headers_sent()) { |
218
|
|
|
header(sprintf('HTTP/1.0 %s', $exception->getStatusCode())); |
|
|
|
|
219
|
|
|
|
220
|
|
|
foreach ($exception->getHeaders() as $name => $value) { |
|
|
|
|
221
|
|
|
header($name.':'.$value, false); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
header('Content-Type: text/html; charset='.$this->charset); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
echo $this->design($this->getContent($exception), $this->getStylesheet()); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Gets the full HTML content associated with the given exception. |
232
|
|
|
* |
233
|
|
|
* @param \Exception|\Syscodes\Debug\FlattenExceptions\FlattenException $exception An \Exception or \FlattenException instance |
234
|
|
|
* |
235
|
|
|
* @return string The HTML content as a string |
236
|
|
|
*/ |
237
|
|
|
public function getHtmlResponse($exception) |
238
|
|
|
{ |
239
|
|
|
if ( ! $exception instanceof FlattenException) { |
240
|
|
|
$exception = FlattenException::make($exception); |
|
|
|
|
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
echo $this->design($this->getContent($exception), $this->getStylesheet()); |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Layout HTML for gets the content and style css. |
248
|
|
|
* |
249
|
|
|
* @param string $content |
250
|
|
|
* @param string $styleCss |
251
|
|
|
* |
252
|
|
|
* @return string |
253
|
|
|
*/ |
254
|
|
|
private function design($content, $styleCss) |
255
|
|
|
{ |
256
|
|
|
return <<<EOF |
257
|
|
|
<!DOCTYPE html> |
258
|
|
|
<html> |
259
|
|
|
<head> |
260
|
|
|
<meta charset="{$this->charset}" /> |
261
|
|
|
<meta name="robots" content="noindex"> |
262
|
|
|
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1"> |
263
|
|
|
<style> |
264
|
|
|
$styleCss |
265
|
|
|
</style> |
266
|
|
|
</head> |
267
|
|
|
<body> |
268
|
|
|
$content |
269
|
|
|
</body> |
270
|
|
|
</html> |
271
|
|
|
EOF; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* Gets the HTML content associated with the given exception. |
276
|
|
|
* |
277
|
|
|
* @param \Syscodes\Debug\FlattenExceptions\FlattenException $exception |
278
|
|
|
* |
279
|
|
|
* @return string The HTML content as a string |
280
|
|
|
*/ |
281
|
|
|
public function getContent(FlattenException $exception) |
282
|
|
|
{ |
283
|
|
|
switch ($exception->getStatusCode()) { |
|
|
|
|
284
|
|
|
case 404: |
285
|
|
|
$title = 'Sorry, the page you are looking to could not be found'; |
286
|
|
|
break; |
287
|
|
|
default: |
288
|
|
|
$title = 'Whoops, looks like something went wrong'; |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
if ( ! $this->debug) { |
292
|
|
|
return <<<EOF |
293
|
|
|
<div class="container"> |
294
|
|
|
<h1>$title</h1> |
295
|
|
|
</div> |
296
|
|
|
EOF; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
$content = ''; |
300
|
|
|
|
301
|
|
|
try { |
302
|
|
|
$count = count($exception->getAllPrevious()); |
303
|
|
|
$total = $count + 1; |
304
|
|
|
|
305
|
|
|
foreach ($exception->toArray() as $position => $e) { |
306
|
|
|
$index = $count - $position + 1; |
307
|
|
|
$class = $this->formatClass($e['class']); |
308
|
|
|
$message = nl2br($this->escapeHtml($e['message'])); |
309
|
|
|
$content .= sprintf(<<<'EOF' |
310
|
|
|
<div class="trace"> |
311
|
|
|
<table> |
312
|
|
|
<tr class="trace-head"><th> |
313
|
|
|
<h3 class="trace-class"> |
314
|
|
|
<span class="text-muted">(%d/%d)</span> |
315
|
|
|
<span class="exception_title">%s</span> |
316
|
|
|
</h3> |
317
|
|
|
<p class="break-long-words trace-message">%s</p> |
318
|
|
|
</th></tr> |
319
|
|
|
EOF |
320
|
|
|
, $index, $total, $class, $message); |
321
|
|
|
|
322
|
|
|
foreach ($e['trace'] as $trace) { |
323
|
|
|
$content .= '<tr><td>'; |
324
|
|
|
|
325
|
|
|
if ($trace['function']) { |
326
|
|
|
$content .= sprintf('from <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'])); |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
if (isset($trace['file']) && isset($trace['line'])) { |
330
|
|
|
$content .= $this->formatPath($trace['file'], $trace['line']); |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
$content .= "</td></tr>\n"; |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
$content .= "</table>\n</div>\n"; |
337
|
|
|
} |
338
|
|
|
} catch (Exception $e) { |
339
|
|
|
if ($this->debug) { |
340
|
|
|
$e = FlattenException::make($e); |
|
|
|
|
341
|
|
|
$title = sprintf('Exception thrown when handling an exception: (%s: %s)', |
342
|
|
|
$e->getClass(), |
343
|
|
|
$this->escapeHtml($e->getMessage()) |
344
|
|
|
); |
345
|
|
|
} else { |
346
|
|
|
$title = 'Whoops, looks like something went wrong'; |
347
|
|
|
} |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
return <<<EOF |
351
|
|
|
<div class="exception"> |
352
|
|
|
<div class="container"> |
353
|
|
|
<div class="exception-wrapper"> |
354
|
|
|
<h1 class="break-long-words exception-message">$title</h1> |
355
|
|
|
</div> |
356
|
|
|
</div> |
357
|
|
|
</div> |
358
|
|
|
|
359
|
|
|
<div class="container"> |
360
|
|
|
$content |
361
|
|
|
</div> |
362
|
|
|
EOF; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
public function getStylesheet() |
366
|
|
|
{ |
367
|
|
|
if ( ! $this->debug) { |
368
|
|
|
return <<<'EOF' |
369
|
|
|
body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; overflow: hidden; } |
370
|
|
|
.container { display: flex; align-items: center; justify-content: center; height: 100vh; width: 100vw; } |
371
|
|
|
h1 { color: #586d7e; font-size: 2em; text-shadow: none; word-break: break-all; word-break: break-word; } |
372
|
|
|
EOF; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
return <<<'EOF' |
376
|
|
|
body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; } |
377
|
|
|
|
378
|
|
|
a { cursor: pointer; text-decoration: none; } |
379
|
|
|
a:hover { text-decoration: underline; } |
380
|
|
|
abbr[title] { border-bottom: none; cursor: help; text-decoration: none; } |
381
|
|
|
|
382
|
|
|
code, pre { font: 13px/1.5 Consolas, Monaco, Menlo, "Ubuntu Mono", "Liberation Mono", monospace; } |
383
|
|
|
|
384
|
|
|
table, tr, th, td { background: #FFF; border-collapse: collapse; vertical-align: top; } |
385
|
|
|
table { background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; } |
386
|
|
|
table th, table td { border: solid #E0E0E0; border-width: 1px 0; padding: 8px 10px; } |
387
|
|
|
table th { background-color: #E0E0E0; font-weight: bold; text-align: left; } |
388
|
|
|
|
389
|
|
|
.hidden-xs-down { display: none; } |
390
|
|
|
.block { display: block; } |
391
|
|
|
.break-long-words { -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; } |
392
|
|
|
.text-muted { color: #999; } |
393
|
|
|
|
394
|
|
|
.container { max-width: 1024px; margin: 0 auto; padding: 0 15px; } |
395
|
|
|
.container::after { content: ""; display: table; clear: both; } |
396
|
|
|
|
397
|
|
|
.exception { 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; } |
398
|
|
|
|
399
|
|
|
.exception-wrapper { display: flex; align-items: center; min-height: 70px; } |
400
|
|
|
.exception-message { flex-grow: 1; padding: 30px 0; text-shadow: none; } |
401
|
|
|
.exception-message, .exception-message a { color: #FFF; font-size: 21px; font-weight: 400; margin: 0; } |
402
|
|
|
.exception-message.long { font-size: 18px; } |
403
|
|
|
.exception-message a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); font-size: inherit; text-decoration: none; } |
404
|
|
|
.exception-message a:hover { border-bottom-color: #ffffff; } |
405
|
|
|
|
406
|
|
|
.exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; } |
407
|
|
|
|
408
|
|
|
.trace + .trace { margin-top: 30px; } |
409
|
|
|
.trace-head .trace-class { color: #222; font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; } |
410
|
|
|
|
411
|
|
|
.trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; } |
412
|
|
|
|
413
|
|
|
.trace-file, .trace-file a { color: #222; margin-top: 3px; font-size: 13px; } |
414
|
|
|
.trace-class { color: #B0413E; } |
415
|
|
|
.trace-type { padding: 0 2px; } |
416
|
|
|
.trace-method { color: #B0413E; font-weight: bold; } |
417
|
|
|
.trace-args { color: #777; font-weight: normal; padding-left: 2px; } |
418
|
|
|
|
419
|
|
|
@media (min-width: 575px) { |
420
|
|
|
.hidden-xs-down { display: initial; } |
421
|
|
|
} |
422
|
|
|
EOF; |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* Gets the format class where the exception. |
427
|
|
|
* |
428
|
|
|
* @param string $class |
429
|
|
|
* |
430
|
|
|
* @return string |
431
|
|
|
*/ |
432
|
|
|
private function formatClass($class) |
433
|
|
|
{ |
434
|
|
|
$parts = explode('\\', $class); |
435
|
|
|
|
436
|
|
|
return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts)); |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
/** |
440
|
|
|
* Gets the path file with you line code. |
441
|
|
|
* |
442
|
|
|
* @param string $path |
443
|
|
|
* @param int $line |
444
|
|
|
* |
445
|
|
|
* @return string |
446
|
|
|
*/ |
447
|
|
|
private function formatPath($path, $line) |
448
|
|
|
{ |
449
|
|
|
$file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path); |
450
|
|
|
$frmt = $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); |
451
|
|
|
|
452
|
|
|
if ( ! $frmt) { |
453
|
|
|
return sprintf('<span class="block trace-file">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', |
454
|
|
|
$this->escapeHtml($path), |
455
|
|
|
$file, |
456
|
|
|
0 < $line ? ' line '.$line : '' |
457
|
|
|
); |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
if (is_string($frmt)) { |
461
|
|
|
$index = strpos($f = $frmt, '&', max(strrpos($f, '%f'), strrpos($f, '%l')) ?: strlen($f)); |
462
|
|
|
$frmt = [substr($f, 0, $index)] + preg_split('/&([^>]++)>/', substr($f, $index), -1, PREG_SPLIT_DELIM_CAPTURE); |
463
|
|
|
|
464
|
|
|
for ($index = 1; isset($frmt[$index]); ++$index) { |
465
|
|
|
if (strpos($path, $k = $frmt[$index++])) { |
466
|
|
|
$path = substr_replace($path, $frmt[$index], 0, strlen($k)); |
|
|
|
|
467
|
|
|
break; |
468
|
|
|
} |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
$data = strstr($frmt[0], ['%f' => $file, '%l' => $line]); |
|
|
|
|
472
|
|
|
} else { |
473
|
|
|
try { |
474
|
|
|
$data = $frmt->format($file, $line); |
475
|
|
|
} catch (Exception $e) { |
476
|
|
|
return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', |
477
|
|
|
$this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : ''); |
478
|
|
|
} |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
return sprintf('<span class="block trace-file">in <a href="%s" title="Go to source"><b>%s</b>%s</a></span>', |
482
|
|
|
$this->escapeHtml($data), $file, $line > 0 ? ' line '.$line : ''); |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* Formats an array as a string. |
487
|
|
|
* |
488
|
|
|
* @param array $args |
489
|
|
|
* |
490
|
|
|
* @return string |
491
|
|
|
*/ |
492
|
|
|
private function formatArgs(array $args) |
493
|
|
|
{ |
494
|
|
|
$result = []; |
495
|
|
|
|
496
|
|
|
foreach ($args as $key => $value) { |
497
|
|
|
if ($value[0] === 'object') { |
498
|
|
|
$formatValue = sprintf('<em>(Object)</em>%s', $this->formatClass($value[1])); |
499
|
|
|
} elseif ($value[0] === 'array') { |
500
|
|
|
$formatValue = sprintf('<em>(array)</em>%s', is_array($value[1]) ? $this->formatArgs($value[1]) : $value[1]); |
501
|
|
|
} elseif ($value[0] === 'null') { |
502
|
|
|
$formatValue = '<em>Null</em>'; |
503
|
|
|
} elseif ($value[0] === 'boolean') { |
504
|
|
|
$formatValue = '<em>'.strtolower(var_export($value[1], true)).'</em>'; |
505
|
|
|
} elseif ($value[0] === 'resource') { |
506
|
|
|
$formatValue = '<em>resource</em>'; |
507
|
|
|
} else { |
508
|
|
|
$formatValue = str_replace("\n", '', $this->escapeHtml(var_export($value[1], true))); |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
$result[] = is_int($key) ? $formatValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formatValue); |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
return implode(', ', $result); |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Gets HTML-encode as a string. |
519
|
|
|
* |
520
|
|
|
* @param string $string |
521
|
|
|
* |
522
|
|
|
* @return string |
523
|
|
|
*/ |
524
|
|
|
private function escapeHtml($string) |
525
|
|
|
{ |
526
|
|
|
return htmlspecialchars($string, ENT_COMPAT | ENT_SUBSTITUTE, $this->charset); |
527
|
|
|
} |
528
|
|
|
} |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths