vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php line 50

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\HttpKernel\DataCollector;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\RequestStack;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
  15. use Symfony\Component\Stopwatch\Stopwatch;
  16. use Symfony\Component\VarDumper\Cloner\Data;
  17. use Symfony\Component\VarDumper\Cloner\VarCloner;
  18. use Symfony\Component\VarDumper\Dumper\CliDumper;
  19. use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
  20. use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
  21. use Symfony\Component\VarDumper\Dumper\HtmlDumper;
  22. use Symfony\Component\VarDumper\Server\Connection;
  23. /**
  24.  * @author Nicolas Grekas <p@tchwork.com>
  25.  *
  26.  * @final
  27.  */
  28. class DumpDataCollector extends DataCollector implements DataDumperInterface
  29. {
  30.     private $stopwatch;
  31.     private $fileLinkFormat;
  32.     private $dataCount 0;
  33.     private $isCollected true;
  34.     private $clonesCount 0;
  35.     private $clonesIndex 0;
  36.     private $rootRefs;
  37.     private $charset;
  38.     private $requestStack;
  39.     private $dumper;
  40.     private $sourceContextProvider;
  41.     /**
  42.      * @param string|FileLinkFormatter|null       $fileLinkFormat
  43.      * @param DataDumperInterface|Connection|null $dumper
  44.      */
  45.     public function __construct(Stopwatch $stopwatch null$fileLinkFormat nullstring $charset nullRequestStack $requestStack null$dumper null)
  46.     {
  47.         $fileLinkFormat $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
  48.         $this->stopwatch $stopwatch;
  49.         $this->fileLinkFormat $fileLinkFormat instanceof FileLinkFormatter && false === $fileLinkFormat->format(''0) ? false $fileLinkFormat;
  50.         $this->charset $charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8';
  51.         $this->requestStack $requestStack;
  52.         $this->dumper $dumper;
  53.         // All clones share these properties by reference:
  54.         $this->rootRefs = [
  55.             &$this->data,
  56.             &$this->dataCount,
  57.             &$this->isCollected,
  58.             &$this->clonesCount,
  59.         ];
  60.         $this->sourceContextProvider $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset);
  61.     }
  62.     public function __clone()
  63.     {
  64.         $this->clonesIndex = ++$this->clonesCount;
  65.     }
  66.     public function dump(Data $data)
  67.     {
  68.         if ($this->stopwatch) {
  69.             $this->stopwatch->start('dump');
  70.         }
  71.         ['name' => $name'file' => $file'line' => $line'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext();
  72.         if ($this->dumper instanceof Connection) {
  73.             if (!$this->dumper->write($data)) {
  74.                 $this->isCollected false;
  75.             }
  76.         } elseif ($this->dumper) {
  77.             $this->doDump($this->dumper$data$name$file$line);
  78.         } else {
  79.             $this->isCollected false;
  80.         }
  81.         if (!$this->dataCount) {
  82.             $this->data = [];
  83.         }
  84.         $this->data[] = compact('data''name''file''line''fileExcerpt');
  85.         ++$this->dataCount;
  86.         if ($this->stopwatch) {
  87.             $this->stopwatch->stop('dump');
  88.         }
  89.     }
  90.     public function collect(Request $requestResponse $response\Throwable $exception null)
  91.     {
  92.         if (!$this->dataCount) {
  93.             $this->data = [];
  94.         }
  95.         // Sub-requests and programmatic calls stay in the collected profile.
  96.         if ($this->dumper || ($this->requestStack && $this->requestStack->getMainRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) {
  97.             return;
  98.         }
  99.         // In all other conditions that remove the web debug toolbar, dumps are written on the output.
  100.         if (!$this->requestStack
  101.             || !$response->headers->has('X-Debug-Token')
  102.             || $response->isRedirection()
  103.             || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html'))
  104.             || 'html' !== $request->getRequestFormat()
  105.             || false === strripos($response->getContent(), '</body>')
  106.         ) {
  107.             if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type'), 'html')) {
  108.                 $dumper = new HtmlDumper('php://output'$this->charset);
  109.                 $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  110.             } else {
  111.                 $dumper = new CliDumper('php://output'$this->charset);
  112.                 if (method_exists($dumper'setDisplayOptions')) {
  113.                     $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  114.                 }
  115.             }
  116.             foreach ($this->data as $dump) {
  117.                 $this->doDump($dumper$dump['data'], $dump['name'], $dump['file'], $dump['line']);
  118.             }
  119.         }
  120.     }
  121.     public function reset()
  122.     {
  123.         if ($this->stopwatch) {
  124.             $this->stopwatch->reset();
  125.         }
  126.         $this->data = [];
  127.         $this->dataCount 0;
  128.         $this->isCollected true;
  129.         $this->clonesCount 0;
  130.         $this->clonesIndex 0;
  131.     }
  132.     /**
  133.      * @internal
  134.      */
  135.     public function __sleep(): array
  136.     {
  137.         if (!$this->dataCount) {
  138.             $this->data = [];
  139.         }
  140.         if ($this->clonesCount !== $this->clonesIndex) {
  141.             return [];
  142.         }
  143.         $this->data[] = $this->fileLinkFormat;
  144.         $this->data[] = $this->charset;
  145.         $this->dataCount 0;
  146.         $this->isCollected true;
  147.         return parent::__sleep();
  148.     }
  149.     /**
  150.      * @internal
  151.      */
  152.     public function __wakeup()
  153.     {
  154.         parent::__wakeup();
  155.         $charset array_pop($this->data);
  156.         $fileLinkFormat array_pop($this->data);
  157.         $this->dataCount \count($this->data);
  158.         foreach ($this->data as $dump) {
  159.             if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) {
  160.                 throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  161.             }
  162.         }
  163.         self::__construct($this->stopwatch\is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter $fileLinkFormat null\is_string($charset) ? $charset null);
  164.     }
  165.     public function getDumpsCount(): int
  166.     {
  167.         return $this->dataCount;
  168.     }
  169.     public function getDumps(string $formatint $maxDepthLimit = -1int $maxItemsPerDepth = -1): array
  170.     {
  171.         $data fopen('php://memory''r+');
  172.         if ('html' === $format) {
  173.             $dumper = new HtmlDumper($data$this->charset);
  174.             $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  175.         } else {
  176.             throw new \InvalidArgumentException(sprintf('Invalid dump format: "%s".'$format));
  177.         }
  178.         $dumps = [];
  179.         if (!$this->dataCount) {
  180.             return $this->data = [];
  181.         }
  182.         foreach ($this->data as $dump) {
  183.             $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth));
  184.             $dump['data'] = stream_get_contents($data, -10);
  185.             ftruncate($data0);
  186.             rewind($data);
  187.             $dumps[] = $dump;
  188.         }
  189.         return $dumps;
  190.     }
  191.     public function getName(): string
  192.     {
  193.         return 'dump';
  194.     }
  195.     public function __destruct()
  196.     {
  197.         if (=== $this->clonesCount-- && !$this->isCollected && $this->dataCount) {
  198.             $this->clonesCount 0;
  199.             $this->isCollected true;
  200.             $h headers_list();
  201.             $i \count($h);
  202.             array_unshift($h'Content-Type: '.\ini_get('default_mimetype'));
  203.             while (!== stripos($h[$i], 'Content-Type:')) {
  204.                 --$i;
  205.             }
  206.             if (!\in_array(\PHP_SAPI, ['cli''phpdbg'], true) && stripos($h[$i], 'html')) {
  207.                 $dumper = new HtmlDumper('php://output'$this->charset);
  208.                 $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  209.             } else {
  210.                 $dumper = new CliDumper('php://output'$this->charset);
  211.                 if (method_exists($dumper'setDisplayOptions')) {
  212.                     $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  213.                 }
  214.             }
  215.             foreach ($this->data as $i => $dump) {
  216.                 $this->data[$i] = null;
  217.                 $this->doDump($dumper$dump['data'], $dump['name'], $dump['file'], $dump['line']);
  218.             }
  219.             $this->data = [];
  220.             $this->dataCount 0;
  221.         }
  222.     }
  223.     private function doDump(DataDumperInterface $dumperData $datastring $namestring $fileint $line)
  224.     {
  225.         if ($dumper instanceof CliDumper) {
  226.             $contextDumper = function ($name$file$line$fmt) {
  227.                 if ($this instanceof HtmlDumper) {
  228.                     if ($file) {
  229.                         $s $this->style('meta''%s');
  230.                         $f strip_tags($this->style(''$file));
  231.                         $name strip_tags($this->style(''$name));
  232.                         if ($fmt && $link \is_string($fmt) ? strtr($fmt, ['%f' => $file'%l' => $line]) : $fmt->format($file$line)) {
  233.                             $name sprintf('<a href="%s" title="%s">'.$s.'</a>'strip_tags($this->style(''$link)), $f$name);
  234.                         } else {
  235.                             $name sprintf('<abbr title="%s">'.$s.'</abbr>'$f$name);
  236.                         }
  237.                     } else {
  238.                         $name $this->style('meta'$name);
  239.                     }
  240.                     $this->line $name.' on line '.$this->style('meta'$line).':';
  241.                 } else {
  242.                     $this->line $this->style('meta'$name).' on line '.$this->style('meta'$line).':';
  243.                 }
  244.                 $this->dumpLine(0);
  245.             };
  246.             $contextDumper $contextDumper->bindTo($dumper$dumper);
  247.             $contextDumper($name$file$line$this->fileLinkFormat);
  248.         } else {
  249.             $cloner = new VarCloner();
  250.             $dumper->dump($cloner->cloneVar($name.' on line '.$line.':'));
  251.         }
  252.         $dumper->dump($data);
  253.     }
  254. }