1 | <?php |
||||||
2 | |||||||
3 | /** |
||||||
4 | * This file is part of Blitz PHP framework. |
||||||
5 | * |
||||||
6 | * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]> |
||||||
7 | * |
||||||
8 | * For the full copyright and license information, please view |
||||||
9 | * the LICENSE file that was distributed with this source code. |
||||||
10 | */ |
||||||
11 | |||||||
12 | namespace BlitzPHP\Debug; |
||||||
13 | |||||||
14 | use BlitzPHP\Core\Application; |
||||||
15 | use BlitzPHP\Debug\Toolbar\Collectors\BaseCollector; |
||||||
16 | use BlitzPHP\Debug\Toolbar\Collectors\Config; |
||||||
17 | use BlitzPHP\Debug\Toolbar\Collectors\HistoryCollector; |
||||||
18 | use BlitzPHP\Formatter\JsonFormatter; |
||||||
19 | use BlitzPHP\Formatter\XmlFormatter; |
||||||
20 | use BlitzPHP\Http\Request; |
||||||
21 | use BlitzPHP\Http\Response; |
||||||
22 | use BlitzPHP\Utilities\Date; |
||||||
23 | use BlitzPHP\View\Parser; |
||||||
24 | use Exception; |
||||||
25 | use GuzzleHttp\Psr7\Utils; |
||||||
26 | use Kint\Kint; |
||||||
27 | use Psr\Http\Message\ResponseInterface; |
||||||
28 | use Psr\Http\Message\ServerRequestInterface; |
||||||
29 | use stdClass; |
||||||
30 | |||||||
31 | /** |
||||||
32 | * Affiche une barre d'outils avec des bits de statistiques pour aider un développeur dans le débogage. |
||||||
33 | * |
||||||
34 | * Inspiration: http://prophiler.fabfuel.de |
||||||
35 | * |
||||||
36 | * @credit <a href="https://codeigniter.com">CodeIgniter 4.2 - CodeIgniter\Debug\Toolbar</a> |
||||||
37 | */ |
||||||
38 | class Toolbar |
||||||
39 | { |
||||||
40 | /** |
||||||
41 | * Paramètres de configuration de la barre d'outils. |
||||||
42 | * |
||||||
43 | * @var stdClass |
||||||
44 | */ |
||||||
45 | protected $config; |
||||||
46 | |||||||
47 | /** |
||||||
48 | * Collecteurs à utiliser et à exposer. |
||||||
49 | * |
||||||
50 | * @var list<BaseCollector> |
||||||
0 ignored issues
–
show
|
|||||||
51 | */ |
||||||
52 | protected $collectors = []; |
||||||
53 | |||||||
54 | /** |
||||||
55 | * Dossier de sauvegarde des information de debogage |
||||||
56 | */ |
||||||
57 | private string $debugPath = FRAMEWORK_STORAGE_PATH . 'debugbar'; |
||||||
58 | |||||||
59 | /** |
||||||
60 | * Constructeur |
||||||
61 | */ |
||||||
62 | public function __construct(?stdClass $config = null) |
||||||
63 | { |
||||||
64 | $this->config = $config ?? (object) config('toolbar'); |
||||||
65 | |||||||
66 | foreach ($this->config->collectors as $collector) { |
||||||
67 | if (! class_exists($collector)) { |
||||||
68 | logger()->critical( |
||||||
69 | 'Le collecteur de la barre d\'outils n\'existe pas (' . $collector . ').' |
||||||
70 | . ' Veuillez vérifier $collectors dans le fichier app/Config/toolbar.php.' |
||||||
71 | ); |
||||||
72 | |||||||
73 | continue; |
||||||
74 | } |
||||||
75 | |||||||
76 | $this->collectors[] = new $collector(); |
||||||
77 | } |
||||||
78 | } |
||||||
79 | |||||||
80 | /** |
||||||
81 | * Renvoie toutes les données requises par la barre de débogage |
||||||
82 | * |
||||||
83 | * @param float $startTime Heure de début de l'application |
||||||
84 | * @param Request $request |
||||||
85 | * |
||||||
86 | * @return string Données encodées en JSON |
||||||
87 | */ |
||||||
88 | public function run(float $startTime, float $totalTime, ServerRequestInterface $request, ResponseInterface $response): string |
||||||
89 | { |
||||||
90 | // Éléments de données utilisés dans la vue. |
||||||
91 | $data['url'] = current_url(); |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
92 | $data['method'] = $request->getMethod(); |
||||||
93 | $data['isAJAX'] = $request->ajax(); |
||||||
0 ignored issues
–
show
The method
ajax() does not exist on Psr\Http\Message\ServerRequestInterface . It seems like you code against a sub-type of Psr\Http\Message\ServerRequestInterface such as BlitzPHP\Http\ServerRequest .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
94 | $data['startTime'] = $startTime; |
||||||
95 | $data['totalTime'] = $totalTime * 1000; |
||||||
96 | $data['totalMemory'] = number_format(memory_get_peak_usage() / 1024 / 1024, 3); |
||||||
97 | $data['segmentDuration'] = $this->roundTo($data['totalTime'] / 7); |
||||||
98 | $data['segmentCount'] = (int) ceil($data['totalTime'] / $data['segmentDuration']); |
||||||
99 | $data['blitzVersion'] = Application::VERSION; |
||||||
100 | $data['collectors'] = []; |
||||||
101 | |||||||
102 | foreach ($this->collectors as $collector) { |
||||||
103 | $data['collectors'][] = $collector->getAsArray(); |
||||||
104 | } |
||||||
105 | |||||||
106 | foreach ($this->collectVarData() as $heading => $items) { |
||||||
107 | $varData = []; |
||||||
108 | |||||||
109 | if (is_array($items)) { |
||||||
110 | foreach ($items as $key => $value) { |
||||||
111 | if (is_string($value)) { |
||||||
112 | $varData[esc($key)] = esc($value); |
||||||
113 | } else { |
||||||
114 | $oldKintMode = Kint::$mode_default; |
||||||
115 | $oldKintCalledFrom = Kint::$display_called_from; |
||||||
116 | |||||||
117 | Kint::$mode_default = Kint::MODE_RICH; |
||||||
118 | Kint::$display_called_from = false; |
||||||
119 | |||||||
120 | $kint = @Kint::dump($value); |
||||||
121 | $kint = substr($kint, strpos($kint, '</style>') + 8); |
||||||
122 | |||||||
123 | Kint::$mode_default = $oldKintMode; |
||||||
124 | Kint::$display_called_from = $oldKintCalledFrom; |
||||||
125 | |||||||
126 | $varData[esc($key)] = $kint; |
||||||
127 | } |
||||||
128 | } |
||||||
129 | } |
||||||
130 | |||||||
131 | $data['vars']['varData'][esc($heading)] = $varData; |
||||||
132 | } |
||||||
133 | |||||||
134 | if ($_SESSION !== []) { |
||||||
135 | foreach ($_SESSION as $key => $value) { |
||||||
136 | // Remplacez les données binaires par une chaîne pour éviter l'échec de json_encode. |
||||||
137 | if (is_string($value) && preg_match('~[^\x20-\x7E\t\r\n]~', $value)) { |
||||||
138 | $value = 'donnée binaire'; |
||||||
139 | } |
||||||
140 | |||||||
141 | $data['vars']['session'][esc($key)] = is_string($value) ? esc($value) : '<pre>' . esc(print_r($value, true)) . '</pre>'; |
||||||
0 ignored issues
–
show
Are you sure
esc(print_r($value, true)) of type array|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() It seems like
print_r($value, true) can also be of type true ; however, parameter $data of esc() does only seem to accept array|string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
142 | } |
||||||
143 | } |
||||||
144 | |||||||
145 | foreach ($request->getQueryParams() as $name => $value) { |
||||||
146 | $data['vars']['get'][esc($name)] = is_array($value) ? '<pre>' . esc(print_r($value, true)) . '</pre>' : esc($value); |
||||||
147 | } |
||||||
148 | |||||||
149 | foreach ($request->getParsedBody() as $name => $value) { |
||||||
150 | $data['vars']['post'][esc($name)] = is_array($value) ? '<pre>' . esc(print_r($value, true)) . '</pre>' : esc($value); |
||||||
151 | } |
||||||
152 | |||||||
153 | foreach ($request->getHeaders() as $header => $value) { |
||||||
154 | if (empty($value)) { |
||||||
155 | continue; |
||||||
156 | } |
||||||
157 | $data['vars']['headers'][esc($header)] = esc($request->getHeaderLine($header)); |
||||||
158 | } |
||||||
159 | |||||||
160 | foreach ($request->getCookieParams() as $name => $value) { |
||||||
161 | $data['vars']['cookies'][esc($name)] = esc($value); |
||||||
162 | } |
||||||
163 | |||||||
164 | $data['vars']['request'] = ($request->is('ssl') ? 'HTTPS' : 'HTTP') . '/' . $request->getProtocolVersion(); |
||||||
0 ignored issues
–
show
The method
is() does not exist on Psr\Http\Message\ServerRequestInterface . It seems like you code against a sub-type of Psr\Http\Message\ServerRequestInterface such as BlitzPHP\Http\ServerRequest .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
165 | |||||||
166 | $data['vars']['response'] = [ |
||||||
167 | 'statusCode' => $response->getStatusCode(), |
||||||
168 | 'reason' => esc($response->getReasonPhrase()), |
||||||
169 | 'contentType' => esc($response->getHeaderLine('Content-Type')), |
||||||
170 | 'headers' => [], |
||||||
171 | ]; |
||||||
172 | |||||||
173 | foreach ($response->getHeaders() as $header => $value) { |
||||||
174 | if (empty($value)) { |
||||||
175 | continue; |
||||||
176 | } |
||||||
177 | $data['vars']['response']['headers'][esc($header)] = esc($response->getHeaderLine($header)); |
||||||
178 | } |
||||||
179 | |||||||
180 | $data['config'] = Config::display(); |
||||||
181 | |||||||
182 | return json_encode($data); |
||||||
183 | } |
||||||
184 | |||||||
185 | /** |
||||||
186 | * Appelé dans la vue pour afficher la chronologie elle-même. |
||||||
187 | */ |
||||||
188 | protected function renderTimeline(array $collectors, float $startTime, int $segmentCount, int $segmentDuration, array &$styles): string |
||||||
189 | { |
||||||
190 | $rows = $this->collectTimelineData($collectors); |
||||||
191 | $styleCount = 0; |
||||||
192 | |||||||
193 | // Utiliser la fonction de rendu récursif |
||||||
194 | return $this->renderTimelineRecursive($rows, $startTime, $segmentCount, $segmentDuration, $styles, $styleCount); |
||||||
195 | } |
||||||
196 | |||||||
197 | /** |
||||||
198 | * Restitue de manière récursive les éléments de la chronologie et leurs enfants. |
||||||
199 | */ |
||||||
200 | protected function renderTimelineRecursive(array $rows, float $startTime, int $segmentCount, int $segmentDuration, array &$styles, int &$styleCount, int $level = 0, bool $isChild = false): string |
||||||
201 | { |
||||||
202 | $displayTime = $segmentCount * $segmentDuration; |
||||||
203 | |||||||
204 | $output = ''; |
||||||
205 | |||||||
206 | foreach ($rows as $row) { |
||||||
207 | $hasChildren = isset($row['children']) && ! empty($row['children']); |
||||||
208 | $isQuery = isset($row['query']) && ! empty($row['query']); |
||||||
209 | |||||||
210 | // Ouvrir la chronologie du contrôleur par défaut |
||||||
211 | $open = $row['name'] === 'Controller'; |
||||||
212 | |||||||
213 | if ($hasChildren || $isQuery) { |
||||||
214 | $output .= '<tr class="timeline-parent' . ($open ? ' timeline-parent-open' : '') . '" id="timeline-' . $styleCount . '_parent" data-toggle="childrows" data-child="timeline-' . $styleCount . '">'; |
||||||
215 | } else { |
||||||
216 | $output .= '<tr>'; |
||||||
217 | } |
||||||
218 | |||||||
219 | $output .= '<td class="' . ($isChild ? 'debug-bar-width30' : '') . ' debug-bar-level-' . $level . '" >' . ($hasChildren || $isQuery ? '<nav></nav>' : '') . $row['name'] . '</td>'; |
||||||
220 | $output .= '<td class="' . ($isChild ? 'debug-bar-width10' : '') . '">' . $row['component'] . '</td>'; |
||||||
221 | $output .= '<td class="' . ($isChild ? 'debug-bar-width10 ' : '') . 'debug-bar-alignRight">' . number_format($row['duration'] * 1000, 2) . ' ms</td>'; |
||||||
222 | $output .= "<td class='debug-bar-noverflow' colspan='{$segmentCount}'>"; |
||||||
223 | |||||||
224 | $offset = ((((float) $row['start'] - $startTime) * 1000) / $displayTime) * 100; |
||||||
225 | $length = (((float) $row['duration'] * 1000) / $displayTime) * 100; |
||||||
226 | |||||||
227 | $styles['debug-bar-timeline-' . $styleCount] = "left: {$offset}%; width: {$length}%;"; |
||||||
228 | |||||||
229 | $output .= "<span class='timer debug-bar-timeline-{$styleCount}' title='" . number_format($length, 2) . "%'></span>"; |
||||||
230 | $output .= '</td>'; |
||||||
231 | $output .= '</tr>'; |
||||||
232 | |||||||
233 | $styleCount++; |
||||||
234 | |||||||
235 | // Ajouter des enfants le cas échéant |
||||||
236 | if ($hasChildren || $isQuery) { |
||||||
237 | $output .= '<tr class="child-row ' . ($open ? '' : ' debug-bar-ndisplay') . '" id="timeline-' . ($styleCount - 1) . '_children" >'; |
||||||
238 | $output .= '<td colspan="' . ($segmentCount + 3) . '" class="child-container">'; |
||||||
239 | $output .= '<table class="timeline">'; |
||||||
240 | $output .= '<tbody>'; |
||||||
241 | |||||||
242 | if ($isQuery) { |
||||||
243 | // Sortie de la chaîne de requête si requête |
||||||
244 | $output .= '<tr>'; |
||||||
245 | $output .= '<td class="query-container debug-bar-level-' . ($level + 1) . '" >' . $row['query'] . '</td>'; |
||||||
246 | $output .= '</tr>'; |
||||||
247 | } else { |
||||||
248 | // Rendre récursivement les enfants |
||||||
249 | $output .= $this->renderTimelineRecursive($row['children'], $startTime, $segmentCount, $segmentDuration, $styles, $styleCount, $level + 1, true); |
||||||
250 | } |
||||||
251 | |||||||
252 | $output .= '</tbody>'; |
||||||
253 | $output .= '</table>'; |
||||||
254 | $output .= '</td>'; |
||||||
255 | $output .= '</tr>'; |
||||||
256 | } |
||||||
257 | } |
||||||
258 | |||||||
259 | return $output; |
||||||
260 | } |
||||||
261 | |||||||
262 | /** |
||||||
263 | * Renvoie un tableau trié de tableaux de données chronologiques à partir des collecteurs. |
||||||
264 | * |
||||||
265 | * @param mixed $collectors |
||||||
266 | */ |
||||||
267 | protected function collectTimelineData($collectors): array |
||||||
268 | { |
||||||
269 | $data = []; |
||||||
270 | |||||||
271 | // Le collecter |
||||||
272 | foreach ($collectors as $collector) { |
||||||
273 | if (! $collector['hasTimelineData']) { |
||||||
274 | continue; |
||||||
275 | } |
||||||
276 | |||||||
277 | $data = array_merge($data, $collector['timelineData']); |
||||||
278 | } |
||||||
279 | |||||||
280 | // Le trier |
||||||
281 | $sortArray = [ |
||||||
282 | array_column($data, 'start'), SORT_NUMERIC, SORT_ASC, |
||||||
283 | array_column($data, 'duration'), SORT_NUMERIC, SORT_DESC, |
||||||
284 | &$data, |
||||||
285 | ]; |
||||||
286 | |||||||
287 | array_multisort(...$sortArray); |
||||||
0 ignored issues
–
show
It seems like
$sortArray can also be of type integer ; however, parameter $array of array_multisort() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
288 | |||||||
289 | // Ajouter une heure de fin à chaque élément |
||||||
290 | array_walk($data, static function (&$row): void { |
||||||
291 | $row['end'] = $row['start'] + $row['duration']; |
||||||
292 | }); |
||||||
293 | |||||||
294 | // Le grouper |
||||||
295 | $data = $this->structureTimelineData($data); |
||||||
296 | |||||||
297 | return $data; |
||||||
298 | } |
||||||
299 | |||||||
300 | /** |
||||||
301 | * Organise les données de chronologie déjà triées dans une structure parent => enfant. |
||||||
302 | */ |
||||||
303 | protected function structureTimelineData(array $elements): array |
||||||
304 | { |
||||||
305 | // Nous nous définissons comme le premier élément du tableau |
||||||
306 | $element = array_shift($elements); |
||||||
307 | |||||||
308 | // Si nous avons des enfants derrière nous, récupérez-les et attachez-les-nous |
||||||
309 | while ($elements !== [] && $elements[array_key_first($elements)]['end'] <= $element['end']) { |
||||||
310 | $element['children'][] = array_shift($elements); |
||||||
311 | } |
||||||
312 | |||||||
313 | // Assurez-vous que nos enfants sachent s'ils ont eux aussi des enfants |
||||||
314 | if (isset($element['children'])) { |
||||||
315 | $element['children'] = $this->structureTimelineData($element['children']); |
||||||
316 | } |
||||||
317 | |||||||
318 | // Si nous n'avons pas de frères et sœurs plus jeunes, nous pouvons revenir |
||||||
319 | if ($elements === []) { |
||||||
320 | return [$element]; |
||||||
321 | } |
||||||
322 | |||||||
323 | // Assurez-vous que nos jeunes frères et sœurs connaissent également leurs proches |
||||||
324 | return array_merge([$element], $this->structureTimelineData($elements)); |
||||||
325 | } |
||||||
326 | |||||||
327 | /** |
||||||
328 | * Renvoie un tableau de données de tous les modules |
||||||
329 | * qui devrait être affiché dans l'onglet 'Vars'. |
||||||
330 | */ |
||||||
331 | protected function collectVarData(): array |
||||||
332 | { |
||||||
333 | if (! ($this->config->collectVarData ?? true)) { |
||||||
334 | return []; |
||||||
335 | } |
||||||
336 | |||||||
337 | $data = []; |
||||||
338 | |||||||
339 | foreach ($this->collectors as $collector) { |
||||||
340 | if (! $collector->hasVarData()) { |
||||||
341 | continue; |
||||||
342 | } |
||||||
343 | |||||||
344 | $data = array_merge($data, $collector->getVarData()); |
||||||
345 | } |
||||||
346 | |||||||
347 | return $data; |
||||||
348 | } |
||||||
349 | |||||||
350 | /** |
||||||
351 | * Arrondit un nombre à la valeur incrémentielle la plus proche. |
||||||
352 | */ |
||||||
353 | protected function roundTo(float $number, int $increments = 5): float |
||||||
354 | { |
||||||
355 | $increments = 1 / $increments; |
||||||
356 | |||||||
357 | return ceil($number * $increments) / $increments; |
||||||
358 | } |
||||||
359 | |||||||
360 | /** |
||||||
361 | * Traite la barre d'outils de débogage pour la requête en cours. |
||||||
362 | * |
||||||
363 | * Cette méthode détermine s'il faut afficher la barre d'outils de débogage ou la préparer pour une utilisation ultérieure. |
||||||
364 | * |
||||||
365 | * @param array $stats Un tableau contenant des statistiques de performances. |
||||||
366 | * @param Request $request La requête serveur en cours. |
||||||
367 | * @param ResponseInterface $response La réponse en cours. |
||||||
368 | * |
||||||
369 | * @return ResponseInterface La réponse traitée, avec la barre d'outils de débogage injectée ou préparée pour une utilisation ultérieure. |
||||||
370 | */ |
||||||
371 | public function process(array $stats, ServerRequestInterface $request, ResponseInterface $response): ResponseInterface |
||||||
372 | { |
||||||
373 | if ($request->hasAny('blitzphp-debugbar', 'debugbar_time')) { |
||||||
0 ignored issues
–
show
The method
hasAny() does not exist on Psr\Http\Message\ServerRequestInterface . It seems like you code against a sub-type of Psr\Http\Message\ServerRequestInterface such as BlitzPHP\Http\ServerRequest .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
374 | return $this->respond($request); |
||||||
375 | } |
||||||
376 | |||||||
377 | return $this->prepare($stats, $request, $response); |
||||||
378 | } |
||||||
379 | |||||||
380 | /** |
||||||
381 | * Préparez-vous au débogage.. |
||||||
382 | */ |
||||||
383 | public function prepare(array $stats, ?ServerRequestInterface $request = null, ?ResponseInterface $response = null): ResponseInterface |
||||||
384 | { |
||||||
385 | /** @var Request $request */ |
||||||
386 | $request ??= service('request'); |
||||||
387 | /** @var Response $response */ |
||||||
388 | $response ??= service('response'); |
||||||
389 | |||||||
390 | // Si on est en CLI ou en prod, pas la peine de continuer car la debugbar n'est pas utilisable dans ces environnements |
||||||
391 | if (is_cli() || on_prod()) { |
||||||
392 | return $response; |
||||||
393 | } |
||||||
394 | |||||||
395 | // Si on a desactiver le debogage ou l'affichage de la debugbar, on s'arrete |
||||||
396 | if (! BLITZ_DEBUG || ! $this->config->show_debugbar) { |
||||||
397 | return $response; |
||||||
398 | } |
||||||
399 | |||||||
400 | $toolbar = service('toolbar', $this->config); |
||||||
401 | $data = $toolbar->run( |
||||||
402 | $stats['startTime'], |
||||||
403 | $stats['totalTime'], |
||||||
404 | $request, |
||||||
405 | $response |
||||||
406 | ); |
||||||
407 | |||||||
408 | // Mise à jour vers microtime() pour que nous puissions obtenir l'historique |
||||||
409 | $time = sprintf('%.6f', Date::now()->format('U.u')); |
||||||
410 | |||||||
411 | if (! is_dir($this->debugPath)) { |
||||||
412 | mkdir($this->debugPath, 0o777); |
||||||
413 | } |
||||||
414 | |||||||
415 | $this->writeFile($this->debugPath . '/debugbar_' . $time . '.json', $data, 'w+'); |
||||||
416 | |||||||
417 | $format = $response->getHeaderLine('Content-Type'); |
||||||
418 | |||||||
419 | // Les formats non HTML ne doivent pas inclure la barre de débogage, |
||||||
420 | // puis nous envoyons des en-têtes indiquant où trouver les données de débogage pour cette réponse |
||||||
421 | if ($request->ajax() || ! str_contains($format, 'html')) { |
||||||
422 | return $response |
||||||
0 ignored issues
–
show
|
|||||||
423 | ->withHeader('Debugbar-Time', "{$time}") |
||||||
424 | ->withHeader('Debugbar-Link', site_url("?debugbar_time={$time}")); |
||||||
425 | } |
||||||
426 | |||||||
427 | $oldKintMode = Kint::$mode_default; |
||||||
428 | Kint::$mode_default = Kint::MODE_RICH; |
||||||
429 | $kintScript = @Kint::dump(''); |
||||||
430 | Kint::$mode_default = $oldKintMode; |
||||||
431 | $kintScript = substr($kintScript, 0, strpos($kintScript, '</style>') + 8); |
||||||
432 | $kintScript = ($kintScript === '0') ? '' : $kintScript; |
||||||
433 | |||||||
434 | $script = PHP_EOL |
||||||
435 | . '<script id="debugbar_loader" ' |
||||||
436 | . 'data-time="' . $time . '" ' |
||||||
437 | . 'src="' . site_url() . '?blitzphp-debugbar"></script>' |
||||||
438 | . '<script id="debugbar_dynamic_script"></script>' |
||||||
439 | . '<style id="debugbar_dynamic_style"></style>' |
||||||
440 | . $kintScript |
||||||
441 | . PHP_EOL; |
||||||
442 | |||||||
443 | if (str_contains($responseContent = (string) $response->getBody(), '<head>')) { |
||||||
444 | $responseContent = preg_replace( |
||||||
445 | '/<head>/', |
||||||
446 | '<head>' . $script, |
||||||
447 | $responseContent, |
||||||
448 | 1, |
||||||
449 | ); |
||||||
450 | } else { |
||||||
451 | $responseContent .= $script; |
||||||
452 | } |
||||||
453 | |||||||
454 | return $response->withBody(Utils::streamFor($responseContent)); |
||||||
0 ignored issues
–
show
|
|||||||
455 | } |
||||||
456 | |||||||
457 | /** |
||||||
458 | * Injectez la barre d'outils de débogage dans la réponse. |
||||||
459 | * |
||||||
460 | * @param Request $request |
||||||
461 | * |
||||||
462 | * @codeCoverageIgnore |
||||||
463 | */ |
||||||
464 | public function respond(ServerRequestInterface $request): Response |
||||||
465 | { |
||||||
466 | $response = new Response(); |
||||||
467 | |||||||
468 | if (on_test()) { |
||||||
469 | return $response; |
||||||
470 | } |
||||||
471 | |||||||
472 | // Si la requête contient '?blitzphp-debugbar alors nous sommes |
||||||
473 | // renvoie simplement le script de chargement |
||||||
474 | if ($request->getQuery('blitzphp-debugbar') !== null) { |
||||||
0 ignored issues
–
show
The method
getQuery() does not exist on Psr\Http\Message\ServerRequestInterface . Did you maybe mean getQueryParams() ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
475 | $response = $response->withType('application/javascript'); |
||||||
476 | |||||||
477 | ob_start(); |
||||||
478 | include $this->config->view_path . DS . 'toolbarloader.js'; |
||||||
479 | $output = ob_get_clean(); |
||||||
480 | |||||||
481 | return $response->withStringBody(str_replace('{url}', rtrim(site_url(), '/'), $output)); |
||||||
482 | } |
||||||
483 | |||||||
484 | // Sinon, s'il inclut ?debugbar_time, alors |
||||||
485 | // nous devrions retourner la barre de débogage entière. |
||||||
486 | if (null !== $debugbarTime = $request->getQuery('debugbar_time')) { |
||||||
487 | // Négociation du type de contenu pour formater la sortie |
||||||
488 | $format = $request->negotiate('media', ['text/html', 'application/json', 'application/xml']); |
||||||
0 ignored issues
–
show
The method
negotiate() does not exist on Psr\Http\Message\ServerRequestInterface . It seems like you code against a sub-type of Psr\Http\Message\ServerRequestInterface such as BlitzPHP\Http\ServerRequest .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
489 | $response = $response->withType($format); |
||||||
490 | $format = explode('/', $format)[1]; |
||||||
491 | |||||||
492 | $filename = 'debugbar_' . $debugbarTime; |
||||||
493 | $filename = $this->debugPath . DS . $filename . '.json'; |
||||||
494 | |||||||
495 | if (is_file($filename)) { |
||||||
496 | // Affiche la barre d'outils si elle existe |
||||||
497 | return $response->withStringBody($this->format($debugbarTime, file_get_contents($filename), $format)); |
||||||
498 | } |
||||||
499 | } |
||||||
500 | |||||||
501 | // Nom de fichier introuvable |
||||||
502 | return $response->withStatus(404); |
||||||
503 | } |
||||||
504 | |||||||
505 | /** |
||||||
506 | * Formatte la sortie |
||||||
507 | * |
||||||
508 | * @param mixed $debugbar_time |
||||||
509 | */ |
||||||
510 | protected function format($debugbar_time, string $data, string $format = 'html'): string |
||||||
511 | { |
||||||
512 | $data = json_decode($data, true); |
||||||
513 | |||||||
514 | if ($this->config->max_history !== 0 && preg_match('/\d+\.\d{6}/s', (string) $debugbar_time, $debugbarTime)) { |
||||||
515 | $history = new HistoryCollector(); |
||||||
516 | $history->setFiles( |
||||||
517 | $debugbarTime[0], |
||||||
518 | $this->config->max_history |
||||||
519 | ); |
||||||
520 | |||||||
521 | $data['collectors'][] = $history->getAsArray(); |
||||||
522 | } |
||||||
523 | $output = ''; |
||||||
524 | |||||||
525 | switch ($format) { |
||||||
526 | case 'html': |
||||||
527 | $data['styles'] = []; |
||||||
528 | extract($data); |
||||||
529 | $parser = new Parser([], $this->config->view_path); |
||||||
530 | ob_start(); |
||||||
531 | include rtrim($this->config->view_path, '/\\') . DS . 'toolbar.tpl.php'; |
||||||
532 | $output = ob_get_clean(); |
||||||
533 | break; |
||||||
534 | |||||||
535 | case 'json': |
||||||
536 | $formatter = new JsonFormatter(); |
||||||
537 | $output = $formatter->format($data); |
||||||
538 | break; |
||||||
539 | |||||||
540 | case 'xml': |
||||||
541 | $formatter = new XmlFormatter(); |
||||||
542 | $output = $formatter->format($data); |
||||||
543 | break; |
||||||
544 | } |
||||||
545 | |||||||
546 | return $output; |
||||||
0 ignored issues
–
show
|
|||||||
547 | } |
||||||
548 | |||||||
549 | /** |
||||||
550 | * Écrit des données dans le fichier spécifié dans le chemin. |
||||||
551 | * Crée un nouveau fichier s'il n'existe pas. |
||||||
552 | */ |
||||||
553 | protected function writeFile(string $path, string $data, string $mode = 'wb'): bool |
||||||
554 | { |
||||||
555 | try { |
||||||
556 | $fp = fopen($path, $mode); |
||||||
557 | |||||||
558 | flock($fp, LOCK_EX); |
||||||
559 | |||||||
560 | for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) { |
||||||
561 | if (($result = fwrite($fp, substr($data, $written))) === false) { |
||||||
562 | break; |
||||||
563 | } |
||||||
564 | } |
||||||
565 | |||||||
566 | flock($fp, LOCK_UN); |
||||||
567 | fclose($fp); |
||||||
568 | |||||||
569 | return is_int($result); |
||||||
570 | } catch (Exception) { |
||||||
571 | return false; |
||||||
572 | } |
||||||
573 | } |
||||||
574 | } |
||||||
575 |
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