blitz-php /
framework
| 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
Loading history...
|
|||||||
| 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
Loading history...
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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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. Loading history...
|
|||||||
| 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
Loading history...
|
|||||||
| 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