|
22 | 22 | use Symfony\Component\HttpKernel\Event\ControllerEvent; |
23 | 23 | use Symfony\Component\HttpKernel\Event\ResponseEvent; |
24 | 24 | use Symfony\Component\HttpKernel\KernelEvents; |
| 25 | +use Symfony\Component\Process\Process; |
25 | 26 | use Symfony\Component\VarDumper\Cloner\Data; |
26 | 27 |
|
27 | 28 | /** |
@@ -112,6 +113,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep |
112 | 113 | 'controller' => 'n/a', |
113 | 114 | 'locale' => $request->getLocale(), |
114 | 115 | 'dotenv_vars' => $dotenvVars, |
| 116 | + 'curlCommand' => $this->getCurlCommand(), |
115 | 117 | ]; |
116 | 118 |
|
117 | 119 | if (isset($this->data['request_headers']['php-auth-pw'])) { |
@@ -495,4 +497,76 @@ private function parseController(array|object|string|null $controller): array|st |
495 | 497 |
|
496 | 498 | return \is_string($controller) ? $controller : 'n/a'; |
497 | 499 | } |
| 500 | + |
| 501 | + public function getCurlCommand(): ?string |
| 502 | + { |
| 503 | + if (!isset($this->data['method']) || !isset($this->data['path_info'])) { |
| 504 | + return null; |
| 505 | + } |
| 506 | + |
| 507 | + $command = ['curl', '--compressed']; |
| 508 | + |
| 509 | + // Build the full URL |
| 510 | + $scheme = $this->data['request_server']['HTTPS'] ?? false ? 'https' : 'http'; |
| 511 | + $host = $this->data['request_server']['HTTP_HOST'] ?? $this->data['request_server']['SERVER_NAME'] ?? 'localhost'; |
| 512 | + $url = $scheme . '://' . $host . $this->data['path_info']; |
| 513 | + |
| 514 | + if (!empty($this->data['request_query'])) { |
| 515 | + $url .= '?' . http_build_query($this->data['request_query']->getValue()); |
| 516 | + } |
| 517 | + |
| 518 | + // Add HTTP method |
| 519 | + $method = $this->data['method']; |
| 520 | + if ($method !== 'GET') { |
| 521 | + $command[] = sprintf('--request %s', $method); |
| 522 | + } |
| 523 | + |
| 524 | + $command[] = sprintf('--url %s', escapeshellarg($url)); |
| 525 | + |
| 526 | + // Add headers |
| 527 | + foreach ($this->data['request_headers']->getValue() as $name => $value) { |
| 528 | + if (is_array($value)) { |
| 529 | + $value = implode(', ', $value); |
| 530 | + } |
| 531 | + |
| 532 | + // Skip certain headers |
| 533 | + if (in_array(strtolower($name), ['host', 'cookie'])) { |
| 534 | + continue; |
| 535 | + } |
| 536 | + |
| 537 | + $command[] = '--header ' . escapeshellarg(ucwords($name, '-') . ': ' . $value); |
| 538 | + } |
| 539 | + |
| 540 | + // Add cookies |
| 541 | + if (!empty($this->data['request_cookies']->getValue())) { |
| 542 | + $cookies = []; |
| 543 | + foreach ($this->data['request_cookies']->getValue() as $name => $value) { |
| 544 | + $cookies[] = $name . '=' . $value; |
| 545 | + } |
| 546 | + $command[] = '--header ' . escapeshellarg('Cookie: ' . implode('; ', $cookies)); |
| 547 | + } |
| 548 | + |
| 549 | + // Add body data |
| 550 | + $content = $this->data['content']; |
| 551 | + if (!empty($content) && in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'])) { |
| 552 | + $command[] = '--data-raw ' . $this->escapePayload($content); |
| 553 | + } |
| 554 | + |
| 555 | + return implode(" \\\n ", $command); |
| 556 | + } |
| 557 | + |
| 558 | + private function escapePayload(string $payload): string |
| 559 | + { |
| 560 | + static $useProcess; |
| 561 | + |
| 562 | + if ($useProcess ??= \function_exists('proc_open') && class_exists(\Symfony\Component\Process\Process::class)) { |
| 563 | + return substr((new Process(['', $payload]))->getCommandLine(), 3); |
| 564 | + } |
| 565 | + |
| 566 | + if ('\\' === \DIRECTORY_SEPARATOR) { |
| 567 | + return '"' . str_replace('"', '""', $payload) . '"'; |
| 568 | + } |
| 569 | + |
| 570 | + return "'" . str_replace("'", "'\\''", $payload) . "'"; |
| 571 | + } |
498 | 572 | } |
0 commit comments