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

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 since Symfony 4.3
  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.     /**
  91.      * {@inheritdoc}
  92.      *
  93.      * @param \Throwable|null $exception
  94.      */
  95.     public function collect(Request $requestResponse $response/* , \Throwable $exception = null */)
  96.     {
  97.         if (!$this->dataCount) {
  98.             $this->data = [];
  99.         }
  100.         // Sub-requests and programmatic calls stay in the collected profile.
  101.         if ($this->dumper || ($this->requestStack && $this->requestStack->getMasterRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) {
  102.             return;
  103.         }
  104.         // In all other conditions that remove the web debug toolbar, dumps are written on the output.
  105.         if (!$this->requestStack
  106.             || !$response->headers->has('X-Debug-Token')
  107.             || $response->isRedirection()
  108.             || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html'))
  109.             || 'html' !== $request->getRequestFormat()
  110.             || false === strripos($response->getContent(), '</body>')
  111.         ) {
  112.             if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type'), 'html')) {
  113.                 $dumper = new HtmlDumper('php://output'$this->charset);
  114.                 $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  115.             } else {
  116.                 $dumper = new CliDumper('php://output'$this->charset);
  117.                 if (method_exists($dumper'setDisplayOptions')) {
  118.                     $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  119.                 }
  120.             }
  121.             foreach ($this->data as $dump) {
  122.                 $this->doDump($dumper$dump['data'], $dump['name'], $dump['file'], $dump['line']);
  123.             }
  124.         }
  125.     }
  126.     public function reset()
  127.     {
  128.         if ($this->stopwatch) {
  129.             $this->stopwatch->reset();
  130.         }
  131.         $this->data = [];
  132.         $this->dataCount 0;
  133.         $this->isCollected true;
  134.         $this->clonesCount 0;
  135.         $this->clonesIndex 0;
  136.     }
  137.     /**
  138.      * @internal
  139.      */
  140.     public function __sleep(): array
  141.     {
  142.         if (!$this->dataCount) {
  143.             $this->data = [];
  144.         }
  145.         if ($this->clonesCount !== $this->clonesIndex) {
  146.             return [];
  147.         }
  148.         $this->data[] = $this->fileLinkFormat;
  149.         $this->data[] = $this->charset;
  150.         $this->dataCount 0;
  151.         $this->isCollected true;
  152.         return parent::__sleep();
  153.     }
  154.     /**
  155.      * @internal
  156.      */
  157.     public function __wakeup()
  158.     {
  159.         parent::__wakeup();
  160.         $charset array_pop($this->data);
  161.         $fileLinkFormat array_pop($this->data);
  162.         $this->dataCount = \count($this->data);
  163.         foreach ($this->data as $dump) {
  164.             if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) {
  165.                 throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  166.             }
  167.         }
  168.         self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter $fileLinkFormat null, \is_string($charset) ? $charset null);
  169.     }
  170.     public function getDumpsCount()
  171.     {
  172.         return $this->dataCount;
  173.     }
  174.     public function getDumps($format$maxDepthLimit = -1$maxItemsPerDepth = -1)
  175.     {
  176.         $data fopen('php://memory''r+');
  177.         if ('html' === $format) {
  178.             $dumper = new HtmlDumper($data$this->charset);
  179.             $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  180.         } else {
  181.             throw new \InvalidArgumentException(sprintf('Invalid dump format: "%s".'$format));
  182.         }
  183.         $dumps = [];
  184.         if (!$this->dataCount) {
  185.             return $this->data = [];
  186.         }
  187.         foreach ($this->data as $dump) {
  188.             $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth));
  189.             $dump['data'] = stream_get_contents($data, -10);
  190.             ftruncate($data0);
  191.             rewind($data);
  192.             $dumps[] = $dump;
  193.         }
  194.         return $dumps;
  195.     }
  196.     public function getName()
  197.     {
  198.         return 'dump';
  199.     }
  200.     public function __destruct()
  201.     {
  202.         if (=== $this->clonesCount-- && !$this->isCollected && $this->dataCount) {
  203.             $this->clonesCount 0;
  204.             $this->isCollected true;
  205.             $h headers_list();
  206.             $i = \count($h);
  207.             array_unshift($h'Content-Type: '.\ini_get('default_mimetype'));
  208.             while (!== stripos($h[$i], 'Content-Type:')) {
  209.                 --$i;
  210.             }
  211.             if (!\in_array(\PHP_SAPI, ['cli''phpdbg'], true) && stripos($h[$i], 'html')) {
  212.                 $dumper = new HtmlDumper('php://output'$this->charset);
  213.                 $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  214.             } else {
  215.                 $dumper = new CliDumper('php://output'$this->charset);
  216.                 if (method_exists($dumper'setDisplayOptions')) {
  217.                     $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
  218.                 }
  219.             }
  220.             foreach ($this->data as $i => $dump) {
  221.                 $this->data[$i] = null;
  222.                 $this->doDump($dumper$dump['data'], $dump['name'], $dump['file'], $dump['line']);
  223.             }
  224.             $this->data = [];
  225.             $this->dataCount 0;
  226.         }
  227.     }
  228.     private function doDump(DataDumperInterface $dumperData $datastring $namestring $fileint $line)
  229.     {
  230.         if ($dumper instanceof CliDumper) {
  231.             $contextDumper = function ($name$file$line$fmt) {
  232.                 if ($this instanceof HtmlDumper) {
  233.                     if ($file) {
  234.                         $s $this->style('meta''%s');
  235.                         $f strip_tags($this->style(''$file));
  236.                         $name strip_tags($this->style(''$name));
  237.                         if ($fmt && $link = \is_string($fmt) ? strtr($fmt, ['%f' => $file'%l' => $line]) : $fmt->format($file$line)) {
  238.                             $name sprintf('<a href="%s" title="%s">'.$s.'</a>'strip_tags($this->style(''$link)), $f$name);
  239.                         } else {
  240.                             $name sprintf('<abbr title="%s">'.$s.'</abbr>'$f$name);
  241.                         }
  242.                     } else {
  243.                         $name $this->style('meta'$name);
  244.                     }
  245.                     $this->line $name.' on line '.$this->style('meta'$line).':';
  246.                 } else {
  247.                     $this->line $this->style('meta'$name).' on line '.$this->style('meta'$line).':';
  248.                 }
  249.                 $this->dumpLine(0);
  250.             };
  251.             $contextDumper $contextDumper->bindTo($dumper$dumper);
  252.             $contextDumper($name$file$line$this->fileLinkFormat);
  253.         } else {
  254.             $cloner = new VarCloner();
  255.             $dumper->dump($cloner->cloneVar($name.' on line '.$line.':'));
  256.         }
  257.         $dumper->dump($data);
  258.     }
  259. }