File manager - Edit - /home/opticamezl/www/newok/var-dumper.tar
Back
Command/ServerDumpCommand.php 0000644 00000007464 15173250124 0012241 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor; use Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface; use Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\Server\DumpServer; /** * Starts a dump server to collect and output dumps on a single place with multiple formats support. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> * * @final */ class ServerDumpCommand extends Command { protected static $defaultName = 'server:dump'; protected static $defaultDescription = 'Start a dump server that collects and displays dumps in a single place'; private $server; /** @var DumpDescriptorInterface[] */ private $descriptors; public function __construct(DumpServer $server, array $descriptors = []) { $this->server = $server; $this->descriptors = $descriptors + [ 'cli' => new CliDescriptor(new CliDumper()), 'html' => new HtmlDescriptor(new HtmlDumper()), ]; parent::__construct(); } protected function configure() { $this ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', implode(', ', $this->getAvailableFormats())), 'cli') ->setDescription(self::$defaultDescription) ->setHelp(<<<'EOF' <info>%command.name%</info> starts a dump server that collects and displays dumps in a single place for debugging you application: <info>php %command.full_name%</info> You can consult dumped data in HTML format in your browser by providing the <comment>--format=html</comment> option and redirecting the output to a file: <info>php %command.full_name% --format="html" > dump.html</info> EOF ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $format = $input->getOption('format'); if (!$descriptor = $this->descriptors[$format] ?? null) { throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $format)); } $errorIo = $io->getErrorStyle(); $errorIo->title('Symfony Var Dumper Server'); $this->server->start(); $errorIo->success(sprintf('Server listening on %s', $this->server->getHost())); $errorIo->comment('Quit the server with CONTROL-C.'); $this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) { $descriptor->describe($io, $data, $context, $clientId); }); return 0; } public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { if ($input->mustSuggestOptionValuesFor('format')) { $suggestions->suggestValues($this->getAvailableFormats()); } } private function getAvailableFormats(): array { return array_keys($this->descriptors); } } Command/Descriptor/CliDescriptor.php 0000644 00000005115 15173250124 0013521 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Command\Descriptor; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\CliDumper; /** * Describe collected data clones for cli output. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> * * @final */ class CliDescriptor implements DumpDescriptorInterface { private $dumper; private $lastIdentifier; public function __construct(CliDumper $dumper) { $this->dumper = $dumper; } public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void { $io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output); $this->dumper->setColors($output->isDecorated()); $rows = [['date', date('r', (int) $context['timestamp'])]]; $lastIdentifier = $this->lastIdentifier; $this->lastIdentifier = $clientId; $section = "Received from client #$clientId"; if (isset($context['request'])) { $request = $context['request']; $this->lastIdentifier = $request['identifier']; $section = sprintf('%s %s', $request['method'], $request['uri']); if ($controller = $request['controller']) { $rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")]; } } elseif (isset($context['cli'])) { $this->lastIdentifier = $context['cli']['identifier']; $section = '$ '.$context['cli']['command_line']; } if ($this->lastIdentifier !== $lastIdentifier) { $io->section($section); } if (isset($context['source'])) { $source = $context['source']; $sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']); if ($fileLink = $source['file_link'] ?? null) { $sourceInfo = sprintf('<href=%s>%s</>', $fileLink, $sourceInfo); } $rows[] = ['source', $sourceInfo]; $file = $source['file_relative'] ?? $source['file']; $rows[] = ['file', $file]; } $io->table([], $rows); $this->dumper->dump($data); $io->newLine(); } } Command/Descriptor/HtmlDescriptor.php 0000644 00000007154 15173250124 0013723 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Command\Descriptor; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\HtmlDumper; /** * Describe collected data clones for html output. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> * * @final */ class HtmlDescriptor implements DumpDescriptorInterface { private $dumper; private $initialized = false; public function __construct(HtmlDumper $dumper) { $this->dumper = $dumper; } public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void { if (!$this->initialized) { $styles = file_get_contents(__DIR__.'/../../Resources/css/htmlDescriptor.css'); $scripts = file_get_contents(__DIR__.'/../../Resources/js/htmlDescriptor.js'); $output->writeln("<style>$styles</style><script>$scripts</script>"); $this->initialized = true; } $title = '-'; if (isset($context['request'])) { $request = $context['request']; $controller = "<span class='dumped-tag'>{$this->dumper->dump($request['controller'], true, ['maxDepth' => 0])}</span>"; $title = sprintf('<code>%s</code> <a href="%s">%s</a>', $request['method'], $uri = $request['uri'], $uri); $dedupIdentifier = $request['identifier']; } elseif (isset($context['cli'])) { $title = '<code>$ </code>'.$context['cli']['command_line']; $dedupIdentifier = $context['cli']['identifier']; } else { $dedupIdentifier = uniqid('', true); } $sourceDescription = ''; if (isset($context['source'])) { $source = $context['source']; $projectDir = $source['project_dir'] ?? null; $sourceDescription = sprintf('%s on line %d', $source['name'], $source['line']); if (isset($source['file_link'])) { $sourceDescription = sprintf('<a href="%s">%s</a>', $source['file_link'], $sourceDescription); } } $isoDate = $this->extractDate($context, 'c'); $tags = array_filter([ 'controller' => $controller ?? null, 'project dir' => $projectDir ?? null, ]); $output->writeln(<<<HTML <article data-dedup-id="$dedupIdentifier"> <header> <div class="row"> <h2 class="col">$title</h2> <time class="col text-small" title="$isoDate" datetime="$isoDate"> {$this->extractDate($context)} </time> </div> {$this->renderTags($tags)} </header> <section class="body"> <p class="text-small"> $sourceDescription </p> {$this->dumper->dump($data, true)} </section> </article> HTML ); } private function extractDate(array $context, string $format = 'r'): string { return date($format, (int) $context['timestamp']); } private function renderTags(array $tags): string { if (!$tags) { return ''; } $renderedTags = ''; foreach ($tags as $key => $value) { $renderedTags .= sprintf('<li><span class="badge">%s</span>%s</li>', $key, $value); } return <<<HTML <div class="row"> <ul class="tags"> $renderedTags </ul> </div> HTML; } } Command/Descriptor/DumpDescriptorInterface.php 0000644 00000001142 15173250124 0015534 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Command\Descriptor; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\VarDumper\Cloner\Data; /** * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ interface DumpDescriptorInterface { public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void; } Test/VarDumperTestTrait.php 0000644 00000005000 15173250124 0011740 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Test; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; /** * @author Nicolas Grekas <p@tchwork.com> */ trait VarDumperTestTrait { /** * @internal */ private $varDumperConfig = [ 'casters' => [], 'flags' => null, ]; protected function setUpVarDumper(array $casters, int $flags = null): void { $this->varDumperConfig['casters'] = $casters; $this->varDumperConfig['flags'] = $flags; } /** * @after */ protected function tearDownVarDumper(): void { $this->varDumperConfig['casters'] = []; $this->varDumperConfig['flags'] = null; } public function assertDumpEquals($expected, $data, int $filter = 0, string $message = '') { $this->assertSame($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); } public function assertDumpMatchesFormat($expected, $data, int $filter = 0, string $message = '') { $this->assertStringMatchesFormat($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); } protected function getDump($data, $key = null, int $filter = 0): ?string { if (null === $flags = $this->varDumperConfig['flags']) { $flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0; $flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0; $flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0; } $cloner = new VarCloner(); $cloner->addCasters($this->varDumperConfig['casters']); $cloner->setMaxItems(-1); $dumper = new CliDumper(null, null, $flags); $dumper->setColors(false); $data = $cloner->cloneVar($data, $filter)->withRefHandles(false); if (null !== $key && null === $data = $data->seek($key)) { return null; } return rtrim($dumper->dump($data, true)); } private function prepareExpectation($expected, int $filter): string { if (!\is_string($expected)) { $expected = $this->getDump($expected, null, $filter); } return rtrim($expected); } } Dumper/DataDumperInterface.php 0000644 00000000771 15173250124 0012365 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper; use Symfony\Component\VarDumper\Cloner\Data; /** * DataDumperInterface for dumping Data objects. * * @author Nicolas Grekas <p@tchwork.com> */ interface DataDumperInterface { public function dump(Data $data); } Dumper/CliDumper.php 0000644 00000053227 15173250124 0010406 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper; use Symfony\Component\VarDumper\Cloner\Cursor; use Symfony\Component\VarDumper\Cloner\Stub; /** * CliDumper dumps variables for command line output. * * @author Nicolas Grekas <p@tchwork.com> */ class CliDumper extends AbstractDumper { public static $defaultColors; public static $defaultOutput = 'php://stdout'; protected $colors; protected $maxStringWidth = 0; protected $styles = [ // See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 'default' => '0;38;5;208', 'num' => '1;38;5;38', 'const' => '1;38;5;208', 'str' => '1;38;5;113', 'note' => '38;5;38', 'ref' => '38;5;247', 'public' => '', 'protected' => '', 'private' => '', 'meta' => '38;5;170', 'key' => '38;5;113', 'index' => '38;5;38', ]; protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/'; protected static $controlCharsMap = [ "\t" => '\t', "\n" => '\n', "\v" => '\v', "\f" => '\f', "\r" => '\r', "\033" => '\e', ]; protected $collapseNextHash = false; protected $expandNextHash = false; private $displayOptions = [ 'fileLinkFormat' => null, ]; private $handlesHrefGracefully; /** * {@inheritdoc} */ public function __construct($output = null, string $charset = null, int $flags = 0) { parent::__construct($output, $charset, $flags); if ('\\' === \DIRECTORY_SEPARATOR && !$this->isWindowsTrueColor()) { // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI $this->setStyles([ 'default' => '31', 'num' => '1;34', 'const' => '1;31', 'str' => '1;32', 'note' => '34', 'ref' => '1;30', 'meta' => '35', 'key' => '32', 'index' => '34', ]); } $this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'; } /** * Enables/disables colored output. */ public function setColors(bool $colors) { $this->colors = $colors; } /** * Sets the maximum number of characters per line for dumped strings. */ public function setMaxStringWidth(int $maxStringWidth) { $this->maxStringWidth = $maxStringWidth; } /** * Configures styles. * * @param array $styles A map of style names to style definitions */ public function setStyles(array $styles) { $this->styles = $styles + $this->styles; } /** * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior */ public function setDisplayOptions(array $displayOptions) { $this->displayOptions = $displayOptions + $this->displayOptions; } /** * {@inheritdoc} */ public function dumpScalar(Cursor $cursor, string $type, $value) { $this->dumpKey($cursor); $this->collapseNextHash = $this->expandNextHash = false; $style = 'const'; $attr = $cursor->attr; switch ($type) { case 'default': $style = 'default'; break; case 'integer': $style = 'num'; if (isset($this->styles['integer'])) { $style = 'integer'; } break; case 'double': $style = 'num'; if (isset($this->styles['float'])) { $style = 'float'; } switch (true) { case \INF === $value: $value = 'INF'; break; case -\INF === $value: $value = '-INF'; break; case is_nan($value): $value = 'NAN'; break; default: $value = (string) $value; if (!str_contains($value, $this->decimalPoint)) { $value .= $this->decimalPoint.'0'; } break; } break; case 'NULL': $value = 'null'; break; case 'boolean': $value = $value ? 'true' : 'false'; break; default: $attr += ['value' => $this->utf8Encode($value)]; $value = $this->utf8Encode($type); break; } $this->line .= $this->style($style, $value, $attr); $this->endValue($cursor); } /** * {@inheritdoc} */ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) { $this->dumpKey($cursor); $this->collapseNextHash = $this->expandNextHash = false; $attr = $cursor->attr; if ($bin) { $str = $this->utf8Encode($str); } if ('' === $str) { $this->line .= '""'; if ($cut) { $this->line .= '…'.$cut; } $this->endValue($cursor); } else { $attr += [ 'length' => 0 <= $cut ? mb_strlen($str, 'UTF-8') + $cut : 0, 'binary' => $bin, ]; $str = $bin && false !== strpos($str, "\0") ? [$str] : explode("\n", $str); if (isset($str[1]) && !isset($str[2]) && !isset($str[1][0])) { unset($str[1]); $str[0] .= "\n"; } $m = \count($str) - 1; $i = $lineCut = 0; if (self::DUMP_STRING_LENGTH & $this->flags) { $this->line .= '('.$attr['length'].') '; } if ($bin) { $this->line .= 'b'; } if ($m) { $this->line .= '"""'; $this->dumpLine($cursor->depth); } else { $this->line .= '"'; } foreach ($str as $str) { if ($i < $m) { $str .= "\n"; } if (0 < $this->maxStringWidth && $this->maxStringWidth < $len = mb_strlen($str, 'UTF-8')) { $str = mb_substr($str, 0, $this->maxStringWidth, 'UTF-8'); $lineCut = $len - $this->maxStringWidth; } if ($m && 0 < $cursor->depth) { $this->line .= $this->indentPad; } if ('' !== $str) { $this->line .= $this->style('str', $str, $attr); } if ($i++ == $m) { if ($m) { if ('' !== $str) { $this->dumpLine($cursor->depth); if (0 < $cursor->depth) { $this->line .= $this->indentPad; } } $this->line .= '"""'; } else { $this->line .= '"'; } if ($cut < 0) { $this->line .= '…'; $lineCut = 0; } elseif ($cut) { $lineCut += $cut; } } if ($lineCut) { $this->line .= '…'.$lineCut; $lineCut = 0; } if ($i > $m) { $this->endValue($cursor); } else { $this->dumpLine($cursor->depth); } } } } /** * {@inheritdoc} */ public function enterHash(Cursor $cursor, int $type, $class, bool $hasChild) { if (null === $this->colors) { $this->colors = $this->supportsColors(); } $this->dumpKey($cursor); $this->expandNextHash = false; $attr = $cursor->attr; if ($this->collapseNextHash) { $cursor->skipChildren = true; $this->collapseNextHash = $hasChild = false; } $class = $this->utf8Encode($class); if (Cursor::HASH_OBJECT === $type) { $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr).(empty($attr['cut_hash']) ? ' {' : '') : '{'; } elseif (Cursor::HASH_RESOURCE === $type) { $prefix = $this->style('note', $class.' resource', $attr).($hasChild ? ' {' : ' '); } else { $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '['; } if (($cursor->softRefCount || 0 < $cursor->softRefHandle) && empty($attr['cut_hash'])) { $prefix .= $this->style('ref', (Cursor::HASH_RESOURCE === $type ? '@' : '#').(0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->softRefTo), ['count' => $cursor->softRefCount]); } elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) { $prefix .= $this->style('ref', '&'.$cursor->hardRefTo, ['count' => $cursor->hardRefCount]); } elseif (!$hasChild && Cursor::HASH_RESOURCE === $type) { $prefix = substr($prefix, 0, -1); } $this->line .= $prefix; if ($hasChild) { $this->dumpLine($cursor->depth); } } /** * {@inheritdoc} */ public function leaveHash(Cursor $cursor, int $type, $class, bool $hasChild, int $cut) { if (empty($cursor->attr['cut_hash'])) { $this->dumpEllipsis($cursor, $hasChild, $cut); $this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : '')); } $this->endValue($cursor); } /** * Dumps an ellipsis for cut children. * * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by */ protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) { if ($cut) { $this->line .= ' …'; if (0 < $cut) { $this->line .= $cut; } if ($hasChild) { $this->dumpLine($cursor->depth + 1); } } } /** * Dumps a key in a hash structure. */ protected function dumpKey(Cursor $cursor) { if (null !== $key = $cursor->hashKey) { if ($cursor->hashKeyIsBinary) { $key = $this->utf8Encode($key); } $attr = ['binary' => $cursor->hashKeyIsBinary]; $bin = $cursor->hashKeyIsBinary ? 'b' : ''; $style = 'key'; switch ($cursor->hashType) { default: case Cursor::HASH_INDEXED: if (self::DUMP_LIGHT_ARRAY & $this->flags) { break; } $style = 'index'; // no break case Cursor::HASH_ASSOC: if (\is_int($key)) { $this->line .= $this->style($style, $key).' => '; } else { $this->line .= $bin.'"'.$this->style($style, $key).'" => '; } break; case Cursor::HASH_RESOURCE: $key = "\0~\0".$key; // no break case Cursor::HASH_OBJECT: if (!isset($key[0]) || "\0" !== $key[0]) { $this->line .= '+'.$bin.$this->style('public', $key).': '; } elseif (0 < strpos($key, "\0", 1)) { $key = explode("\0", substr($key, 1), 2); switch ($key[0][0]) { case '+': // User inserted keys $attr['dynamic'] = true; $this->line .= '+'.$bin.'"'.$this->style('public', $key[1], $attr).'": '; break 2; case '~': $style = 'meta'; if (isset($key[0][1])) { parse_str(substr($key[0], 1), $attr); $attr += ['binary' => $cursor->hashKeyIsBinary]; } break; case '*': $style = 'protected'; $bin = '#'.$bin; break; default: $attr['class'] = $key[0]; $style = 'private'; $bin = '-'.$bin; break; } if (isset($attr['collapse'])) { if ($attr['collapse']) { $this->collapseNextHash = true; } else { $this->expandNextHash = true; } } $this->line .= $bin.$this->style($style, $key[1], $attr).($attr['separator'] ?? ': '); } else { // This case should not happen $this->line .= '-'.$bin.'"'.$this->style('private', $key, ['class' => '']).'": '; } break; } if ($cursor->hardRefTo) { $this->line .= $this->style('ref', '&'.($cursor->hardRefCount ? $cursor->hardRefTo : ''), ['count' => $cursor->hardRefCount]).' '; } } } /** * Decorates a value with some style. * * @param string $style The type of style being applied * @param string $value The value being styled * @param array $attr Optional context information * * @return string */ protected function style(string $style, string $value, array $attr = []) { if (null === $this->colors) { $this->colors = $this->supportsColors(); } if (null === $this->handlesHrefGracefully) { $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR') && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100) && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); } if (isset($attr['ellipsis'], $attr['ellipsis-type'])) { $prefix = substr($value, 0, -$attr['ellipsis']); if ('cli' === \PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === \DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && str_starts_with($prefix, $_SERVER[$pwd])) { $prefix = '.'.substr($prefix, \strlen($_SERVER[$pwd])); } if (!empty($attr['ellipsis-tail'])) { $prefix .= substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']); $value = substr($value, -$attr['ellipsis'] + $attr['ellipsis-tail']); } else { $value = substr($value, -$attr['ellipsis']); } $value = $this->style('default', $prefix).$this->style($style, $value); goto href; } $map = static::$controlCharsMap; $startCchr = $this->colors ? "\033[m\033[{$this->styles['default']}m" : ''; $endCchr = $this->colors ? "\033[m\033[{$this->styles[$style]}m" : ''; $value = preg_replace_callback(static::$controlCharsRx, function ($c) use ($map, $startCchr, $endCchr) { $s = $startCchr; $c = $c[$i = 0]; do { $s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i])); } while (isset($c[++$i])); return $s.$endCchr; }, $value, -1, $cchrCount); if ($this->colors) { if ($cchrCount && "\033" === $value[0]) { $value = substr($value, \strlen($startCchr)); } else { $value = "\033[{$this->styles[$style]}m".$value; } if ($cchrCount && str_ends_with($value, $endCchr)) { $value = substr($value, 0, -\strlen($endCchr)); } else { $value .= "\033[{$this->styles['default']}m"; } } href: if ($this->colors && $this->handlesHrefGracefully) { if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) { if ('note' === $style) { $value .= "\033]8;;{$href}\033\\^\033]8;;\033\\"; } else { $attr['href'] = $href; } } if (isset($attr['href'])) { $value = "\033]8;;{$attr['href']}\033\\{$value}\033]8;;\033\\"; } } elseif ($attr['if_links'] ?? false) { return ''; } return $value; } /** * @return bool */ protected function supportsColors() { if ($this->outputStream !== static::$defaultOutput) { return $this->hasColorSupport($this->outputStream); } if (null !== static::$defaultColors) { return static::$defaultColors; } if (isset($_SERVER['argv'][1])) { $colors = $_SERVER['argv']; $i = \count($colors); while (--$i > 0) { if (isset($colors[$i][5])) { switch ($colors[$i]) { case '--ansi': case '--color': case '--color=yes': case '--color=force': case '--color=always': case '--colors=always': return static::$defaultColors = true; case '--no-ansi': case '--color=no': case '--color=none': case '--color=never': case '--colors=never': return static::$defaultColors = false; } } } } $h = stream_get_meta_data($this->outputStream) + ['wrapper_type' => null]; $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'w') : $this->outputStream; return static::$defaultColors = $this->hasColorSupport($h); } /** * {@inheritdoc} */ protected function dumpLine(int $depth, bool $endOfValue = false) { if ($this->colors) { $this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); } parent::dumpLine($depth); } protected function endValue(Cursor $cursor) { if (-1 === $cursor->hashType) { return; } if (Stub::ARRAY_INDEXED === $cursor->hashType || Stub::ARRAY_ASSOC === $cursor->hashType) { if (self::DUMP_TRAILING_COMMA & $this->flags && 0 < $cursor->depth) { $this->line .= ','; } elseif (self::DUMP_COMMA_SEPARATOR & $this->flags && 1 < $cursor->hashLength - $cursor->hashIndex) { $this->line .= ','; } } $this->dumpLine($cursor->depth, true); } /** * Returns true if the stream supports colorization. * * Reference: Composer\XdebugHandler\Process::supportsColor * https://github.com/composer/xdebug-handler * * @param mixed $stream A CLI output stream */ private function hasColorSupport($stream): bool { if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) { return false; } // Follow https://no-color.org/ if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { return false; } if ('Hyper' === getenv('TERM_PROGRAM')) { return true; } if (\DIRECTORY_SEPARATOR === '\\') { return (\function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support($stream)) || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'); } return stream_isatty($stream); } /** * Returns true if the Windows terminal supports true color. * * Note that this does not check an output stream, but relies on environment * variables from known implementations, or a PHP and Windows version that * supports true color. */ private function isWindowsTrueColor(): bool { $result = 183 <= getenv('ANSICON_VER') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM') || 'Hyper' === getenv('TERM_PROGRAM'); if (!$result) { $version = sprintf( '%s.%s.%s', PHP_WINDOWS_VERSION_MAJOR, PHP_WINDOWS_VERSION_MINOR, PHP_WINDOWS_VERSION_BUILD ); $result = $version >= '10.0.15063'; } return $result; } private function getSourceLink(string $file, int $line) { if ($fmt = $this->displayOptions['fileLinkFormat']) { return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file.'#L'.$line); } return false; } } Dumper/ContextProvider/SourceContextProvider.php 0000644 00000011555 15173250124 0016177 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper\ContextProvider; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\VarDumper; use Twig\Template; /** * Tries to provide context from sources (class name, file, line, code excerpt, ...). * * @author Nicolas Grekas <p@tchwork.com> * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ final class SourceContextProvider implements ContextProviderInterface { private $limit; private $charset; private $projectDir; private $fileLinkFormatter; public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 9) { $this->charset = $charset; $this->projectDir = $projectDir; $this->fileLinkFormatter = $fileLinkFormatter; $this->limit = $limit; } public function getContext(): ?array { $trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, $this->limit); $file = $trace[1]['file']; $line = $trace[1]['line']; $name = '-' === $file || 'Standard input code' === $file ? 'Standard input code' : false; $fileExcerpt = false; for ($i = 2; $i < $this->limit; ++$i) { if (isset($trace[$i]['class'], $trace[$i]['function']) && 'dump' === $trace[$i]['function'] && VarDumper::class === $trace[$i]['class'] ) { $file = $trace[$i]['file'] ?? $file; $line = $trace[$i]['line'] ?? $line; while (++$i < $this->limit) { if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && !str_starts_with($trace[$i]['function'], 'call_user_func')) { $file = $trace[$i]['file']; $line = $trace[$i]['line']; break; } elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof Template) { $template = $trace[$i]['object']; $name = $template->getTemplateName(); $src = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : false); $info = $template->getDebugInfo(); if (isset($info[$trace[$i - 1]['line']])) { $line = $info[$trace[$i - 1]['line']]; $file = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null; if ($src) { $src = explode("\n", $src); $fileExcerpt = []; for ($i = max($line - 3, 1), $max = min($line + 3, \count($src)); $i <= $max; ++$i) { $fileExcerpt[] = '<li'.($i === $line ? ' class="selected"' : '').'><code>'.$this->htmlEncode($src[$i - 1]).'</code></li>'; } $fileExcerpt = '<ol start="'.max($line - 3, 1).'">'.implode("\n", $fileExcerpt).'</ol>'; } } break; } } break; } } if (false === $name) { $name = str_replace('\\', '/', $file); $name = substr($name, strrpos($name, '/') + 1); } $context = ['name' => $name, 'file' => $file, 'line' => $line]; $context['file_excerpt'] = $fileExcerpt; if (null !== $this->projectDir) { $context['project_dir'] = $this->projectDir; if (str_starts_with($file, $this->projectDir)) { $context['file_relative'] = ltrim(substr($file, \strlen($this->projectDir)), \DIRECTORY_SEPARATOR); } } if ($this->fileLinkFormatter && $fileLink = $this->fileLinkFormatter->format($context['file'], $context['line'])) { $context['file_link'] = $fileLink; } return $context; } private function htmlEncode(string $s): string { $html = ''; $dumper = new HtmlDumper(function ($line) use (&$html) { $html .= $line; }, $this->charset); $dumper->setDumpHeader(''); $dumper->setDumpBoundaries('', ''); $cloner = new VarCloner(); $dumper->dump($cloner->cloneVar($s)); return substr(strip_tags($html), 1, -1); } } Dumper/ContextProvider/RequestContextProvider.php 0000644 00000002701 15173250124 0016360 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper\ContextProvider; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\VarCloner; /** * Tries to provide context from a request. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ final class RequestContextProvider implements ContextProviderInterface { private $requestStack; private $cloner; public function __construct(RequestStack $requestStack) { $this->requestStack = $requestStack; $this->cloner = new VarCloner(); $this->cloner->setMaxItems(0); $this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); } public function getContext(): ?array { if (null === $request = $this->requestStack->getCurrentRequest()) { return null; } $controller = $request->attributes->get('_controller'); return [ 'uri' => $request->getUri(), 'method' => $request->getMethod(), 'controller' => $controller ? $this->cloner->cloneVar($controller) : $controller, 'identifier' => spl_object_hash($request), ]; } } Dumper/ContextProvider/ContextProviderInterface.php 0000644 00000001031 15173250124 0016623 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper\ContextProvider; /** * Interface to provide contextual data about dump data clones sent to a server. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ interface ContextProviderInterface { public function getContext(): ?array; } Dumper/ContextProvider/CliContextProvider.php 0000644 00000001446 15173250124 0015444 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper\ContextProvider; /** * Tries to provide context on CLI. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ final class CliContextProvider implements ContextProviderInterface { public function getContext(): ?array { if ('cli' !== \PHP_SAPI) { return null; } return [ 'command_line' => $commandLine = implode(' ', $_SERVER['argv'] ?? []), 'identifier' => hash('crc32b', $commandLine.$_SERVER['REQUEST_TIME_FLOAT']), ]; } } Dumper/ContextualizedDumper.php 0000644 00000002226 15173250124 0012672 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; /** * @author Kévin Thérage <therage.kevin@gmail.com> */ class ContextualizedDumper implements DataDumperInterface { private $wrappedDumper; private $contextProviders; /** * @param ContextProviderInterface[] $contextProviders */ public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders) { $this->wrappedDumper = $wrappedDumper; $this->contextProviders = $contextProviders; } public function dump(Data $data) { $context = []; foreach ($this->contextProviders as $contextProvider) { $context[\get_class($contextProvider)] = $contextProvider->getContext(); } $this->wrappedDumper->dump($data->withContext($context)); } } Dumper/AbstractDumper.php 0000644 00000014034 15173250124 0011433 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\DumperInterface; /** * Abstract mechanism for dumping a Data object. * * @author Nicolas Grekas <p@tchwork.com> */ abstract class AbstractDumper implements DataDumperInterface, DumperInterface { public const DUMP_LIGHT_ARRAY = 1; public const DUMP_STRING_LENGTH = 2; public const DUMP_COMMA_SEPARATOR = 4; public const DUMP_TRAILING_COMMA = 8; public static $defaultOutput = 'php://output'; protected $line = ''; protected $lineDumper; protected $outputStream; protected $decimalPoint; // This is locale dependent protected $indentPad = ' '; protected $flags; private $charset = ''; /** * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput * @param string|null $charset The default character encoding to use for non-UTF8 strings * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation */ public function __construct($output = null, string $charset = null, int $flags = 0) { $this->flags = $flags; $this->setCharset($charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'); $this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point']; $this->setOutput($output ?: static::$defaultOutput); if (!$output && \is_string(static::$defaultOutput)) { static::$defaultOutput = $this->outputStream; } } /** * Sets the output destination of the dumps. * * @param callable|resource|string $output A line dumper callable, an opened stream or an output path * * @return callable|resource|string The previous output destination */ public function setOutput($output) { $prev = $this->outputStream ?? $this->lineDumper; if (\is_callable($output)) { $this->outputStream = null; $this->lineDumper = $output; } else { if (\is_string($output)) { $output = fopen($output, 'w'); } $this->outputStream = $output; $this->lineDumper = [$this, 'echoLine']; } return $prev; } /** * Sets the default character encoding to use for non-UTF8 strings. * * @return string The previous charset */ public function setCharset(string $charset) { $prev = $this->charset; $charset = strtoupper($charset); $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; $this->charset = $charset; return $prev; } /** * Sets the indentation pad string. * * @param string $pad A string that will be prepended to dumped lines, repeated by nesting level * * @return string The previous indent pad */ public function setIndentPad(string $pad) { $prev = $this->indentPad; $this->indentPad = $pad; return $prev; } /** * Dumps a Data object. * * @param callable|resource|string|true|null $output A line dumper callable, an opened stream, an output path or true to return the dump * * @return string|null The dump as string when $output is true */ public function dump(Data $data, $output = null) { $this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point']; if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(\LC_NUMERIC, 0) : null) { setlocale(\LC_NUMERIC, 'C'); } if ($returnDump = true === $output) { $output = fopen('php://memory', 'r+'); } if ($output) { $prevOutput = $this->setOutput($output); } try { $data->dump($this); $this->dumpLine(-1); if ($returnDump) { $result = stream_get_contents($output, -1, 0); fclose($output); return $result; } } finally { if ($output) { $this->setOutput($prevOutput); } if ($locale) { setlocale(\LC_NUMERIC, $locale); } } return null; } /** * Dumps the current line. * * @param int $depth The recursive depth in the dumped structure for the line being dumped, * or -1 to signal the end-of-dump to the line dumper callable */ protected function dumpLine(int $depth) { ($this->lineDumper)($this->line, $depth, $this->indentPad); $this->line = ''; } /** * Generic line dumper callback. */ protected function echoLine(string $line, int $depth, string $indentPad) { if (-1 !== $depth) { fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n"); } } /** * Converts a non-UTF-8 string to UTF-8. * * @return string|null */ protected function utf8Encode(?string $s) { if (null === $s || preg_match('//u', $s)) { return $s; } if (!\function_exists('iconv')) { throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); } if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { return $c; } if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { return $c; } return iconv('CP850', 'UTF-8', $s); } } Dumper/HtmlDumper.php 0000644 00000102337 15173250124 0010600 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper; use Symfony\Component\VarDumper\Cloner\Cursor; use Symfony\Component\VarDumper\Cloner\Data; /** * HtmlDumper dumps variables as HTML. * * @author Nicolas Grekas <p@tchwork.com> */ class HtmlDumper extends CliDumper { public static $defaultOutput = 'php://output'; protected static $themes = [ 'dark' => [ 'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', 'str' => 'font-weight:bold; color:#56DB3A', 'note' => 'color:#1299DA', 'ref' => 'color:#A0A0A0', 'public' => 'color:#FFFFFF', 'protected' => 'color:#FFFFFF', 'private' => 'color:#FFFFFF', 'meta' => 'color:#B729D9', 'key' => 'color:#56DB3A', 'index' => 'color:#1299DA', 'ellipsis' => 'color:#FF8400', 'ns' => 'user-select:none;', ], 'light' => [ 'default' => 'background:none; color:#CC7832; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', 'str' => 'font-weight:bold; color:#629755;', 'note' => 'color:#6897BB', 'ref' => 'color:#6E6E6E', 'public' => 'color:#262626', 'protected' => 'color:#262626', 'private' => 'color:#262626', 'meta' => 'color:#B729D9', 'key' => 'color:#789339', 'index' => 'color:#1299DA', 'ellipsis' => 'color:#CC7832', 'ns' => 'user-select:none;', ], ]; protected $dumpHeader; protected $dumpPrefix = '<pre class=sf-dump id=%s data-indent-pad="%s">'; protected $dumpSuffix = '</pre><script>Sfdump(%s)</script>'; protected $dumpId = 'sf-dump'; protected $colors = true; protected $headerIsDumped = false; protected $lastDepth = -1; protected $styles; private $displayOptions = [ 'maxDepth' => 1, 'maxStringLength' => 160, 'fileLinkFormat' => null, ]; private $extraDisplayOptions = []; /** * {@inheritdoc} */ public function __construct($output = null, string $charset = null, int $flags = 0) { AbstractDumper::__construct($output, $charset, $flags); $this->dumpId = 'sf-dump-'.mt_rand(); $this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); $this->styles = static::$themes['dark'] ?? self::$themes['dark']; } /** * {@inheritdoc} */ public function setStyles(array $styles) { $this->headerIsDumped = false; $this->styles = $styles + $this->styles; } public function setTheme(string $themeName) { if (!isset(static::$themes[$themeName])) { throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); } $this->setStyles(static::$themes[$themeName]); } /** * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior */ public function setDisplayOptions(array $displayOptions) { $this->headerIsDumped = false; $this->displayOptions = $displayOptions + $this->displayOptions; } /** * Sets an HTML header that will be dumped once in the output stream. */ public function setDumpHeader(?string $header) { $this->dumpHeader = $header; } /** * Sets an HTML prefix and suffix that will encapse every single dump. */ public function setDumpBoundaries(string $prefix, string $suffix) { $this->dumpPrefix = $prefix; $this->dumpSuffix = $suffix; } /** * {@inheritdoc} */ public function dump(Data $data, $output = null, array $extraDisplayOptions = []) { $this->extraDisplayOptions = $extraDisplayOptions; $result = parent::dump($data, $output); $this->dumpId = 'sf-dump-'.mt_rand(); return $result; } /** * Dumps the HTML header. */ protected function getDumpHeader() { $this->headerIsDumped = $this->outputStream ?? $this->lineDumper; if (null !== $this->dumpHeader) { return $this->dumpHeader; } $line = str_replace('{$options}', json_encode($this->displayOptions, \JSON_FORCE_OBJECT), <<<'EOHTML' <script> Sfdump = window.Sfdump || (function (doc) { var refStyle = doc.createElement('style'), rxEsc = /([.*+?^${}()|\[\]\/\\])/g, idRx = /\bsf-dump-\d+-ref[012]\w+\b/, keyHint = 0 <= navigator.platform.toUpperCase().indexOf('MAC') ? 'Cmd' : 'Ctrl', addEventListener = function (e, n, cb) { e.addEventListener(n, cb, false); }; refStyle.innerHTML = 'pre.sf-dump .sf-dump-compact, .sf-dump-str-collapse .sf-dump-str-collapse, .sf-dump-str-expand .sf-dump-str-expand { display: none; }'; doc.head.appendChild(refStyle); refStyle = doc.createElement('style'); doc.head.appendChild(refStyle); if (!doc.addEventListener) { addEventListener = function (element, eventName, callback) { element.attachEvent('on' + eventName, function (e) { e.preventDefault = function () {e.returnValue = false;}; e.target = e.srcElement; callback(e); }); }; } function toggle(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className, arrow, newClass; if (/\bsf-dump-compact\b/.test(oldClass)) { arrow = '▼'; newClass = 'sf-dump-expanded'; } else if (/\bsf-dump-expanded\b/.test(oldClass)) { arrow = '▶'; newClass = 'sf-dump-compact'; } else { return false; } if (doc.createEvent && s.dispatchEvent) { var event = doc.createEvent('Event'); event.initEvent('sf-dump-expanded' === newClass ? 'sfbeforedumpexpand' : 'sfbeforedumpcollapse', true, false); s.dispatchEvent(event); } a.lastChild.innerHTML = arrow; s.className = s.className.replace(/\bsf-dump-(compact|expanded)\b/, newClass); if (recursive) { try { a = s.querySelectorAll('.'+oldClass); for (s = 0; s < a.length; ++s) { if (-1 == a[s].className.indexOf(newClass)) { a[s].className = newClass; a[s].previousSibling.lastChild.innerHTML = arrow; } } } catch (e) { } } return true; }; function collapse(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className; if (/\bsf-dump-expanded\b/.test(oldClass)) { toggle(a, recursive); return true; } return false; }; function expand(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className; if (/\bsf-dump-compact\b/.test(oldClass)) { toggle(a, recursive); return true; } return false; }; function collapseAll(root) { var a = root.querySelector('a.sf-dump-toggle'); if (a) { collapse(a, true); expand(a); return true; } return false; } function reveal(node) { var previous, parents = []; while ((node = node.parentNode || {}) && (previous = node.previousSibling) && 'A' === previous.tagName) { parents.push(previous); } if (0 !== parents.length) { parents.forEach(function (parent) { expand(parent); }); return true; } return false; } function highlight(root, activeNode, nodes) { resetHighlightedNodes(root); Array.from(nodes||[]).forEach(function (node) { if (!/\bsf-dump-highlight\b/.test(node.className)) { node.className = node.className + ' sf-dump-highlight'; } }); if (!/\bsf-dump-highlight-active\b/.test(activeNode.className)) { activeNode.className = activeNode.className + ' sf-dump-highlight-active'; } } function resetHighlightedNodes(root) { Array.from(root.querySelectorAll('.sf-dump-str, .sf-dump-key, .sf-dump-public, .sf-dump-protected, .sf-dump-private')).forEach(function (strNode) { strNode.className = strNode.className.replace(/\bsf-dump-highlight\b/, ''); strNode.className = strNode.className.replace(/\bsf-dump-highlight-active\b/, ''); }); } return function (root, x) { root = doc.getElementById(root); var indentRx = new RegExp('^('+(root.getAttribute('data-indent-pad') || ' ').replace(rxEsc, '\\$1')+')+', 'm'), options = {$options}, elt = root.getElementsByTagName('A'), len = elt.length, i = 0, s, h, t = []; while (i < len) t.push(elt[i++]); for (i in x) { options[i] = x[i]; } function a(e, f) { addEventListener(root, e, function (e, n) { if ('A' == e.target.tagName) { f(e.target, e); } else if ('A' == e.target.parentNode.tagName) { f(e.target.parentNode, e); } else { n = /\bsf-dump-ellipsis\b/.test(e.target.className) ? e.target.parentNode : e.target; if ((n = n.nextElementSibling) && 'A' == n.tagName) { if (!/\bsf-dump-toggle\b/.test(n.className)) { n = n.nextElementSibling || n; } f(n, e, true); } } }); }; function isCtrlKey(e) { return e.ctrlKey || e.metaKey; } function xpathString(str) { var parts = str.match(/[^'"]+|['"]/g).map(function (part) { if ("'" == part) { return '"\'"'; } if ('"' == part) { return "'\"'"; } return "'" + part + "'"; }); return "concat(" + parts.join(",") + ", '')"; } function xpathHasClass(className) { return "contains(concat(' ', normalize-space(@class), ' '), ' " + className +" ')"; } addEventListener(root, 'mouseover', function (e) { if ('' != refStyle.innerHTML) { refStyle.innerHTML = ''; } }); a('mouseover', function (a, e, c) { if (c) { e.target.style.cursor = "pointer"; } else if (a = idRx.exec(a.className)) { try { refStyle.innerHTML = 'pre.sf-dump .'+a[0]+'{background-color: #B729D9; color: #FFF !important; border-radius: 2px}'; } catch (e) { } } }); a('click', function (a, e, c) { if (/\bsf-dump-toggle\b/.test(a.className)) { e.preventDefault(); if (!toggle(a, isCtrlKey(e))) { var r = doc.getElementById(a.getAttribute('href').slice(1)), s = r.previousSibling, f = r.parentNode, t = a.parentNode; t.replaceChild(r, a); f.replaceChild(a, s); t.insertBefore(s, r); f = f.firstChild.nodeValue.match(indentRx); t = t.firstChild.nodeValue.match(indentRx); if (f && t && f[0] !== t[0]) { r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\$1'), 'mg'), t[0]); } if (/\bsf-dump-compact\b/.test(r.className)) { toggle(s, isCtrlKey(e)); } } if (c) { } else if (doc.getSelection) { try { doc.getSelection().removeAllRanges(); } catch (e) { doc.getSelection().empty(); } } else { doc.selection.empty(); } } else if (/\bsf-dump-str-toggle\b/.test(a.className)) { e.preventDefault(); e = a.parentNode.parentNode; e.className = e.className.replace(/\bsf-dump-str-(expand|collapse)\b/, a.parentNode.className); } }); elt = root.getElementsByTagName('SAMP'); len = elt.length; i = 0; while (i < len) t.push(elt[i++]); len = t.length; for (i = 0; i < len; ++i) { elt = t[i]; if ('SAMP' == elt.tagName) { a = elt.previousSibling || {}; if ('A' != a.tagName) { a = doc.createElement('A'); a.className = 'sf-dump-ref'; elt.parentNode.insertBefore(a, elt); } else { a.innerHTML += ' '; } a.title = (a.title ? a.title+'\n[' : '[')+keyHint+'+click] Expand all children'; a.innerHTML += elt.className == 'sf-dump-compact' ? '<span>▶</span>' : '<span>▼</span>'; a.className += ' sf-dump-toggle'; x = 1; if ('sf-dump' != elt.parentNode.className) { x += elt.parentNode.getAttribute('data-depth')/1; } } else if (/\bsf-dump-ref\b/.test(elt.className) && (a = elt.getAttribute('href'))) { a = a.slice(1); elt.className += ' '+a; if (/[\[{]$/.test(elt.previousSibling.nodeValue)) { a = a != elt.nextSibling.id && doc.getElementById(a); try { s = a.nextSibling; elt.appendChild(a); s.parentNode.insertBefore(a, s); if (/^[@#]/.test(elt.innerHTML)) { elt.innerHTML += ' <span>▶</span>'; } else { elt.innerHTML = '<span>▶</span>'; elt.className = 'sf-dump-ref'; } elt.className += ' sf-dump-toggle'; } catch (e) { if ('&' == elt.innerHTML.charAt(0)) { elt.innerHTML = '…'; elt.className = 'sf-dump-ref'; } } } } } if (doc.evaluate && Array.from && root.children.length > 1) { root.setAttribute('tabindex', 0); SearchState = function () { this.nodes = []; this.idx = 0; }; SearchState.prototype = { next: function () { if (this.isEmpty()) { return this.current(); } this.idx = this.idx < (this.nodes.length - 1) ? this.idx + 1 : 0; return this.current(); }, previous: function () { if (this.isEmpty()) { return this.current(); } this.idx = this.idx > 0 ? this.idx - 1 : (this.nodes.length - 1); return this.current(); }, isEmpty: function () { return 0 === this.count(); }, current: function () { if (this.isEmpty()) { return null; } return this.nodes[this.idx]; }, reset: function () { this.nodes = []; this.idx = 0; }, count: function () { return this.nodes.length; }, }; function showCurrent(state) { var currentNode = state.current(), currentRect, searchRect; if (currentNode) { reveal(currentNode); highlight(root, currentNode, state.nodes); if ('scrollIntoView' in currentNode) { currentNode.scrollIntoView(true); currentRect = currentNode.getBoundingClientRect(); searchRect = search.getBoundingClientRect(); if (currentRect.top < (searchRect.top + searchRect.height)) { window.scrollBy(0, -(searchRect.top + searchRect.height + 5)); } } } counter.textContent = (state.isEmpty() ? 0 : state.idx + 1) + ' of ' + state.count(); } var search = doc.createElement('div'); search.className = 'sf-dump-search-wrapper sf-dump-search-hidden'; search.innerHTML = ' <input type="text" class="sf-dump-search-input"> <span class="sf-dump-search-count">0 of 0<\/span> <button type="button" class="sf-dump-search-input-previous" tabindex="-1"> <svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 1331l-166 165q-19 19-45 19t-45-19L896 965l-531 531q-19 19-45 19t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19 45-19t45 19l742 741q19 19 19 45.5t-19 45.5z"\/><\/svg> <\/button> <button type="button" class="sf-dump-search-input-next" tabindex="-1"> <svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 808l-742 741q-19 19-45 19t-45-19L109 808q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"\/><\/svg> <\/button> '; root.insertBefore(search, root.firstChild); var state = new SearchState(); var searchInput = search.querySelector('.sf-dump-search-input'); var counter = search.querySelector('.sf-dump-search-count'); var searchInputTimer = 0; var previousSearchQuery = ''; addEventListener(searchInput, 'keyup', function (e) { var searchQuery = e.target.value; /* Don't perform anything if the pressed key didn't change the query */ if (searchQuery === previousSearchQuery) { return; } previousSearchQuery = searchQuery; clearTimeout(searchInputTimer); searchInputTimer = setTimeout(function () { state.reset(); collapseAll(root); resetHighlightedNodes(root); if ('' === searchQuery) { counter.textContent = '0 of 0'; return; } var classMatches = [ "sf-dump-str", "sf-dump-key", "sf-dump-public", "sf-dump-protected", "sf-dump-private", ].map(xpathHasClass).join(' or '); var xpathResult = doc.evaluate('.//span[' + classMatches + '][contains(translate(child::text(), ' + xpathString(searchQuery.toUpperCase()) + ', ' + xpathString(searchQuery.toLowerCase()) + '), ' + xpathString(searchQuery.toLowerCase()) + ')]', root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); while (node = xpathResult.iterateNext()) state.nodes.push(node); showCurrent(state); }, 400); }); Array.from(search.querySelectorAll('.sf-dump-search-input-next, .sf-dump-search-input-previous')).forEach(function (btn) { addEventListener(btn, 'click', function (e) { e.preventDefault(); -1 !== e.target.className.indexOf('next') ? state.next() : state.previous(); searchInput.focus(); collapseAll(root); showCurrent(state); }) }); addEventListener(root, 'keydown', function (e) { var isSearchActive = !/\bsf-dump-search-hidden\b/.test(search.className); if ((114 === e.keyCode && !isSearchActive) || (isCtrlKey(e) && 70 === e.keyCode)) { /* F3 or CMD/CTRL + F */ if (70 === e.keyCode && document.activeElement === searchInput) { /* * If CMD/CTRL + F is hit while having focus on search input, * the user probably meant to trigger browser search instead. * Let the browser execute its behavior: */ return; } e.preventDefault(); search.className = search.className.replace(/\bsf-dump-search-hidden\b/, ''); searchInput.focus(); } else if (isSearchActive) { if (27 === e.keyCode) { /* ESC key */ search.className += ' sf-dump-search-hidden'; e.preventDefault(); resetHighlightedNodes(root); searchInput.value = ''; } else if ( (isCtrlKey(e) && 71 === e.keyCode) /* CMD/CTRL + G */ || 13 === e.keyCode /* Enter */ || 114 === e.keyCode /* F3 */ ) { e.preventDefault(); e.shiftKey ? state.previous() : state.next(); collapseAll(root); showCurrent(state); } } }); } if (0 >= options.maxStringLength) { return; } try { elt = root.querySelectorAll('.sf-dump-str'); len = elt.length; i = 0; t = []; while (i < len) t.push(elt[i++]); len = t.length; for (i = 0; i < len; ++i) { elt = t[i]; s = elt.innerText || elt.textContent; x = s.length - options.maxStringLength; if (0 < x) { h = elt.innerHTML; elt[elt.innerText ? 'innerText' : 'textContent'] = s.substring(0, options.maxStringLength); elt.className += ' sf-dump-str-collapse'; elt.innerHTML = '<span class=sf-dump-str-collapse>'+h+'<a class="sf-dump-ref sf-dump-str-toggle" title="Collapse"> ◀</a></span>'+ '<span class=sf-dump-str-expand>'+elt.innerHTML+'<a class="sf-dump-ref sf-dump-str-toggle" title="'+x+' remaining characters"> ▶</a></span>'; } } } catch (e) { } }; })(document); </script><style> pre.sf-dump { display: block; white-space: pre; padding: 5px; overflow: initial !important; } pre.sf-dump:after { content: ""; visibility: hidden; display: block; height: 0; clear: both; } pre.sf-dump span { display: inline; } pre.sf-dump a { text-decoration: none; cursor: pointer; border: 0; outline: none; color: inherit; } pre.sf-dump img { max-width: 50em; max-height: 50em; margin: .5em 0 0 0; padding: 0; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAHUlEQVQY02O8zAABilCaiQEN0EeA8QuUcX9g3QEAAjcC5piyhyEAAAAASUVORK5CYII=) #D3D3D3; } pre.sf-dump .sf-dump-ellipsis { display: inline-block; overflow: visible; text-overflow: ellipsis; max-width: 5em; white-space: nowrap; overflow: hidden; vertical-align: top; } pre.sf-dump .sf-dump-ellipsis+.sf-dump-ellipsis { max-width: none; } pre.sf-dump code { display:inline; padding:0; background:none; } .sf-dump-public.sf-dump-highlight, .sf-dump-protected.sf-dump-highlight, .sf-dump-private.sf-dump-highlight, .sf-dump-str.sf-dump-highlight, .sf-dump-key.sf-dump-highlight { background: rgba(111, 172, 204, 0.3); border: 1px solid #7DA0B1; border-radius: 3px; } .sf-dump-public.sf-dump-highlight-active, .sf-dump-protected.sf-dump-highlight-active, .sf-dump-private.sf-dump-highlight-active, .sf-dump-str.sf-dump-highlight-active, .sf-dump-key.sf-dump-highlight-active { background: rgba(253, 175, 0, 0.4); border: 1px solid #ffa500; border-radius: 3px; } pre.sf-dump .sf-dump-search-hidden { display: none !important; } pre.sf-dump .sf-dump-search-wrapper { font-size: 0; white-space: nowrap; margin-bottom: 5px; display: flex; position: -webkit-sticky; position: sticky; top: 5px; } pre.sf-dump .sf-dump-search-wrapper > * { vertical-align: top; box-sizing: border-box; height: 21px; font-weight: normal; border-radius: 0; background: #FFF; color: #757575; border: 1px solid #BBB; } pre.sf-dump .sf-dump-search-wrapper > input.sf-dump-search-input { padding: 3px; height: 21px; font-size: 12px; border-right: none; border-top-left-radius: 3px; border-bottom-left-radius: 3px; color: #000; min-width: 15px; width: 100%; } pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next, pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous { background: #F2F2F2; outline: none; border-left: none; font-size: 0; line-height: 0; } pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next { border-top-right-radius: 3px; border-bottom-right-radius: 3px; } pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next > svg, pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous > svg { pointer-events: none; width: 12px; height: 12px; } pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-count { display: inline-block; padding: 0 5px; margin: 0; border-left: none; line-height: 21px; font-size: 12px; } EOHTML ); foreach ($this->styles as $class => $style) { $line .= 'pre.sf-dump'.('default' === $class ? ', pre.sf-dump' : '').' .sf-dump-'.$class.'{'.$style.'}'; } $line .= 'pre.sf-dump .sf-dump-ellipsis-note{'.$this->styles['note'].'}'; return $this->dumpHeader = preg_replace('/\s+/', ' ', $line).'</style>'.$this->dumpHeader; } /** * {@inheritdoc} */ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) { if ('' === $str && isset($cursor->attr['img-data'], $cursor->attr['content-type'])) { $this->dumpKey($cursor); $this->line .= $this->style('default', $cursor->attr['img-size'] ?? '', []); $this->line .= $cursor->depth >= $this->displayOptions['maxDepth'] ? ' <samp class=sf-dump-compact>' : ' <samp class=sf-dump-expanded>'; $this->endValue($cursor); $this->line .= $this->indentPad; $this->line .= sprintf('<img src="data:%s;base64,%s" /></samp>', $cursor->attr['content-type'], base64_encode($cursor->attr['img-data'])); $this->endValue($cursor); } else { parent::dumpString($cursor, $str, $bin, $cut); } } /** * {@inheritdoc} */ public function enterHash(Cursor $cursor, int $type, $class, bool $hasChild) { if (Cursor::HASH_OBJECT === $type) { $cursor->attr['depth'] = $cursor->depth; } parent::enterHash($cursor, $type, $class, false); if ($cursor->skipChildren || $cursor->depth >= $this->displayOptions['maxDepth']) { $cursor->skipChildren = false; $eol = ' class=sf-dump-compact>'; } else { $this->expandNextHash = false; $eol = ' class=sf-dump-expanded>'; } if ($hasChild) { $this->line .= '<samp data-depth='.($cursor->depth + 1); if ($cursor->refIndex) { $r = Cursor::HASH_OBJECT !== $type ? 1 - (Cursor::HASH_RESOURCE !== $type) : 2; $r .= $r && 0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->refIndex; $this->line .= sprintf(' id=%s-ref%s', $this->dumpId, $r); } $this->line .= $eol; $this->dumpLine($cursor->depth); } } /** * {@inheritdoc} */ public function leaveHash(Cursor $cursor, int $type, $class, bool $hasChild, int $cut) { $this->dumpEllipsis($cursor, $hasChild, $cut); if ($hasChild) { $this->line .= '</samp>'; } parent::leaveHash($cursor, $type, $class, $hasChild, 0); } /** * {@inheritdoc} */ protected function style(string $style, string $value, array $attr = []) { if ('' === $value) { return ''; } $v = esc($value); if ('ref' === $style) { if (empty($attr['count'])) { return sprintf('<a class=sf-dump-ref>%s</a>', $v); } $r = ('#' !== $v[0] ? 1 - ('@' !== $v[0]) : 2).substr($value, 1); return sprintf('<a class=sf-dump-ref href=#%s-ref%s title="%d occurrences">%s</a>', $this->dumpId, $r, 1 + $attr['count'], $v); } if ('const' === $style && isset($attr['value'])) { $style .= sprintf(' title="%s"', esc(\is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value']))); } elseif ('public' === $style) { $style .= sprintf(' title="%s"', empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property'); } elseif ('str' === $style && 1 < $attr['length']) { $style .= sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); } elseif ('note' === $style && 0 < ($attr['depth'] ?? 0) && false !== $c = strrpos($value, '\\')) { $style .= ' title=""'; $attr += [ 'ellipsis' => \strlen($value) - $c, 'ellipsis-type' => 'note', 'ellipsis-tail' => 1, ]; } elseif ('protected' === $style) { $style .= ' title="Protected property"'; } elseif ('meta' === $style && isset($attr['title'])) { $style .= sprintf(' title="%s"', esc($this->utf8Encode($attr['title']))); } elseif ('private' === $style) { $style .= sprintf(' title="Private property defined in class: `%s`"', esc($this->utf8Encode($attr['class']))); } $map = static::$controlCharsMap; if (isset($attr['ellipsis'])) { $class = 'sf-dump-ellipsis'; if (isset($attr['ellipsis-type'])) { $class = sprintf('"%s sf-dump-ellipsis-%s"', $class, $attr['ellipsis-type']); } $label = esc(substr($value, -$attr['ellipsis'])); $style = str_replace(' title="', " title=\"$v\n", $style); $v = sprintf('<span class=%s>%s</span>', $class, substr($v, 0, -\strlen($label))); if (!empty($attr['ellipsis-tail'])) { $tail = \strlen(esc(substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']))); $v .= sprintf('<span class=%s>%s</span>%s', $class, substr($label, 0, $tail), substr($label, $tail)); } else { $v .= $label; } } $v = "<span class=sf-dump-{$style}>".preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) { $s = $b = '<span class="sf-dump-default'; $c = $c[$i = 0]; if ($ns = "\r" === $c[$i] || "\n" === $c[$i]) { $s .= ' sf-dump-ns'; } $s .= '">'; do { if (("\r" === $c[$i] || "\n" === $c[$i]) !== $ns) { $s .= '</span>'.$b; if ($ns = !$ns) { $s .= ' sf-dump-ns'; } $s .= '">'; } $s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i])); } while (isset($c[++$i])); return $s.'</span>'; }, $v).'</span>'; if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) { $attr['href'] = $href; } if (isset($attr['href'])) { $target = isset($attr['file']) ? '' : ' target="_blank"'; $v = sprintf('<a href="%s"%s rel="noopener noreferrer">%s</a>', esc($this->utf8Encode($attr['href'])), $target, $v); } if (isset($attr['lang'])) { $v = sprintf('<code class="%s">%s</code>', esc($attr['lang']), $v); } return $v; } /** * {@inheritdoc} */ protected function dumpLine(int $depth, bool $endOfValue = false) { if (-1 === $this->lastDepth) { $this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line; } if ($this->headerIsDumped !== ($this->outputStream ?? $this->lineDumper)) { $this->line = $this->getDumpHeader().$this->line; } if (-1 === $depth) { $args = ['"'.$this->dumpId.'"']; if ($this->extraDisplayOptions) { $args[] = json_encode($this->extraDisplayOptions, \JSON_FORCE_OBJECT); } // Replace is for BC $this->line .= sprintf(str_replace('"%s"', '%s', $this->dumpSuffix), implode(', ', $args)); } $this->lastDepth = $depth; $this->line = mb_encode_numericentity($this->line, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8'); if (-1 === $depth) { AbstractDumper::dumpLine(0); } AbstractDumper::dumpLine($depth); } private function getSourceLink(string $file, int $line) { $options = $this->extraDisplayOptions + $this->displayOptions; if ($fmt = $options['fileLinkFormat']) { return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line); } return false; } } function esc(string $str) { return htmlspecialchars($str, \ENT_QUOTES, 'UTF-8'); } Dumper/ServerDumper.php 0000644 00000003105 15173250124 0011133 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Dumper; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; use Symfony\Component\VarDumper\Server\Connection; /** * ServerDumper forwards serialized Data clones to a server. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ class ServerDumper implements DataDumperInterface { private $connection; private $wrappedDumper; /** * @param string $host The server host * @param DataDumperInterface|null $wrappedDumper A wrapped instance used whenever we failed contacting the server * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name */ public function __construct(string $host, DataDumperInterface $wrappedDumper = null, array $contextProviders = []) { $this->connection = new Connection($host, $contextProviders); $this->wrappedDumper = $wrappedDumper; } public function getContextProviders(): array { return $this->connection->getContextProviders(); } /** * {@inheritdoc} */ public function dump(Data $data) { if (!$this->connection->write($data) && $this->wrappedDumper) { $this->wrappedDumper->dump($data); } } } VarDumper.php 0000644 00000007412 15173250124 0007166 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Dumper\ContextProvider\CliContextProvider; use Symfony\Component\VarDumper\Dumper\ContextProvider\RequestContextProvider; use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; use Symfony\Component\VarDumper\Dumper\ContextualizedDumper; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\Dumper\ServerDumper; // Load the global dump() function require_once __DIR__.'/Resources/functions/dump.php'; /** * @author Nicolas Grekas <p@tchwork.com> */ class VarDumper { /** * @var callable|null */ private static $handler; public static function dump($var) { if (null === self::$handler) { self::register(); } return (self::$handler)($var); } /** * @return callable|null */ public static function setHandler(callable $callable = null) { $prevHandler = self::$handler; // Prevent replacing the handler with expected format as soon as the env var was set: if (isset($_SERVER['VAR_DUMPER_FORMAT'])) { return $prevHandler; } self::$handler = $callable; return $prevHandler; } private static function register(): void { $cloner = new VarCloner(); $cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); $format = $_SERVER['VAR_DUMPER_FORMAT'] ?? null; switch (true) { case 'html' === $format: $dumper = new HtmlDumper(); break; case 'cli' === $format: $dumper = new CliDumper(); break; case 'server' === $format: case $format && 'tcp' === parse_url($format, \PHP_URL_SCHEME): $host = 'server' === $format ? $_SERVER['VAR_DUMPER_SERVER'] ?? '127.0.0.1:9912' : $format; $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliDumper() : new HtmlDumper(); $dumper = new ServerDumper($host, $dumper, self::getDefaultContextProviders()); break; default: $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliDumper() : new HtmlDumper(); } if (!$dumper instanceof ServerDumper) { $dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]); } self::$handler = function ($var) use ($cloner, $dumper) { $dumper->dump($cloner->cloneVar($var)); }; } private static function getDefaultContextProviders(): array { $contextProviders = []; if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && class_exists(Request::class)) { $requestStack = new RequestStack(); $requestStack->push(Request::createFromGlobals()); $contextProviders['request'] = new RequestContextProvider($requestStack); } $fileLinkFormatter = class_exists(FileLinkFormatter::class) ? new FileLinkFormatter(null, $requestStack ?? null) : null; return $contextProviders + [ 'cli' => new CliContextProvider(), 'source' => new SourceContextProvider(null, null, $fileLinkFormatter), ]; } } Cloner/ClonerInterface.php 0000644 00000001013 15173250124 0011535 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Cloner; /** * @author Nicolas Grekas <p@tchwork.com> */ interface ClonerInterface { /** * Clones a PHP variable. * * @param mixed $var Any PHP variable * * @return Data */ public function cloneVar($var); } Cloner/DumperInterface.php 0000644 00000003474 15173250124 0011564 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Cloner; /** * DumperInterface used by Data objects. * * @author Nicolas Grekas <p@tchwork.com> */ interface DumperInterface { /** * Dumps a scalar value. * * @param string $type The PHP type of the value being dumped * @param string|int|float|bool $value The scalar value being dumped */ public function dumpScalar(Cursor $cursor, string $type, $value); /** * Dumps a string. * * @param string $str The string being dumped * @param bool $bin Whether $str is UTF-8 or binary encoded * @param int $cut The number of characters $str has been cut by */ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); /** * Dumps while entering an hash. * * @param int $type A Cursor::HASH_* const for the type of hash * @param string|int $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item */ public function enterHash(Cursor $cursor, int $type, $class, bool $hasChild); /** * Dumps while leaving an hash. * * @param int $type A Cursor::HASH_* const for the type of hash * @param string|int $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by */ public function leaveHash(Cursor $cursor, int $type, $class, bool $hasChild, int $cut); } Cloner/Stub.php 0000644 00000003024 15173250124 0007413 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Cloner; /** * Represents the main properties of a PHP variable. * * @author Nicolas Grekas <p@tchwork.com> */ class Stub { public const TYPE_REF = 1; public const TYPE_STRING = 2; public const TYPE_ARRAY = 3; public const TYPE_OBJECT = 4; public const TYPE_RESOURCE = 5; public const STRING_BINARY = 1; public const STRING_UTF8 = 2; public const ARRAY_ASSOC = 1; public const ARRAY_INDEXED = 2; public $type = self::TYPE_REF; public $class = ''; public $value; public $cut = 0; public $handle = 0; public $refCount = 0; public $position = 0; public $attr = []; private static $defaultProperties = []; /** * @internal */ public function __sleep(): array { $properties = []; if (!isset(self::$defaultProperties[$c = static::class])) { self::$defaultProperties[$c] = get_class_vars($c); foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) { unset(self::$defaultProperties[$c][$k]); } } foreach (self::$defaultProperties[$c] as $k => $v) { if ($this->$k !== $v) { $properties[] = $k; } } return $properties; } } Cloner/AbstractCloner.php 0000644 00000051262 15173250124 0011413 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Cloner; use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Exception\ThrowingCasterException; /** * AbstractCloner implements a generic caster mechanism for objects and resources. * * @author Nicolas Grekas <p@tchwork.com> */ abstract class AbstractCloner implements ClonerInterface { public static $defaultCasters = [ '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], 'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'], 'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], 'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'], 'Fiber' => ['Symfony\Component\VarDumper\Caster\FiberCaster', 'castFiber'], 'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'], 'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'], 'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'], 'ReflectionAttribute' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castAttribute'], 'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'], 'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'], 'ReflectionClassConstant' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClassConstant'], 'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'], 'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'], 'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'], 'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'], 'ReflectionReference' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReference'], 'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'], 'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'], 'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'], 'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'], 'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'], 'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], 'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], 'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'], 'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'], 'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], 'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], 'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], 'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], 'DOMTypeinfo' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'], 'DOMDomError' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'], 'DOMLocator' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'], 'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], 'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], 'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], 'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], 'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'], 'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'], 'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'], 'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'], 'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'], 'Symfony\Bridge\Monolog\Logger' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Symfony\Component\EventDispatcher\EventDispatcherInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Symfony\Component\HttpClient\AmpHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpClient\Response\AmpResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'], 'Symfony\Component\Uid\Ulid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUlid'], 'Symfony\Component\Uid\Uuid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUuid'], 'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'], 'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'], 'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'], 'Symfony\Component\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'], 'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'], 'Ramsey\Uuid\UuidInterface' => ['Symfony\Component\VarDumper\Caster\UuidCaster', 'castRamseyUuid'], 'ProxyManager\Proxy\ProxyInterface' => ['Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'], 'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'], 'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'], 'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'], 'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'], 'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'], 'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'], 'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'], 'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'], 'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'], 'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'], 'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'], 'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'], 'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], 'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'], 'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], 'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'], 'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'], 'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], 'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'], 'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'], 'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'], 'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'], 'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'], 'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'], 'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'], 'MessageFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'], 'NumberFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'], 'IntlTimeZone' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'], 'IntlCalendar' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'], 'IntlDateFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'], 'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'], 'Ds\Collection' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castCollection'], 'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'], 'Ds\Pair' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPair'], 'Symfony\Component\VarDumper\Caster\DsPairStub' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPairStub'], 'mysqli_driver' => ['Symfony\Component\VarDumper\Caster\MysqliCaster', 'castMysqliDriver'], 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], 'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], ':mysql link' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'], ':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], ':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], ':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], ':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], ':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'], ':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], 'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], ':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], ':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], ':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'], 'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], ':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], 'RdKafka' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castRdKafka'], 'RdKafka\Conf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castConf'], 'RdKafka\KafkaConsumer' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castKafkaConsumer'], 'RdKafka\Metadata\Broker' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castBrokerMetadata'], 'RdKafka\Metadata\Collection' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castCollectionMetadata'], 'RdKafka\Metadata\Partition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castPartitionMetadata'], 'RdKafka\Metadata\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicMetadata'], 'RdKafka\Message' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castMessage'], 'RdKafka\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopic'], 'RdKafka\TopicPartition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicPartition'], 'RdKafka\TopicConf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicConf'], ]; protected $maxItems = 2500; protected $maxString = -1; protected $minDepth = 1; /** * @var array<string, list<callable>> */ private $casters = []; /** * @var callable|null */ private $prevErrorHandler; private $classInfo = []; private $filter = 0; /** * @param callable[]|null $casters A map of casters * * @see addCasters */ public function __construct(array $casters = null) { if (null === $casters) { $casters = static::$defaultCasters; } $this->addCasters($casters); } /** * Adds casters for resources and objects. * * Maps resources or objects types to a callback. * Types are in the key, with a callable caster for value. * Resource types are to be prefixed with a `:`, * see e.g. static::$defaultCasters. * * @param callable[] $casters A map of casters */ public function addCasters(array $casters) { foreach ($casters as $type => $callback) { $this->casters[$type][] = $callback; } } /** * Sets the maximum number of items to clone past the minimum depth in nested structures. */ public function setMaxItems(int $maxItems) { $this->maxItems = $maxItems; } /** * Sets the maximum cloned length for strings. */ public function setMaxString(int $maxString) { $this->maxString = $maxString; } /** * Sets the minimum tree depth where we are guaranteed to clone all the items. After this * depth is reached, only setMaxItems items will be cloned. */ public function setMinDepth(int $minDepth) { $this->minDepth = $minDepth; } /** * Clones a PHP variable. * * @param mixed $var Any PHP variable * @param int $filter A bit field of Caster::EXCLUDE_* constants * * @return Data */ public function cloneVar($var, int $filter = 0) { $this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) { if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) { // Cloner never dies throw new \ErrorException($msg, 0, $type, $file, $line); } if ($this->prevErrorHandler) { return ($this->prevErrorHandler)($type, $msg, $file, $line, $context); } return false; }); $this->filter = $filter; if ($gc = gc_enabled()) { gc_disable(); } try { return new Data($this->doClone($var)); } finally { if ($gc) { gc_enable(); } restore_error_handler(); $this->prevErrorHandler = null; } } /** * Effectively clones the PHP variable. * * @param mixed $var Any PHP variable * * @return array */ abstract protected function doClone($var); /** * Casts an object to an array representation. * * @param bool $isNested True if the object is nested in the dumped structure * * @return array */ protected function castObject(Stub $stub, bool $isNested) { $obj = $stub->value; $class = $stub->class; if (\PHP_VERSION_ID < 80000 ? "\0" === ($class[15] ?? null) : str_contains($class, "@anonymous\0")) { $stub->class = get_debug_type($obj); } if (isset($this->classInfo[$class])) { [$i, $parents, $hasDebugInfo, $fileInfo] = $this->classInfo[$class]; } else { $i = 2; $parents = [$class]; $hasDebugInfo = method_exists($class, '__debugInfo'); foreach (class_parents($class) as $p) { $parents[] = $p; ++$i; } foreach (class_implements($class) as $p) { $parents[] = $p; ++$i; } $parents[] = '*'; $r = new \ReflectionClass($class); $fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : [ 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ]; $this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo]; } $stub->attr += $fileInfo; $a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class); try { while ($i--) { if (!empty($this->casters[$p = $parents[$i]])) { foreach ($this->casters[$p] as $callback) { $a = $callback($obj, $a, $stub, $isNested, $this->filter); } } } } catch (\Exception $e) { $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; } return $a; } /** * Casts a resource to an array representation. * * @param bool $isNested True if the object is nested in the dumped structure * * @return array */ protected function castResource(Stub $stub, bool $isNested) { $a = []; $res = $stub->value; $type = $stub->class; try { if (!empty($this->casters[':'.$type])) { foreach ($this->casters[':'.$type] as $callback) { $a = $callback($res, $a, $stub, $isNested, $this->filter); } } } catch (\Exception $e) { $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; } return $a; } } Cloner/Cursor.php 0000644 00000002071 15173250124 0007754 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Cloner; /** * Represents the current state of a dumper while dumping. * * @author Nicolas Grekas <p@tchwork.com> */ class Cursor { public const HASH_INDEXED = Stub::ARRAY_INDEXED; public const HASH_ASSOC = Stub::ARRAY_ASSOC; public const HASH_OBJECT = Stub::TYPE_OBJECT; public const HASH_RESOURCE = Stub::TYPE_RESOURCE; public $depth = 0; public $refIndex = 0; public $softRefTo = 0; public $softRefCount = 0; public $softRefHandle = 0; public $hardRefTo = 0; public $hardRefCount = 0; public $hardRefHandle = 0; public $hashType; public $hashKey; public $hashKeyIsBinary; public $hashIndex = 0; public $hashLength = 0; public $hashCut = 0; public $stop = false; public $attr = []; public $skipChildren = false; } Cloner/Data.php 0000644 00000033164 15173250124 0007357 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Cloner; use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; /** * @author Nicolas Grekas <p@tchwork.com> */ class Data implements \ArrayAccess, \Countable, \IteratorAggregate { private $data; private $position = 0; private $key = 0; private $maxDepth = 20; private $maxItemsPerDepth = -1; private $useRefHandles = -1; private $context = []; /** * @param array $data An array as returned by ClonerInterface::cloneVar() */ public function __construct(array $data) { $this->data = $data; } /** * @return string|null */ public function getType() { $item = $this->data[$this->position][$this->key]; if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { $item = $item->value; } if (!$item instanceof Stub) { return \gettype($item); } if (Stub::TYPE_STRING === $item->type) { return 'string'; } if (Stub::TYPE_ARRAY === $item->type) { return 'array'; } if (Stub::TYPE_OBJECT === $item->type) { return $item->class; } if (Stub::TYPE_RESOURCE === $item->type) { return $item->class.' resource'; } return null; } /** * Returns a native representation of the original value. * * @param array|bool $recursive Whether values should be resolved recursively or not * * @return string|int|float|bool|array|Data[]|null */ public function getValue($recursive = false) { $item = $this->data[$this->position][$this->key]; if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { $item = $item->value; } if (!($item = $this->getStub($item)) instanceof Stub) { return $item; } if (Stub::TYPE_STRING === $item->type) { return $item->value; } $children = $item->position ? $this->data[$item->position] : []; foreach ($children as $k => $v) { if ($recursive && !($v = $this->getStub($v)) instanceof Stub) { continue; } $children[$k] = clone $this; $children[$k]->key = $k; $children[$k]->position = $item->position; if ($recursive) { if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) { $recursive = (array) $recursive; if (isset($recursive[$v->position])) { continue; } $recursive[$v->position] = true; } $children[$k] = $children[$k]->getValue($recursive); } } return $children; } /** * @return int */ #[\ReturnTypeWillChange] public function count() { return \count($this->getValue()); } /** * @return \Traversable */ #[\ReturnTypeWillChange] public function getIterator() { if (!\is_array($value = $this->getValue())) { throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value))); } yield from $value; } public function __get(string $key) { if (null !== $data = $this->seek($key)) { $item = $this->getStub($data->data[$data->position][$data->key]); return $item instanceof Stub || [] === $item ? $data : $item; } return null; } /** * @return bool */ public function __isset(string $key) { return null !== $this->seek($key); } /** * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($key) { return $this->__isset($key); } /** * @return mixed */ #[\ReturnTypeWillChange] public function offsetGet($key) { return $this->__get($key); } /** * @return void */ #[\ReturnTypeWillChange] public function offsetSet($key, $value) { throw new \BadMethodCallException(self::class.' objects are immutable.'); } /** * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($key) { throw new \BadMethodCallException(self::class.' objects are immutable.'); } /** * @return string */ public function __toString() { $value = $this->getValue(); if (!\is_array($value)) { return (string) $value; } return sprintf('%s (count=%d)', $this->getType(), \count($value)); } /** * Returns a depth limited clone of $this. * * @return static */ public function withMaxDepth(int $maxDepth) { $data = clone $this; $data->maxDepth = $maxDepth; return $data; } /** * Limits the number of elements per depth level. * * @return static */ public function withMaxItemsPerDepth(int $maxItemsPerDepth) { $data = clone $this; $data->maxItemsPerDepth = $maxItemsPerDepth; return $data; } /** * Enables/disables objects' identifiers tracking. * * @param bool $useRefHandles False to hide global ref. handles * * @return static */ public function withRefHandles(bool $useRefHandles) { $data = clone $this; $data->useRefHandles = $useRefHandles ? -1 : 0; return $data; } /** * @return static */ public function withContext(array $context) { $data = clone $this; $data->context = $context; return $data; } /** * Seeks to a specific key in nested data structures. * * @param string|int $key The key to seek to * * @return static|null */ public function seek($key) { $item = $this->data[$this->position][$this->key]; if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { $item = $item->value; } if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) { return null; } $keys = [$key]; switch ($item->type) { case Stub::TYPE_OBJECT: $keys[] = Caster::PREFIX_DYNAMIC.$key; $keys[] = Caster::PREFIX_PROTECTED.$key; $keys[] = Caster::PREFIX_VIRTUAL.$key; $keys[] = "\0$item->class\0$key"; // no break case Stub::TYPE_ARRAY: case Stub::TYPE_RESOURCE: break; default: return null; } $data = null; $children = $this->data[$item->position]; foreach ($keys as $key) { if (isset($children[$key]) || \array_key_exists($key, $children)) { $data = clone $this; $data->key = $key; $data->position = $item->position; break; } } return $data; } /** * Dumps data with a DumperInterface dumper. */ public function dump(DumperInterface $dumper) { $refs = [0]; $cursor = new Cursor(); if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) { $cursor->attr['if_links'] = true; $cursor->hashType = -1; $dumper->dumpScalar($cursor, 'default', '^'); $cursor->attr = ['if_links' => true]; $dumper->dumpScalar($cursor, 'default', ' '); $cursor->hashType = 0; } $this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]); } /** * Depth-first dumping of items. * * @param mixed $item A Stub object or the original value being dumped */ private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $item) { $cursor->refIndex = 0; $cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0; $cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0; $firstSeen = true; if (!$item instanceof Stub) { $cursor->attr = []; $type = \gettype($item); if ($item && 'array' === $type) { $item = $this->getStub($item); } } elseif (Stub::TYPE_REF === $item->type) { if ($item->handle) { if (!isset($refs[$r = $item->handle - (\PHP_INT_MAX >> 1)])) { $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0]; } else { $firstSeen = false; } $cursor->hardRefTo = $refs[$r]; $cursor->hardRefHandle = $this->useRefHandles & $item->handle; $cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0; } $cursor->attr = $item->attr; $type = $item->class ?: \gettype($item->value); $item = $this->getStub($item->value); } if ($item instanceof Stub) { if ($item->refCount) { if (!isset($refs[$r = $item->handle])) { $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0]; } else { $firstSeen = false; } $cursor->softRefTo = $refs[$r]; } $cursor->softRefHandle = $this->useRefHandles & $item->handle; $cursor->softRefCount = $item->refCount; $cursor->attr = $item->attr; $cut = $item->cut; if ($item->position && $firstSeen) { $children = $this->data[$item->position]; if ($cursor->stop) { if ($cut >= 0) { $cut += \count($children); } $children = []; } } else { $children = []; } switch ($item->type) { case Stub::TYPE_STRING: $dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut); break; case Stub::TYPE_ARRAY: $item = clone $item; $item->type = $item->class; $item->class = $item->value; // no break case Stub::TYPE_OBJECT: case Stub::TYPE_RESOURCE: $withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth; $dumper->enterHash($cursor, $item->type, $item->class, $withChildren); if ($withChildren) { if ($cursor->skipChildren) { $withChildren = false; $cut = -1; } else { $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class); } } elseif ($children && 0 <= $cut) { $cut += \count($children); } $cursor->skipChildren = false; $dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut); break; default: throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type)); } } elseif ('array' === $type) { $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false); $dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0); } elseif ('string' === $type) { $dumper->dumpString($cursor, $item, false, 0); } else { $dumper->dumpScalar($cursor, $type, $item); } } /** * Dumps children of hash structures. * * @return int The final number of removed items */ private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, array &$refs, array $children, int $hashCut, int $hashType, bool $dumpKeys): int { $cursor = clone $parentCursor; ++$cursor->depth; $cursor->hashType = $hashType; $cursor->hashIndex = 0; $cursor->hashLength = \count($children); $cursor->hashCut = $hashCut; foreach ($children as $key => $child) { $cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key); $cursor->hashKey = $dumpKeys ? $key : null; $this->dumpItem($dumper, $cursor, $refs, $child); if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) { $parentCursor->stop = true; return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut; } } return $hashCut; } private function getStub($item) { if (!$item || !\is_array($item)) { return $item; } $stub = new Stub(); $stub->type = Stub::TYPE_ARRAY; foreach ($item as $stub->class => $stub->position) { } if (isset($item[0])) { $stub->cut = $item[0]; } $stub->value = $stub->cut + ($stub->position ? \count($this->data[$stub->position]) : 0); return $stub; } } Cloner/VarCloner.php 0000644 00000032733 15173250124 0010402 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Cloner; /** * @author Nicolas Grekas <p@tchwork.com> */ class VarCloner extends AbstractCloner { private static $gid; private static $arrayCache = []; /** * {@inheritdoc} */ protected function doClone($var) { $len = 1; // Length of $queue $pos = 0; // Number of cloned items past the minimum depth $refsCounter = 0; // Hard references counter $queue = [[$var]]; // This breadth-first queue is the return value $hardRefs = []; // Map of original zval ids to stub objects $objRefs = []; // Map of original object handles to their stub object counterpart $objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning $resRefs = []; // Map of original resource handles to their stub object counterpart $values = []; // Map of stub objects' ids to original values $maxItems = $this->maxItems; $maxString = $this->maxString; $minDepth = $this->minDepth; $currentDepth = 0; // Current tree depth $currentDepthFinalIndex = 0; // Final $queue index for current tree depth $minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached $cookie = (object) []; // Unique object used to detect hard references $a = null; // Array cast for nested structures $stub = null; // Stub capturing the main properties of an original item value // or null if the original value is used directly if (!$gid = self::$gid) { $gid = self::$gid = md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable } $arrayStub = new Stub(); $arrayStub->type = Stub::TYPE_ARRAY; $fromObjCast = false; for ($i = 0; $i < $len; ++$i) { // Detect when we move on to the next tree depth if ($i > $currentDepthFinalIndex) { ++$currentDepth; $currentDepthFinalIndex = $len - 1; if ($currentDepth >= $minDepth) { $minimumDepthReached = true; } } $refs = $vals = $queue[$i]; foreach ($vals as $k => $v) { // $v is the original value or a stub object in case of hard references if (\PHP_VERSION_ID >= 70400) { $zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null; } else { $refs[$k] = $cookie; $zvalRef = $vals[$k] === $cookie; } if ($zvalRef) { $vals[$k] = &$stub; // Break hard references to make $queue completely unset($stub); // independent from the original structure if (\PHP_VERSION_ID >= 70400 ? null !== $vals[$k] = $hardRefs[$zvalRef] ?? null : $v instanceof Stub && isset($hardRefs[spl_object_id($v)])) { if (\PHP_VERSION_ID >= 70400) { $v = $vals[$k]; } else { $refs[$k] = $vals[$k] = $v; } if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { ++$v->value->refCount; } ++$v->refCount; continue; } $vals[$k] = new Stub(); $vals[$k]->value = $v; $vals[$k]->handle = ++$refsCounter; if (\PHP_VERSION_ID >= 70400) { $hardRefs[$zvalRef] = $vals[$k]; } else { $refs[$k] = $vals[$k]; $h = spl_object_id($refs[$k]); $hardRefs[$h] = &$refs[$k]; $values[$h] = $v; } } // Create $stub when the original value $v cannot be used directly // If $v is a nested structure, put that structure in array $a switch (true) { case null === $v: case \is_bool($v): case \is_int($v): case \is_float($v): continue 2; case \is_string($v): if ('' === $v) { continue 2; } if (!preg_match('//u', $v)) { $stub = new Stub(); $stub->type = Stub::TYPE_STRING; $stub->class = Stub::STRING_BINARY; if (0 <= $maxString && 0 < $cut = \strlen($v) - $maxString) { $stub->cut = $cut; $stub->value = substr($v, 0, -$cut); } else { $stub->value = $v; } } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = mb_strlen($v, 'UTF-8') - $maxString) { $stub = new Stub(); $stub->type = Stub::TYPE_STRING; $stub->class = Stub::STRING_UTF8; $stub->cut = $cut; $stub->value = mb_substr($v, 0, $maxString, 'UTF-8'); } else { continue 2; } $a = null; break; case \is_array($v): if (!$v) { continue 2; } $stub = $arrayStub; if (\PHP_VERSION_ID >= 80100) { $stub->class = array_is_list($v) ? Stub::ARRAY_INDEXED : Stub::ARRAY_ASSOC; $a = $v; break; } $stub->class = Stub::ARRAY_INDEXED; $j = -1; foreach ($v as $gk => $gv) { if ($gk !== ++$j) { $stub->class = Stub::ARRAY_ASSOC; $a = $v; $a[$gid] = true; break; } } // Copies of $GLOBALS have very strange behavior, // let's detect them with some black magic if (isset($v[$gid])) { unset($v[$gid]); $a = []; foreach ($v as $gk => &$gv) { if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) { unset($v); $v = new Stub(); $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0]; $v->handle = -1; if (\PHP_VERSION_ID >= 70400) { $gv = &$a[$gk]; $hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] = &$gv; } else { $gv = &$hardRefs[spl_object_id($v)]; } $gv = $v; } $a[$gk] = &$gv; } unset($gv); } else { $a = $v; } break; case \is_object($v): if (empty($objRefs[$h = spl_object_id($v)])) { $stub = new Stub(); $stub->type = Stub::TYPE_OBJECT; $stub->class = \get_class($v); $stub->value = $v; $stub->handle = $h; $a = $this->castObject($stub, 0 < $i); if ($v !== $stub->value) { if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) { break; } $stub->handle = $h = spl_object_id($stub->value); } $stub->value = null; if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) { $stub->cut = \count($a); $a = null; } } if (empty($objRefs[$h])) { $objRefs[$h] = $stub; $objects[] = $v; } else { $stub = $objRefs[$h]; ++$stub->refCount; $a = null; } break; default: // resource if (empty($resRefs[$h = (int) $v])) { $stub = new Stub(); $stub->type = Stub::TYPE_RESOURCE; if ('Unknown' === $stub->class = @get_resource_type($v)) { $stub->class = 'Closed'; } $stub->value = $v; $stub->handle = $h; $a = $this->castResource($stub, 0 < $i); $stub->value = null; if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) { $stub->cut = \count($a); $a = null; } } if (empty($resRefs[$h])) { $resRefs[$h] = $stub; } else { $stub = $resRefs[$h]; ++$stub->refCount; $a = null; } break; } if ($a) { if (!$minimumDepthReached || 0 > $maxItems) { $queue[$len] = $a; $stub->position = $len++; } elseif ($pos < $maxItems) { if ($maxItems < $pos += \count($a)) { $a = \array_slice($a, 0, $maxItems - $pos, true); if ($stub->cut >= 0) { $stub->cut += $pos - $maxItems; } } $queue[$len] = $a; $stub->position = $len++; } elseif ($stub->cut >= 0) { $stub->cut += \count($a); $stub->position = 0; } } if ($arrayStub === $stub) { if ($arrayStub->cut) { $stub = [$arrayStub->cut, $arrayStub->class => $arrayStub->position]; $arrayStub->cut = 0; } elseif (isset(self::$arrayCache[$arrayStub->class][$arrayStub->position])) { $stub = self::$arrayCache[$arrayStub->class][$arrayStub->position]; } else { self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = [$arrayStub->class => $arrayStub->position]; } } if (!$zvalRef) { $vals[$k] = $stub; } elseif (\PHP_VERSION_ID >= 70400) { $hardRefs[$zvalRef]->value = $stub; } else { $refs[$k]->value = $stub; } } if ($fromObjCast) { $fromObjCast = false; $refs = $vals; $vals = []; $j = -1; foreach ($queue[$i] as $k => $v) { foreach ([$k => true] as $gk => $gv) { } if ($gk !== $k) { $vals = (object) $vals; $vals->{$k} = $refs[++$j]; $vals = (array) $vals; } else { $vals[$k] = $refs[++$j]; } } } $queue[$i] = $vals; } foreach ($values as $h => $v) { $hardRefs[$h] = $v; } return $queue; } } Server/Connection.php 0000644 00000005241 15173250124 0010624 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Server; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; /** * Forwards serialized Data clones to a server. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ class Connection { private $host; private $contextProviders; /** * @var resource|null */ private $socket; /** * @param string $host The server host * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name */ public function __construct(string $host, array $contextProviders = []) { if (!str_contains($host, '://')) { $host = 'tcp://'.$host; } $this->host = $host; $this->contextProviders = $contextProviders; } public function getContextProviders(): array { return $this->contextProviders; } public function write(Data $data): bool { $socketIsFresh = !$this->socket; if (!$this->socket = $this->socket ?: $this->createSocket()) { return false; } $context = ['timestamp' => microtime(true)]; foreach ($this->contextProviders as $name => $provider) { $context[$name] = $provider->getContext(); } $context = array_filter($context); $encodedPayload = base64_encode(serialize([$data, $context]))."\n"; set_error_handler([self::class, 'nullErrorHandler']); try { if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) { return true; } if (!$socketIsFresh) { stream_socket_shutdown($this->socket, \STREAM_SHUT_RDWR); fclose($this->socket); $this->socket = $this->createSocket(); } if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) { return true; } } finally { restore_error_handler(); } return false; } private static function nullErrorHandler(int $t, string $m) { // no-op } private function createSocket() { set_error_handler([self::class, 'nullErrorHandler']); try { return stream_socket_client($this->host, $errno, $errstr, 3); } finally { restore_error_handler(); } } } Server/DumpServer.php 0000644 00000006307 15173250124 0010625 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Server; use Psr\Log\LoggerInterface; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Stub; /** * A server collecting Data clones sent by a ServerDumper. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> * * @final */ class DumpServer { private $host; private $logger; /** * @var resource|null */ private $socket; public function __construct(string $host, LoggerInterface $logger = null) { if (!str_contains($host, '://')) { $host = 'tcp://'.$host; } $this->host = $host; $this->logger = $logger; } public function start(): void { if (!$this->socket = stream_socket_server($this->host, $errno, $errstr)) { throw new \RuntimeException(sprintf('Server start failed on "%s": ', $this->host).$errstr.' '.$errno); } } public function listen(callable $callback): void { if (null === $this->socket) { $this->start(); } foreach ($this->getMessages() as $clientId => $message) { if ($this->logger) { $this->logger->info('Received a payload from client {clientId}', ['clientId' => $clientId]); } $payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]); // Impossible to decode the message, give up. if (false === $payload) { if ($this->logger) { $this->logger->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]); } continue; } if (!\is_array($payload) || \count($payload) < 2 || !$payload[0] instanceof Data || !\is_array($payload[1])) { if ($this->logger) { $this->logger->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]); } continue; } [$data, $context] = $payload; $callback($data, $context, $clientId); } } public function getHost(): string { return $this->host; } private function getMessages(): iterable { $sockets = [(int) $this->socket => $this->socket]; $write = []; while (true) { $read = $sockets; stream_select($read, $write, $write, null); foreach ($read as $stream) { if ($this->socket === $stream) { $stream = stream_socket_accept($this->socket); $sockets[(int) $stream] = $stream; } elseif (feof($stream)) { unset($sockets[(int) $stream]); fclose($stream); } else { yield (int) $stream => fgets($stream); } } } } } Caster/DsCaster.php 0000644 00000003066 15173250124 0010213 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Ds\Collection; use Ds\Map; use Ds\Pair; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts Ds extension classes to array representation. * * @author Jáchym Toušek <enumag@gmail.com> * * @final */ class DsCaster { public static function castCollection(Collection $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'count'] = $c->count(); $a[Caster::PREFIX_VIRTUAL.'capacity'] = $c->capacity(); if (!$c instanceof Map) { $a += $c->toArray(); } return $a; } public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array { foreach ($c as $k => $v) { $a[] = new DsPairStub($k, $v); } return $a; } public static function castPair(Pair $c, array $a, Stub $stub, bool $isNested): array { foreach ($c->toArray() as $k => $v) { $a[Caster::PREFIX_VIRTUAL.$k] = $v; } return $a; } public static function castPairStub(DsPairStub $c, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $stub->class = Pair::class; $stub->value = null; $stub->handle = 0; $a = $c->value; } return $a; } } Caster/PdoCaster.php 0000644 00000006746 15173250124 0010377 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts PDO related classes to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class PdoCaster { private const PDO_ATTRIBUTES = [ 'CASE' => [ \PDO::CASE_LOWER => 'LOWER', \PDO::CASE_NATURAL => 'NATURAL', \PDO::CASE_UPPER => 'UPPER', ], 'ERRMODE' => [ \PDO::ERRMODE_SILENT => 'SILENT', \PDO::ERRMODE_WARNING => 'WARNING', \PDO::ERRMODE_EXCEPTION => 'EXCEPTION', ], 'TIMEOUT', 'PREFETCH', 'AUTOCOMMIT', 'PERSISTENT', 'DRIVER_NAME', 'SERVER_INFO', 'ORACLE_NULLS' => [ \PDO::NULL_NATURAL => 'NATURAL', \PDO::NULL_EMPTY_STRING => 'EMPTY_STRING', \PDO::NULL_TO_STRING => 'TO_STRING', ], 'CLIENT_VERSION', 'SERVER_VERSION', 'STATEMENT_CLASS', 'EMULATE_PREPARES', 'CONNECTION_STATUS', 'STRINGIFY_FETCHES', 'DEFAULT_FETCH_MODE' => [ \PDO::FETCH_ASSOC => 'ASSOC', \PDO::FETCH_BOTH => 'BOTH', \PDO::FETCH_LAZY => 'LAZY', \PDO::FETCH_NUM => 'NUM', \PDO::FETCH_OBJ => 'OBJ', ], ]; public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) { $attr = []; $errmode = $c->getAttribute(\PDO::ATTR_ERRMODE); $c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); foreach (self::PDO_ATTRIBUTES as $k => $v) { if (!isset($k[0])) { $k = $v; $v = []; } try { $attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(\constant('PDO::ATTR_'.$k)); if ($v && isset($v[$attr[$k]])) { $attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]); } } catch (\Exception $e) { } } if (isset($attr[$k = 'STATEMENT_CLASS'][1])) { if ($attr[$k][1]) { $attr[$k][1] = new ArgsStub($attr[$k][1], '__construct', $attr[$k][0]); } $attr[$k][0] = new ClassStub($attr[$k][0]); } $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'inTransaction' => method_exists($c, 'inTransaction'), $prefix.'errorInfo' => $c->errorInfo(), $prefix.'attributes' => new EnumStub($attr), ]; if ($a[$prefix.'inTransaction']) { $a[$prefix.'inTransaction'] = $c->inTransaction(); } else { unset($a[$prefix.'inTransaction']); } if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { unset($a[$prefix.'errorInfo']); } $c->setAttribute(\PDO::ATTR_ERRMODE, $errmode); return $a; } public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a[$prefix.'errorInfo'] = $c->errorInfo(); if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { unset($a[$prefix.'errorInfo']); } return $a; } } Caster/RedisCaster.php 0000644 00000012217 15173250124 0010711 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts Redis class from ext-redis to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class RedisCaster { private const SERIALIZERS = [ \Redis::SERIALIZER_NONE => 'NONE', \Redis::SERIALIZER_PHP => 'PHP', 2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY ]; private const MODES = [ \Redis::ATOMIC => 'ATOMIC', \Redis::MULTI => 'MULTI', \Redis::PIPELINE => 'PIPELINE', ]; private const COMPRESSION_MODES = [ 0 => 'NONE', // Redis::COMPRESSION_NONE 1 => 'LZF', // Redis::COMPRESSION_LZF ]; private const FAILOVER_OPTIONS = [ \RedisCluster::FAILOVER_NONE => 'NONE', \RedisCluster::FAILOVER_ERROR => 'ERROR', \RedisCluster::FAILOVER_DISTRIBUTE => 'DISTRIBUTE', \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES', ]; public static function castRedis(\Redis $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; if (!$connected = $c->isConnected()) { return $a + [ $prefix.'isConnected' => $connected, ]; } $mode = $c->getMode(); return $a + [ $prefix.'isConnected' => $connected, $prefix.'host' => $c->getHost(), $prefix.'port' => $c->getPort(), $prefix.'auth' => $c->getAuth(), $prefix.'mode' => isset(self::MODES[$mode]) ? new ConstStub(self::MODES[$mode], $mode) : $mode, $prefix.'dbNum' => $c->getDbNum(), $prefix.'timeout' => $c->getTimeout(), $prefix.'lastError' => $c->getLastError(), $prefix.'persistentId' => $c->getPersistentID(), $prefix.'options' => self::getRedisOptions($c), ]; } public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; return $a + [ $prefix.'hosts' => $c->_hosts(), $prefix.'function' => ClassStub::wrapCallable($c->_function()), $prefix.'lastError' => $c->getLastError(), $prefix.'options' => self::getRedisOptions($c), ]; } public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER); $a += [ $prefix.'_masters' => $c->_masters(), $prefix.'_redir' => $c->_redir(), $prefix.'mode' => new ConstStub($c->getMode() ? 'MULTI' : 'ATOMIC', $c->getMode()), $prefix.'lastError' => $c->getLastError(), $prefix.'options' => self::getRedisOptions($c, [ 'SLAVE_FAILOVER' => isset(self::FAILOVER_OPTIONS[$failover]) ? new ConstStub(self::FAILOVER_OPTIONS[$failover], $failover) : $failover, ]), ]; return $a; } /** * @param \Redis|\RedisArray|\RedisCluster $redis */ private static function getRedisOptions($redis, array $options = []): EnumStub { $serializer = $redis->getOption(\Redis::OPT_SERIALIZER); if (\is_array($serializer)) { foreach ($serializer as &$v) { if (isset(self::SERIALIZERS[$v])) { $v = new ConstStub(self::SERIALIZERS[$v], $v); } } } elseif (isset(self::SERIALIZERS[$serializer])) { $serializer = new ConstStub(self::SERIALIZERS[$serializer], $serializer); } $compression = \defined('Redis::OPT_COMPRESSION') ? $redis->getOption(\Redis::OPT_COMPRESSION) : 0; if (\is_array($compression)) { foreach ($compression as &$v) { if (isset(self::COMPRESSION_MODES[$v])) { $v = new ConstStub(self::COMPRESSION_MODES[$v], $v); } } } elseif (isset(self::COMPRESSION_MODES[$compression])) { $compression = new ConstStub(self::COMPRESSION_MODES[$compression], $compression); } $retry = \defined('Redis::OPT_SCAN') ? $redis->getOption(\Redis::OPT_SCAN) : 0; if (\is_array($retry)) { foreach ($retry as &$v) { $v = new ConstStub($v ? 'RETRY' : 'NORETRY', $v); } } else { $retry = new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry); } $options += [ 'TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : 0, 'READ_TIMEOUT' => $redis->getOption(\Redis::OPT_READ_TIMEOUT), 'COMPRESSION' => $compression, 'SERIALIZER' => $serializer, 'PREFIX' => $redis->getOption(\Redis::OPT_PREFIX), 'SCAN' => $retry, ]; return new EnumStub($options); } } Caster/Caster.php 0000644 00000013565 15173250124 0007731 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Helper for filtering out properties in casters. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class Caster { public const EXCLUDE_VERBOSE = 1; public const EXCLUDE_VIRTUAL = 2; public const EXCLUDE_DYNAMIC = 4; public const EXCLUDE_PUBLIC = 8; public const EXCLUDE_PROTECTED = 16; public const EXCLUDE_PRIVATE = 32; public const EXCLUDE_NULL = 64; public const EXCLUDE_EMPTY = 128; public const EXCLUDE_NOT_IMPORTANT = 256; public const EXCLUDE_STRICT = 512; public const PREFIX_VIRTUAL = "\0~\0"; public const PREFIX_DYNAMIC = "\0+\0"; public const PREFIX_PROTECTED = "\0*\0"; /** * Casts objects to arrays and adds the dynamic property prefix. * * @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not */ public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, string $debugClass = null): array { if ($hasDebugInfo) { try { $debugInfo = $obj->__debugInfo(); } catch (\Throwable $e) { // ignore failing __debugInfo() $hasDebugInfo = false; } } $a = $obj instanceof \Closure ? [] : (array) $obj; if ($obj instanceof \__PHP_Incomplete_Class) { return $a; } if ($a) { static $publicProperties = []; $debugClass = $debugClass ?? get_debug_type($obj); $i = 0; $prefixedKeys = []; foreach ($a as $k => $v) { if ("\0" !== ($k[0] ?? '')) { if (!isset($publicProperties[$class])) { foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { $publicProperties[$class][$prop->name] = true; } } if (!isset($publicProperties[$class][$k])) { $prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k; } } elseif ($debugClass !== $class && 1 === strpos($k, $class)) { $prefixedKeys[$i] = "\0".$debugClass.strrchr($k, "\0"); } ++$i; } if ($prefixedKeys) { $keys = array_keys($a); foreach ($prefixedKeys as $i => $k) { $keys[$i] = $k; } $a = array_combine($keys, $a); } } if ($hasDebugInfo && \is_array($debugInfo)) { foreach ($debugInfo as $k => $v) { if (!isset($k[0]) || "\0" !== $k[0]) { if (\array_key_exists(self::PREFIX_DYNAMIC.$k, $a)) { continue; } $k = self::PREFIX_VIRTUAL.$k; } unset($a[$k]); $a[$k] = $v; } } return $a; } /** * Filters out the specified properties. * * By default, a single match in the $filter bit field filters properties out, following an "or" logic. * When EXCLUDE_STRICT is set, an "and" logic is applied: all bits must match for a property to be removed. * * @param array $a The array containing the properties to filter * @param int $filter A bit field of Caster::EXCLUDE_* constants specifying which properties to filter out * @param string[] $listedProperties List of properties to exclude when Caster::EXCLUDE_VERBOSE is set, and to preserve when Caster::EXCLUDE_NOT_IMPORTANT is set * @param int|null &$count Set to the number of removed properties */ public static function filter(array $a, int $filter, array $listedProperties = [], ?int &$count = 0): array { $count = 0; foreach ($a as $k => $v) { $type = self::EXCLUDE_STRICT & $filter; if (null === $v) { $type |= self::EXCLUDE_NULL & $filter; $type |= self::EXCLUDE_EMPTY & $filter; } elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) { $type |= self::EXCLUDE_EMPTY & $filter; } if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) { $type |= self::EXCLUDE_NOT_IMPORTANT; } if ((self::EXCLUDE_VERBOSE & $filter) && \in_array($k, $listedProperties, true)) { $type |= self::EXCLUDE_VERBOSE; } if (!isset($k[1]) || "\0" !== $k[0]) { $type |= self::EXCLUDE_PUBLIC & $filter; } elseif ('~' === $k[1]) { $type |= self::EXCLUDE_VIRTUAL & $filter; } elseif ('+' === $k[1]) { $type |= self::EXCLUDE_DYNAMIC & $filter; } elseif ('*' === $k[1]) { $type |= self::EXCLUDE_PROTECTED & $filter; } else { $type |= self::EXCLUDE_PRIVATE & $filter; } if ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) { unset($a[$k]); ++$count; } } return $a; } public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested): array { if (isset($a['__PHP_Incomplete_Class_Name'])) { $stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')'; unset($a['__PHP_Incomplete_Class_Name']); } return $a; } } Caster/ResourceCaster.php 0000644 00000006261 15173250124 0011434 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts common resource types to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class ResourceCaster { /** * @param \CurlHandle|resource $h */ public static function castCurl($h, array $a, Stub $stub, bool $isNested): array { return curl_getinfo($h); } public static function castDba($dba, array $a, Stub $stub, bool $isNested) { $list = dba_list(); $a['file'] = $list[(int) $dba]; return $a; } public static function castProcess($process, array $a, Stub $stub, bool $isNested) { return proc_get_status($process); } public static function castStream($stream, array $a, Stub $stub, bool $isNested) { $a = stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested); if ($a['uri'] ?? false) { $a['uri'] = new LinkStub($a['uri']); } return $a; } public static function castStreamContext($stream, array $a, Stub $stub, bool $isNested) { return @stream_context_get_params($stream) ?: $a; } public static function castGd($gd, array $a, Stub $stub, bool $isNested) { $a['size'] = imagesx($gd).'x'.imagesy($gd); $a['trueColor'] = imageistruecolor($gd); return $a; } public static function castMysqlLink($h, array $a, Stub $stub, bool $isNested) { $a['host'] = mysql_get_host_info($h); $a['protocol'] = mysql_get_proto_info($h); $a['server'] = mysql_get_server_info($h); return $a; } public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested) { $stub->cut = -1; $info = openssl_x509_parse($h, false); $pin = openssl_pkey_get_public($h); $pin = openssl_pkey_get_details($pin)['key']; $pin = \array_slice(explode("\n", $pin), 1, -2); $pin = base64_decode(implode('', $pin)); $pin = base64_encode(hash('sha256', $pin, true)); $a += [ 'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), 'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), 'expiry' => new ConstStub(date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), 'fingerprint' => new EnumStub([ 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), 'pin-sha256' => new ConstStub($pin), ]), ]; return $a; } } Caster/FrameStub.php 0000644 00000001344 15173250124 0010370 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; /** * Represents a single backtrace frame as returned by debug_backtrace() or Exception->getTrace(). * * @author Nicolas Grekas <p@tchwork.com> */ class FrameStub extends EnumStub { public $keepArgs; public $inTraceStub; public function __construct(array $frame, bool $keepArgs = true, bool $inTraceStub = false) { $this->value = $frame; $this->keepArgs = $keepArgs; $this->inTraceStub = $inTraceStub; } } Caster/DoctrineCaster.php 0000644 00000003210 15173250124 0011403 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Doctrine\Common\Proxy\Proxy as CommonProxy; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Proxy\Proxy as OrmProxy; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts Doctrine related classes to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class DoctrineCaster { public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, bool $isNested) { foreach (['__cloner__', '__initializer__'] as $k) { if (\array_key_exists($k, $a)) { unset($a[$k]); ++$stub->cut; } } return $a; } public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool $isNested) { foreach (['_entityPersister', '_identifier'] as $k) { if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) { unset($a[$k]); ++$stub->cut; } } return $a; } public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, bool $isNested) { foreach (['snapshot', 'association', 'typeClass'] as $k) { if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) { $a[$k] = new CutStub($a[$k]); } } return $a; } } Caster/MysqliCaster.php 0000644 00000001263 15173250124 0011120 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * @author Nicolas Grekas <p@tchwork.com> * * @internal */ final class MysqliCaster { public static function castMysqliDriver(\mysqli_driver $c, array $a, Stub $stub, bool $isNested): array { foreach ($a as $k => $v) { if (isset($c->$k)) { $a[$k] = $c->$k; } } return $a; } } Caster/ReflectionCaster.php 0000644 00000035474 15173250124 0011747 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts Reflector related classes to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class ReflectionCaster { public const UNSET_CLOSURE_FILE_INFO = ['Closure' => __CLASS__.'::unsetClosureFileInfo']; private const EXTRA_MAP = [ 'docComment' => 'getDocComment', 'extension' => 'getExtensionName', 'isDisabled' => 'isDisabled', 'isDeprecated' => 'isDeprecated', 'isInternal' => 'isInternal', 'isUserDefined' => 'isUserDefined', 'isGenerator' => 'isGenerator', 'isVariadic' => 'isVariadic', ]; public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; $c = new \ReflectionFunction($c); $a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter); if (!str_contains($c->name, '{closure}')) { $stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name; unset($a[$prefix.'class']); } unset($a[$prefix.'extra']); $stub->class .= self::getSignature($a); if ($f = $c->getFileName()) { $stub->attr['file'] = $f; $stub->attr['line'] = $c->getStartLine(); } unset($a[$prefix.'parameters']); if ($filter & Caster::EXCLUDE_VERBOSE) { $stub->cut += ($c->getFileName() ? 2 : 0) + \count($a); return []; } if ($f) { $a[$prefix.'file'] = new LinkStub($f, $c->getStartLine()); $a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine(); } return $a; } public static function unsetClosureFileInfo(\Closure $c, array $a) { unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']); return $a; } public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $isNested) { // Cannot create ReflectionGenerator based on a terminated Generator try { $reflectionGenerator = new \ReflectionGenerator($c); } catch (\Exception $e) { $a[Caster::PREFIX_VIRTUAL.'closed'] = true; return $a; } return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; if ($c instanceof \ReflectionNamedType || \PHP_VERSION_ID < 80000) { $a += [ $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, $prefix.'allowsNull' => $c->allowsNull(), $prefix.'isBuiltin' => $c->isBuiltin(), ]; } elseif ($c instanceof \ReflectionUnionType || $c instanceof \ReflectionIntersectionType) { $a[$prefix.'allowsNull'] = $c->allowsNull(); self::addMap($a, $c, [ 'types' => 'getTypes', ]); } else { $a[$prefix.'allowsNull'] = $c->allowsNull(); } return $a; } public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested) { self::addMap($a, $c, [ 'name' => 'getName', 'arguments' => 'getArguments', ]); return $a; } public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; if ($c->getThis()) { $a[$prefix.'this'] = new CutStub($c->getThis()); } $function = $c->getFunction(); $frame = [ 'class' => $function->class ?? null, 'type' => isset($function->class) ? ($function->isStatic() ? '::' : '->') : null, 'function' => $function->name, 'file' => $c->getExecutingFile(), 'line' => $c->getExecutingLine(), ]; if ($trace = $c->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS)) { $function = new \ReflectionGenerator($c->getExecutingGenerator()); array_unshift($trace, [ 'function' => 'yield', 'file' => $function->getExecutingFile(), 'line' => $function->getExecutingLine() - (int) (\PHP_VERSION_ID < 80100), ]); $trace[] = $frame; $a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1); } else { $function = new FrameStub($frame, false, true); $function = ExceptionCaster::castFrameStub($function, [], $function, true); $a[$prefix.'executing'] = $function[$prefix.'src']; } $a[Caster::PREFIX_VIRTUAL.'closed'] = false; return $a; } public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; if ($n = \Reflection::getModifierNames($c->getModifiers())) { $a[$prefix.'modifiers'] = implode(' ', $n); } self::addMap($a, $c, [ 'extends' => 'getParentClass', 'implements' => 'getInterfaceNames', 'constants' => 'getReflectionConstants', ]); foreach ($c->getProperties() as $n) { $a[$prefix.'properties'][$n->name] = $n; } foreach ($c->getMethods() as $n) { $a[$prefix.'methods'][$n->name] = $n; } self::addAttributes($a, $c, $prefix); if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { self::addExtra($a, $c); } return $a; } public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; self::addMap($a, $c, [ 'returnsReference' => 'returnsReference', 'returnType' => 'getReturnType', 'class' => \PHP_VERSION_ID >= 80111 ? 'getClosureCalledClass' : 'getClosureScopeClass', 'this' => 'getClosureThis', ]); if (isset($a[$prefix.'returnType'])) { $v = $a[$prefix.'returnType']; $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); } if (isset($a[$prefix.'class'])) { $a[$prefix.'class'] = new ClassStub($a[$prefix.'class']); } if (isset($a[$prefix.'this'])) { $a[$prefix.'this'] = new CutStub($a[$prefix.'this']); } foreach ($c->getParameters() as $v) { $k = '$'.$v->name; if ($v->isVariadic()) { $k = '...'.$k; } if ($v->isPassedByReference()) { $k = '&'.$k; } $a[$prefix.'parameters'][$k] = $v; } if (isset($a[$prefix.'parameters'])) { $a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']); } self::addAttributes($a, $c, $prefix); if (!($filter & Caster::EXCLUDE_VERBOSE) && $v = $c->getStaticVariables()) { foreach ($v as $k => &$v) { if (\is_object($v)) { $a[$prefix.'use']['$'.$k] = new CutStub($v); } else { $a[$prefix.'use']['$'.$k] = &$v; } } unset($v); $a[$prefix.'use'] = new EnumStub($a[$prefix.'use']); } if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { self::addExtra($a, $c); } return $a; } public static function castClassConstant(\ReflectionClassConstant $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); $a[Caster::PREFIX_VIRTUAL.'value'] = $c->getValue(); self::addAttributes($a, $c); return $a; } public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); return $a; } public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; self::addMap($a, $c, [ 'position' => 'getPosition', 'isVariadic' => 'isVariadic', 'byReference' => 'isPassedByReference', 'allowsNull' => 'allowsNull', ]); self::addAttributes($a, $c, $prefix); if ($v = $c->getType()) { $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; } if (isset($a[$prefix.'typeHint'])) { $v = $a[$prefix.'typeHint']; $a[$prefix.'typeHint'] = new ClassStub($v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); } else { unset($a[$prefix.'allowsNull']); } if ($c->isOptional()) { try { $a[$prefix.'default'] = $v = $c->getDefaultValue(); if ($c->isDefaultValueConstant() && !\is_object($v)) { $a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v); } if (null === $v) { unset($a[$prefix.'allowsNull']); } } catch (\ReflectionException $e) { } } return $a; } public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); self::addAttributes($a, $c); self::addExtra($a, $c); return $a; } public static function castReference(\ReflectionReference $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId(); return $a; } public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, bool $isNested) { self::addMap($a, $c, [ 'version' => 'getVersion', 'dependencies' => 'getDependencies', 'iniEntries' => 'getIniEntries', 'isPersistent' => 'isPersistent', 'isTemporary' => 'isTemporary', 'constants' => 'getConstants', 'functions' => 'getFunctions', 'classes' => 'getClasses', ]); return $a; } public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, bool $isNested) { self::addMap($a, $c, [ 'version' => 'getVersion', 'author' => 'getAuthor', 'copyright' => 'getCopyright', 'url' => 'getURL', ]); return $a; } public static function getSignature(array $a) { $prefix = Caster::PREFIX_VIRTUAL; $signature = ''; if (isset($a[$prefix.'parameters'])) { foreach ($a[$prefix.'parameters']->value as $k => $param) { $signature .= ', '; if ($type = $param->getType()) { if (!$type instanceof \ReflectionNamedType) { $signature .= $type.' '; } else { if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) { $signature .= '?'; } $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' '; } } $signature .= $k; if (!$param->isDefaultValueAvailable()) { continue; } $v = $param->getDefaultValue(); $signature .= ' = '; if ($param->isDefaultValueConstant()) { $signature .= substr(strrchr('\\'.$param->getDefaultValueConstantName(), '\\'), 1); } elseif (null === $v) { $signature .= 'null'; } elseif (\is_array($v)) { $signature .= $v ? '[…'.\count($v).']' : '[]'; } elseif (\is_string($v)) { $signature .= 10 > \strlen($v) && !str_contains($v, '\\') ? "'{$v}'" : "'…".\strlen($v)."'"; } elseif (\is_bool($v)) { $signature .= $v ? 'true' : 'false'; } elseif (\is_object($v)) { $signature .= 'new '.substr(strrchr('\\'.get_debug_type($v), '\\'), 1); } else { $signature .= $v; } } } $signature = (empty($a[$prefix.'returnsReference']) ? '' : '&').'('.substr($signature, 2).')'; if (isset($a[$prefix.'returnType'])) { $signature .= ': '.substr(strrchr('\\'.$a[$prefix.'returnType'], '\\'), 1); } return $signature; } private static function addExtra(array &$a, \Reflector $c) { $x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : []; if (method_exists($c, 'getFileName') && $m = $c->getFileName()) { $x['file'] = new LinkStub($m, $c->getStartLine()); $x['line'] = $c->getStartLine().' to '.$c->getEndLine(); } self::addMap($x, $c, self::EXTRA_MAP, ''); if ($x) { $a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x); } } private static function addMap(array &$a, object $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL) { foreach ($map as $k => $m) { if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) { continue; } if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) { $a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m; } } } private static function addAttributes(array &$a, \Reflector $c, string $prefix = Caster::PREFIX_VIRTUAL): void { if (\PHP_VERSION_ID >= 80000) { foreach ($c->getAttributes() as $n) { $a[$prefix.'attributes'][] = $n; } } } } Caster/CutStub.php 0000644 00000003611 15173250124 0010070 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Represents the main properties of a PHP variable, pre-casted by a caster. * * @author Nicolas Grekas <p@tchwork.com> */ class CutStub extends Stub { public function __construct($value) { $this->value = $value; switch (\gettype($value)) { case 'object': $this->type = self::TYPE_OBJECT; $this->class = \get_class($value); if ($value instanceof \Closure) { ReflectionCaster::castClosure($value, [], $this, true, Caster::EXCLUDE_VERBOSE); } $this->cut = -1; break; case 'array': $this->type = self::TYPE_ARRAY; $this->class = self::ARRAY_ASSOC; $this->cut = $this->value = \count($value); break; case 'resource': case 'unknown type': case 'resource (closed)': $this->type = self::TYPE_RESOURCE; $this->handle = (int) $value; if ('Unknown' === $this->class = @get_resource_type($value)) { $this->class = 'Closed'; } $this->cut = -1; break; case 'string': $this->type = self::TYPE_STRING; $this->class = preg_match('//u', $value) ? self::STRING_UTF8 : self::STRING_BINARY; $this->cut = self::STRING_BINARY === $this->class ? \strlen($value) : mb_strlen($value, 'UTF-8'); $this->value = ''; break; } } } Caster/ExceptionCaster.php 0000644 00000037571 15173250124 0011613 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; use Symfony\Component\VarDumper\Cloner\Stub; use Symfony\Component\VarDumper\Exception\ThrowingCasterException; /** * Casts common Exception classes to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class ExceptionCaster { public static $srcContext = 1; public static $traceArgs = true; public static $errorTypes = [ \E_DEPRECATED => 'E_DEPRECATED', \E_USER_DEPRECATED => 'E_USER_DEPRECATED', \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', \E_ERROR => 'E_ERROR', \E_WARNING => 'E_WARNING', \E_PARSE => 'E_PARSE', \E_NOTICE => 'E_NOTICE', \E_CORE_ERROR => 'E_CORE_ERROR', \E_CORE_WARNING => 'E_CORE_WARNING', \E_COMPILE_ERROR => 'E_COMPILE_ERROR', \E_COMPILE_WARNING => 'E_COMPILE_WARNING', \E_USER_ERROR => 'E_USER_ERROR', \E_USER_WARNING => 'E_USER_WARNING', \E_USER_NOTICE => 'E_USER_NOTICE', \E_STRICT => 'E_STRICT', ]; private static $framesCache = []; public static function castError(\Error $e, array $a, Stub $stub, bool $isNested, int $filter = 0) { return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter); } public static function castException(\Exception $e, array $a, Stub $stub, bool $isNested, int $filter = 0) { return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter); } public static function castErrorException(\ErrorException $e, array $a, Stub $stub, bool $isNested) { if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) { $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); } return $a; } public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, bool $isNested) { $trace = Caster::PREFIX_VIRTUAL.'trace'; $prefix = Caster::PREFIX_PROTECTED; $xPrefix = "\0Exception\0"; if (isset($a[$xPrefix.'previous'], $a[$trace]) && $a[$xPrefix.'previous'] instanceof \Exception) { $b = (array) $a[$xPrefix.'previous']; $class = get_debug_type($a[$xPrefix.'previous']); self::traceUnshift($b[$xPrefix.'trace'], $class, $b[$prefix.'file'], $b[$prefix.'line']); $a[$trace] = new TraceStub($b[$xPrefix.'trace'], false, 0, -\count($a[$trace]->value)); } unset($a[$xPrefix.'previous'], $a[$prefix.'code'], $a[$prefix.'file'], $a[$prefix.'line']); return $a; } public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, bool $isNested) { $sPrefix = "\0".SilencedErrorContext::class."\0"; if (!isset($a[$s = $sPrefix.'severity'])) { return $a; } if (isset(self::$errorTypes[$a[$s]])) { $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); } $trace = [[ 'file' => $a[$sPrefix.'file'], 'line' => $a[$sPrefix.'line'], ]]; if (isset($a[$sPrefix.'trace'])) { $trace = array_merge($trace, $a[$sPrefix.'trace']); } unset($a[$sPrefix.'file'], $a[$sPrefix.'line'], $a[$sPrefix.'trace']); $a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs); return $a; } public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, bool $isNested) { if (!$isNested) { return $a; } $stub->class = ''; $stub->handle = 0; $frames = $trace->value; $prefix = Caster::PREFIX_VIRTUAL; $a = []; $j = \count($frames); if (0 > $i = $trace->sliceOffset) { $i = max(0, $j + $i); } if (!isset($trace->value[$i])) { return []; } $lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : ''; $frames[] = ['function' => '']; $collapse = false; for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) { $f = $frames[$i]; $call = isset($f['function']) ? (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'] : '???'; $frame = new FrameStub( [ 'object' => $f['object'] ?? null, 'class' => $f['class'] ?? null, 'type' => $f['type'] ?? null, 'function' => $f['function'] ?? null, ] + $frames[$i - 1], false, true ); $f = self::castFrameStub($frame, [], $frame, true); if (isset($f[$prefix.'src'])) { foreach ($f[$prefix.'src']->value as $label => $frame) { if (str_starts_with($label, "\0~collapse=0")) { if ($collapse) { $label = substr_replace($label, '1', 11, 1); } else { $collapse = true; } } $label = substr_replace($label, "title=Stack level $j.&", 2, 0); } $f = $frames[$i - 1]; if ($trace->keepArgs && !empty($f['args']) && $frame instanceof EnumStub) { $frame->value['arguments'] = new ArgsStub($f['args'], $f['function'] ?? null, $f['class'] ?? null); } } elseif ('???' !== $lastCall) { $label = new ClassStub($lastCall); if (isset($label->attr['ellipsis'])) { $label->attr['ellipsis'] += 2; $label = substr_replace($prefix, "ellipsis-type=class&ellipsis={$label->attr['ellipsis']}&ellipsis-tail=1&title=Stack level $j.", 2, 0).$label->value.'()'; } else { $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$label->value.'()'; } } else { $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall; } $a[substr_replace($label, sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame; $lastCall = $call; } if (null !== $trace->sliceLength) { $a = \array_slice($a, 0, $trace->sliceLength, true); } return $a; } public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, bool $isNested) { if (!$isNested) { return $a; } $f = $frame->value; $prefix = Caster::PREFIX_VIRTUAL; if (isset($f['file'], $f['line'])) { $cacheKey = $f; unset($cacheKey['object'], $cacheKey['args']); $cacheKey[] = self::$srcContext; $cacheKey = implode('-', $cacheKey); if (isset(self::$framesCache[$cacheKey])) { $a[$prefix.'src'] = self::$framesCache[$cacheKey]; } else { if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) { $f['file'] = substr($f['file'], 0, -\strlen($match[0])); $f['line'] = (int) $match[1]; } $src = $f['line']; $srcKey = $f['file']; $ellipsis = new LinkStub($srcKey, 0); $srcAttr = 'collapse='.(int) $ellipsis->inVendor; $ellipsisTail = $ellipsis->attr['ellipsis-tail'] ?? 0; $ellipsis = $ellipsis->attr['ellipsis'] ?? 0; if (is_file($f['file']) && 0 <= self::$srcContext) { if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) { $template = null; if (isset($f['object'])) { $template = $f['object']; } elseif ((new \ReflectionClass($f['class']))->isInstantiable()) { $template = unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class'])); } if (null !== $template) { $ellipsis = 0; $templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : ''); $templateInfo = $template->getDebugInfo(); if (isset($templateInfo[$f['line']])) { if (!method_exists($template, 'getSourceContext') || !is_file($templatePath = $template->getSourceContext()->getPath())) { $templatePath = null; } if ($templateSrc) { $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, 'twig', $templatePath, $f); $srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']]; } } } } if ($srcKey == $f['file']) { $src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, 'php', $f['file'], $f); $srcKey .= ':'.$f['line']; if ($ellipsis) { $ellipsis += 1 + \strlen($f['line']); } } $srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); } else { $srcAttr .= '&separator=:'; } $srcAttr .= $ellipsis ? '&ellipsis-type=path&ellipsis='.$ellipsis.'&ellipsis-tail='.$ellipsisTail : ''; self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(["\0~$srcAttr\0$srcKey" => $src]); } } unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']); if ($frame->inTraceStub) { unset($a[$prefix.'class'], $a[$prefix.'type'], $a[$prefix.'function']); } foreach ($a as $k => $v) { if (!$v) { unset($a[$k]); } } if ($frame->keepArgs && !empty($f['args'])) { $a[$prefix.'arguments'] = new ArgsStub($f['args'], $f['function'], $f['class']); } return $a; } private static function filterExceptionArray(string $xClass, array $a, string $xPrefix, int $filter): array { if (isset($a[$xPrefix.'trace'])) { $trace = $a[$xPrefix.'trace']; unset($a[$xPrefix.'trace']); // Ensures the trace is always last } else { $trace = []; } if (!($filter & Caster::EXCLUDE_VERBOSE) && $trace) { if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); } $a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs); } if (empty($a[$xPrefix.'previous'])) { unset($a[$xPrefix.'previous']); } unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']); if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { $a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; }, $a[Caster::PREFIX_PROTECTED.'message']); } if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { $a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); } return $a; } private static function traceUnshift(array &$trace, ?string $class, string $file, int $line): void { if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) { return; } array_unshift($trace, [ 'function' => $class ? 'new '.$class : null, 'file' => $file, 'line' => $line, ]); } private static function extractSource(string $srcLines, int $line, int $srcContext, string $lang, ?string $file, array $frame): EnumStub { $srcLines = explode("\n", $srcLines); $src = []; for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) { $src[] = ($srcLines[$i] ?? '')."\n"; } if ($frame['function'] ?? false) { $stub = new CutStub(new \stdClass()); $stub->class = (isset($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; $stub->type = Stub::TYPE_OBJECT; $stub->attr['cut_hash'] = true; $stub->attr['file'] = $frame['file']; $stub->attr['line'] = $frame['line']; try { $caller = isset($frame['class']) ? new \ReflectionMethod($frame['class'], $frame['function']) : new \ReflectionFunction($frame['function']); $stub->class .= ReflectionCaster::getSignature(ReflectionCaster::castFunctionAbstract($caller, [], $stub, true, Caster::EXCLUDE_VERBOSE)); if ($f = $caller->getFileName()) { $stub->attr['file'] = $f; $stub->attr['line'] = $caller->getStartLine(); } } catch (\ReflectionException $e) { // ignore fake class/function } $srcLines = ["\0~separator=\0" => $stub]; } else { $stub = null; $srcLines = []; } $ltrim = 0; do { $pad = null; for ($i = $srcContext << 1; $i >= 0; --$i) { if (isset($src[$i][$ltrim]) && "\r" !== ($c = $src[$i][$ltrim]) && "\n" !== $c) { if (null === $pad) { $pad = $c; } if ((' ' !== $c && "\t" !== $c) || $pad !== $c) { break; } } } ++$ltrim; } while (0 > $i && null !== $pad); --$ltrim; foreach ($src as $i => $c) { if ($ltrim) { $c = isset($c[$ltrim]) && "\r" !== $c[$ltrim] ? substr($c, $ltrim) : ltrim($c, " \t"); } $c = substr($c, 0, -1); if ($i !== $srcContext) { $c = new ConstStub('default', $c); } else { $c = new ConstStub($c, $stub ? 'in '.$stub->class : ''); if (null !== $file) { $c->attr['file'] = $file; $c->attr['line'] = $line; } } $c->attr['lang'] = $lang; $srcLines[sprintf("\0~separator=› &%d\0", $i + $line - $srcContext)] = $c; } return new EnumStub($srcLines); } } Caster/FiberCaster.php 0000644 00000002046 15173250124 0010671 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts Fiber related classes to array representation. * * @author Grégoire Pineau <lyrixx@lyrixx.info> */ final class FiberCaster { public static function castFiber(\Fiber $fiber, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; if ($fiber->isTerminated()) { $status = 'terminated'; } elseif ($fiber->isRunning()) { $status = 'running'; } elseif ($fiber->isSuspended()) { $status = 'suspended'; } elseif ($fiber->isStarted()) { $status = 'started'; } else { $status = 'not started'; } $a[$prefix.'status'] = $status; return $a; } } Caster/XmlResourceCaster.php 0000644 00000004761 15173250124 0012120 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts XML resources to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class XmlResourceCaster { private const XML_ERRORS = [ \XML_ERROR_NONE => 'XML_ERROR_NONE', \XML_ERROR_NO_MEMORY => 'XML_ERROR_NO_MEMORY', \XML_ERROR_SYNTAX => 'XML_ERROR_SYNTAX', \XML_ERROR_NO_ELEMENTS => 'XML_ERROR_NO_ELEMENTS', \XML_ERROR_INVALID_TOKEN => 'XML_ERROR_INVALID_TOKEN', \XML_ERROR_UNCLOSED_TOKEN => 'XML_ERROR_UNCLOSED_TOKEN', \XML_ERROR_PARTIAL_CHAR => 'XML_ERROR_PARTIAL_CHAR', \XML_ERROR_TAG_MISMATCH => 'XML_ERROR_TAG_MISMATCH', \XML_ERROR_DUPLICATE_ATTRIBUTE => 'XML_ERROR_DUPLICATE_ATTRIBUTE', \XML_ERROR_JUNK_AFTER_DOC_ELEMENT => 'XML_ERROR_JUNK_AFTER_DOC_ELEMENT', \XML_ERROR_PARAM_ENTITY_REF => 'XML_ERROR_PARAM_ENTITY_REF', \XML_ERROR_UNDEFINED_ENTITY => 'XML_ERROR_UNDEFINED_ENTITY', \XML_ERROR_RECURSIVE_ENTITY_REF => 'XML_ERROR_RECURSIVE_ENTITY_REF', \XML_ERROR_ASYNC_ENTITY => 'XML_ERROR_ASYNC_ENTITY', \XML_ERROR_BAD_CHAR_REF => 'XML_ERROR_BAD_CHAR_REF', \XML_ERROR_BINARY_ENTITY_REF => 'XML_ERROR_BINARY_ENTITY_REF', \XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => 'XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF', \XML_ERROR_MISPLACED_XML_PI => 'XML_ERROR_MISPLACED_XML_PI', \XML_ERROR_UNKNOWN_ENCODING => 'XML_ERROR_UNKNOWN_ENCODING', \XML_ERROR_INCORRECT_ENCODING => 'XML_ERROR_INCORRECT_ENCODING', \XML_ERROR_UNCLOSED_CDATA_SECTION => 'XML_ERROR_UNCLOSED_CDATA_SECTION', \XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING', ]; public static function castXml($h, array $a, Stub $stub, bool $isNested) { $a['current_byte_index'] = xml_get_current_byte_index($h); $a['current_column_number'] = xml_get_current_column_number($h); $a['current_line_number'] = xml_get_current_line_number($h); $a['error_code'] = xml_get_error_code($h); if (isset(self::XML_ERRORS[$a['error_code']])) { $a['error_code'] = new ConstStub(self::XML_ERRORS[$a['error_code']], $a['error_code']); } return $a; } } Caster/DsPairStub.php 0000644 00000001145 15173250124 0010517 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * @author Nicolas Grekas <p@tchwork.com> */ class DsPairStub extends Stub { public function __construct($key, $value) { $this->value = [ Caster::PREFIX_VIRTUAL.'key' => $key, Caster::PREFIX_VIRTUAL.'value' => $value, ]; } } Caster/DOMCaster.php 0000644 00000023606 15173250124 0010266 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts DOM related classes to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class DOMCaster { private const ERROR_CODES = [ \DOM_PHP_ERR => 'DOM_PHP_ERR', \DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR', \DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR', \DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR', \DOM_WRONG_DOCUMENT_ERR => 'DOM_WRONG_DOCUMENT_ERR', \DOM_INVALID_CHARACTER_ERR => 'DOM_INVALID_CHARACTER_ERR', \DOM_NO_DATA_ALLOWED_ERR => 'DOM_NO_DATA_ALLOWED_ERR', \DOM_NO_MODIFICATION_ALLOWED_ERR => 'DOM_NO_MODIFICATION_ALLOWED_ERR', \DOM_NOT_FOUND_ERR => 'DOM_NOT_FOUND_ERR', \DOM_NOT_SUPPORTED_ERR => 'DOM_NOT_SUPPORTED_ERR', \DOM_INUSE_ATTRIBUTE_ERR => 'DOM_INUSE_ATTRIBUTE_ERR', \DOM_INVALID_STATE_ERR => 'DOM_INVALID_STATE_ERR', \DOM_SYNTAX_ERR => 'DOM_SYNTAX_ERR', \DOM_INVALID_MODIFICATION_ERR => 'DOM_INVALID_MODIFICATION_ERR', \DOM_NAMESPACE_ERR => 'DOM_NAMESPACE_ERR', \DOM_INVALID_ACCESS_ERR => 'DOM_INVALID_ACCESS_ERR', \DOM_VALIDATION_ERR => 'DOM_VALIDATION_ERR', ]; private const NODE_TYPES = [ \XML_ELEMENT_NODE => 'XML_ELEMENT_NODE', \XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE', \XML_TEXT_NODE => 'XML_TEXT_NODE', \XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE', \XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE', \XML_ENTITY_NODE => 'XML_ENTITY_NODE', \XML_PI_NODE => 'XML_PI_NODE', \XML_COMMENT_NODE => 'XML_COMMENT_NODE', \XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE', \XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE', \XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE', \XML_NOTATION_NODE => 'XML_NOTATION_NODE', \XML_HTML_DOCUMENT_NODE => 'XML_HTML_DOCUMENT_NODE', \XML_DTD_NODE => 'XML_DTD_NODE', \XML_ELEMENT_DECL_NODE => 'XML_ELEMENT_DECL_NODE', \XML_ATTRIBUTE_DECL_NODE => 'XML_ATTRIBUTE_DECL_NODE', \XML_ENTITY_DECL_NODE => 'XML_ENTITY_DECL_NODE', \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', ]; public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested) { $k = Caster::PREFIX_PROTECTED.'code'; if (isset($a[$k], self::ERROR_CODES[$a[$k]])) { $a[$k] = new ConstStub(self::ERROR_CODES[$a[$k]], $a[$k]); } return $a; } public static function castLength($dom, array $a, Stub $stub, bool $isNested) { $a += [ 'length' => $dom->length, ]; return $a; } public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested) { $a += [ Caster::PREFIX_VIRTUAL.'Core' => '1.0', Caster::PREFIX_VIRTUAL.'XML' => '2.0', ]; return $a; } public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'nodeName' => $dom->nodeName, 'nodeValue' => new CutStub($dom->nodeValue), 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), 'parentNode' => new CutStub($dom->parentNode), 'childNodes' => $dom->childNodes, 'firstChild' => new CutStub($dom->firstChild), 'lastChild' => new CutStub($dom->lastChild), 'previousSibling' => new CutStub($dom->previousSibling), 'nextSibling' => new CutStub($dom->nextSibling), 'attributes' => $dom->attributes, 'ownerDocument' => new CutStub($dom->ownerDocument), 'namespaceURI' => $dom->namespaceURI, 'prefix' => $dom->prefix, 'localName' => $dom->localName, 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, 'textContent' => new CutStub($dom->textContent), ]; return $a; } public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'nodeName' => $dom->nodeName, 'nodeValue' => new CutStub($dom->nodeValue), 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), 'prefix' => $dom->prefix, 'localName' => $dom->localName, 'namespaceURI' => $dom->namespaceURI, 'ownerDocument' => new CutStub($dom->ownerDocument), 'parentNode' => new CutStub($dom->parentNode), ]; return $a; } public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ 'doctype' => $dom->doctype, 'implementation' => $dom->implementation, 'documentElement' => new CutStub($dom->documentElement), 'actualEncoding' => $dom->actualEncoding, 'encoding' => $dom->encoding, 'xmlEncoding' => $dom->xmlEncoding, 'standalone' => $dom->standalone, 'xmlStandalone' => $dom->xmlStandalone, 'version' => $dom->version, 'xmlVersion' => $dom->xmlVersion, 'strictErrorChecking' => $dom->strictErrorChecking, 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, 'config' => $dom->config, 'formatOutput' => $dom->formatOutput, 'validateOnParse' => $dom->validateOnParse, 'resolveExternals' => $dom->resolveExternals, 'preserveWhiteSpace' => $dom->preserveWhiteSpace, 'recover' => $dom->recover, 'substituteEntities' => $dom->substituteEntities, ]; if (!($filter & Caster::EXCLUDE_VERBOSE)) { $formatOutput = $dom->formatOutput; $dom->formatOutput = true; $a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()]; $dom->formatOutput = $formatOutput; } return $a; } public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'data' => $dom->data, 'length' => $dom->length, ]; return $a; } public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'name' => $dom->name, 'specified' => $dom->specified, 'value' => $dom->value, 'ownerElement' => $dom->ownerElement, 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; return $a; } public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'tagName' => $dom->tagName, 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; return $a; } public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'wholeText' => $dom->wholeText, ]; return $a; } public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'typeName' => $dom->typeName, 'typeNamespace' => $dom->typeNamespace, ]; return $a; } public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'severity' => $dom->severity, 'message' => $dom->message, 'type' => $dom->type, 'relatedException' => $dom->relatedException, 'related_data' => $dom->related_data, 'location' => $dom->location, ]; return $a; } public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'lineNumber' => $dom->lineNumber, 'columnNumber' => $dom->columnNumber, 'offset' => $dom->offset, 'relatedNode' => $dom->relatedNode, 'uri' => $dom->uri ? new LinkStub($dom->uri, $dom->lineNumber) : $dom->uri, ]; return $a; } public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'name' => $dom->name, 'entities' => $dom->entities, 'notations' => $dom->notations, 'publicId' => $dom->publicId, 'systemId' => $dom->systemId, 'internalSubset' => $dom->internalSubset, ]; return $a; } public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'publicId' => $dom->publicId, 'systemId' => $dom->systemId, ]; return $a; } public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'publicId' => $dom->publicId, 'systemId' => $dom->systemId, 'notationName' => $dom->notationName, 'actualEncoding' => $dom->actualEncoding, 'encoding' => $dom->encoding, 'version' => $dom->version, ]; return $a; } public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'target' => $dom->target, 'data' => $dom->data, ]; return $a; } public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested) { $a += [ 'document' => $dom->document, ]; return $a; } } Caster/CutArrayStub.php 0000644 00000001270 15173250124 0011066 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; /** * Represents a cut array. * * @author Nicolas Grekas <p@tchwork.com> */ class CutArrayStub extends CutStub { public $preservedSubset; public function __construct(array $value, array $preservedKeys) { parent::__construct($value); $this->preservedSubset = array_intersect_key($value, array_flip($preservedKeys)); $this->cut -= \count($this->preservedSubset); } } Caster/TraceStub.php 0000644 00000001703 15173250124 0010373 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Represents a backtrace as returned by debug_backtrace() or Exception->getTrace(). * * @author Nicolas Grekas <p@tchwork.com> */ class TraceStub extends Stub { public $keepArgs; public $sliceOffset; public $sliceLength; public $numberingOffset; public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, int $sliceLength = null, int $numberingOffset = 0) { $this->value = $trace; $this->keepArgs = $keepArgs; $this->sliceOffset = $sliceOffset; $this->sliceLength = $sliceLength; $this->numberingOffset = $numberingOffset; } } Caster/MemcachedCaster.php 0000644 00000004451 15173250124 0011512 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * @author Jan Schädlich <jan.schaedlich@sensiolabs.de> * * @final */ class MemcachedCaster { private static $optionConstants; private static $defaultOptions; public static function castMemcached(\Memcached $c, array $a, Stub $stub, bool $isNested) { $a += [ Caster::PREFIX_VIRTUAL.'servers' => $c->getServerList(), Caster::PREFIX_VIRTUAL.'options' => new EnumStub( self::getNonDefaultOptions($c) ), ]; return $a; } private static function getNonDefaultOptions(\Memcached $c): array { self::$defaultOptions = self::$defaultOptions ?? self::discoverDefaultOptions(); self::$optionConstants = self::$optionConstants ?? self::getOptionConstants(); $nonDefaultOptions = []; foreach (self::$optionConstants as $constantKey => $value) { if (self::$defaultOptions[$constantKey] !== $option = $c->getOption($value)) { $nonDefaultOptions[$constantKey] = $option; } } return $nonDefaultOptions; } private static function discoverDefaultOptions(): array { $defaultMemcached = new \Memcached(); $defaultMemcached->addServer('127.0.0.1', 11211); $defaultOptions = []; self::$optionConstants = self::$optionConstants ?? self::getOptionConstants(); foreach (self::$optionConstants as $constantKey => $value) { $defaultOptions[$constantKey] = $defaultMemcached->getOption($value); } return $defaultOptions; } private static function getOptionConstants(): array { $reflectedMemcached = new \ReflectionClass(\Memcached::class); $optionConstants = []; foreach ($reflectedMemcached->getConstants() as $constantKey => $value) { if (str_starts_with($constantKey, 'OPT_')) { $optionConstants[$constantKey] = $value; } } return $optionConstants; } } Caster/ProxyManagerCaster.php 0000644 00000001321 15173250124 0012251 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use ProxyManager\Proxy\ProxyInterface; use Symfony\Component\VarDumper\Cloner\Stub; /** * @author Nicolas Grekas <p@tchwork.com> * * @final */ class ProxyManagerCaster { public static function castProxy(ProxyInterface $c, array $a, Stub $stub, bool $isNested) { if ($parent = get_parent_class($c)) { $stub->class .= ' - '.$parent; } $stub->class .= '@proxy'; return $a; } } Caster/LinkStub.php 0000644 00000006500 15173250124 0010232 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; /** * Represents a file or a URL. * * @author Nicolas Grekas <p@tchwork.com> */ class LinkStub extends ConstStub { public $inVendor = false; private static $vendorRoots; private static $composerRoots; public function __construct(string $label, int $line = 0, string $href = null) { $this->value = $label; if (null === $href) { $href = $label; } if (!\is_string($href)) { return; } if (str_starts_with($href, 'file://')) { if ($href === $label) { $label = substr($label, 7); } $href = substr($href, 7); } elseif (str_contains($href, '://')) { $this->attr['href'] = $href; return; } if (!is_file($href)) { return; } if ($line) { $this->attr['line'] = $line; } if ($label !== $this->attr['file'] = realpath($href) ?: $href) { return; } if ($composerRoot = $this->getComposerRoot($href, $this->inVendor)) { $this->attr['ellipsis'] = \strlen($href) - \strlen($composerRoot) + 1; $this->attr['ellipsis-type'] = 'path'; $this->attr['ellipsis-tail'] = 1 + ($this->inVendor ? 2 + \strlen(implode('', \array_slice(explode(\DIRECTORY_SEPARATOR, substr($href, 1 - $this->attr['ellipsis'])), 0, 2))) : 0); } elseif (3 < \count($ellipsis = explode(\DIRECTORY_SEPARATOR, $href))) { $this->attr['ellipsis'] = 2 + \strlen(implode('', \array_slice($ellipsis, -2))); $this->attr['ellipsis-type'] = 'path'; $this->attr['ellipsis-tail'] = 1; } } private function getComposerRoot(string $file, bool &$inVendor) { if (null === self::$vendorRoots) { self::$vendorRoots = []; foreach (get_declared_classes() as $class) { if ('C' === $class[0] && str_starts_with($class, 'ComposerAutoloaderInit')) { $r = new \ReflectionClass($class); $v = \dirname($r->getFileName(), 2); if (is_file($v.'/composer/installed.json')) { self::$vendorRoots[] = $v.\DIRECTORY_SEPARATOR; } } } } $inVendor = false; if (isset(self::$composerRoots[$dir = \dirname($file)])) { return self::$composerRoots[$dir]; } foreach (self::$vendorRoots as $root) { if ($inVendor = str_starts_with($file, $root)) { return $root; } } $parent = $dir; while (!@is_file($parent.'/composer.json')) { if (!@file_exists($parent)) { // open_basedir restriction in effect break; } if ($parent === \dirname($parent)) { return self::$composerRoots[$dir] = false; } $parent = \dirname($parent); } return self::$composerRoots[$dir] = $parent.\DIRECTORY_SEPARATOR; } } Caster/PgSqlCaster.php 0000644 00000012554 15173250124 0010675 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts pqsql resources to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class PgSqlCaster { private const PARAM_CODES = [ 'server_encoding', 'client_encoding', 'is_superuser', 'session_authorization', 'DateStyle', 'TimeZone', 'IntervalStyle', 'integer_datetimes', 'application_name', 'standard_conforming_strings', ]; private const TRANSACTION_STATUS = [ \PGSQL_TRANSACTION_IDLE => 'PGSQL_TRANSACTION_IDLE', \PGSQL_TRANSACTION_ACTIVE => 'PGSQL_TRANSACTION_ACTIVE', \PGSQL_TRANSACTION_INTRANS => 'PGSQL_TRANSACTION_INTRANS', \PGSQL_TRANSACTION_INERROR => 'PGSQL_TRANSACTION_INERROR', \PGSQL_TRANSACTION_UNKNOWN => 'PGSQL_TRANSACTION_UNKNOWN', ]; private const RESULT_STATUS = [ \PGSQL_EMPTY_QUERY => 'PGSQL_EMPTY_QUERY', \PGSQL_COMMAND_OK => 'PGSQL_COMMAND_OK', \PGSQL_TUPLES_OK => 'PGSQL_TUPLES_OK', \PGSQL_COPY_OUT => 'PGSQL_COPY_OUT', \PGSQL_COPY_IN => 'PGSQL_COPY_IN', \PGSQL_BAD_RESPONSE => 'PGSQL_BAD_RESPONSE', \PGSQL_NONFATAL_ERROR => 'PGSQL_NONFATAL_ERROR', \PGSQL_FATAL_ERROR => 'PGSQL_FATAL_ERROR', ]; private const DIAG_CODES = [ 'severity' => \PGSQL_DIAG_SEVERITY, 'sqlstate' => \PGSQL_DIAG_SQLSTATE, 'message' => \PGSQL_DIAG_MESSAGE_PRIMARY, 'detail' => \PGSQL_DIAG_MESSAGE_DETAIL, 'hint' => \PGSQL_DIAG_MESSAGE_HINT, 'statement position' => \PGSQL_DIAG_STATEMENT_POSITION, 'internal position' => \PGSQL_DIAG_INTERNAL_POSITION, 'internal query' => \PGSQL_DIAG_INTERNAL_QUERY, 'context' => \PGSQL_DIAG_CONTEXT, 'file' => \PGSQL_DIAG_SOURCE_FILE, 'line' => \PGSQL_DIAG_SOURCE_LINE, 'function' => \PGSQL_DIAG_SOURCE_FUNCTION, ]; public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested) { $a['seek position'] = pg_lo_tell($lo); return $a; } public static function castLink($link, array $a, Stub $stub, bool $isNested) { $a['status'] = pg_connection_status($link); $a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']); $a['busy'] = pg_connection_busy($link); $a['transaction'] = pg_transaction_status($link); if (isset(self::TRANSACTION_STATUS[$a['transaction']])) { $a['transaction'] = new ConstStub(self::TRANSACTION_STATUS[$a['transaction']], $a['transaction']); } $a['pid'] = pg_get_pid($link); $a['last error'] = pg_last_error($link); $a['last notice'] = pg_last_notice($link); $a['host'] = pg_host($link); $a['port'] = pg_port($link); $a['dbname'] = pg_dbname($link); $a['options'] = pg_options($link); $a['version'] = pg_version($link); foreach (self::PARAM_CODES as $v) { if (false !== $s = pg_parameter_status($link, $v)) { $a['param'][$v] = $s; } } $a['param']['client_encoding'] = pg_client_encoding($link); $a['param'] = new EnumStub($a['param']); return $a; } public static function castResult($result, array $a, Stub $stub, bool $isNested) { $a['num rows'] = pg_num_rows($result); $a['status'] = pg_result_status($result); if (isset(self::RESULT_STATUS[$a['status']])) { $a['status'] = new ConstStub(self::RESULT_STATUS[$a['status']], $a['status']); } $a['command-completion tag'] = pg_result_status($result, \PGSQL_STATUS_STRING); if (-1 === $a['num rows']) { foreach (self::DIAG_CODES as $k => $v) { $a['error'][$k] = pg_result_error_field($result, $v); } } $a['affected rows'] = pg_affected_rows($result); $a['last OID'] = pg_last_oid($result); $fields = pg_num_fields($result); for ($i = 0; $i < $fields; ++$i) { $field = [ 'name' => pg_field_name($result, $i), 'table' => sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)), 'type' => sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)), 'nullable' => (bool) pg_field_is_null($result, $i), 'storage' => pg_field_size($result, $i).' bytes', 'display' => pg_field_prtlen($result, $i).' chars', ]; if (' (OID: )' === $field['table']) { $field['table'] = null; } if ('-1 bytes' === $field['storage']) { $field['storage'] = 'variable size'; } elseif ('1 bytes' === $field['storage']) { $field['storage'] = '1 byte'; } if ('1 chars' === $field['display']) { $field['display'] = '1 char'; } $a['fields'][] = new EnumStub($field); } return $a; } } Caster/ConstStub.php 0000644 00000001354 15173250124 0010425 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Represents a PHP constant and its value. * * @author Nicolas Grekas <p@tchwork.com> */ class ConstStub extends Stub { public function __construct(string $name, $value = null) { $this->class = $name; $this->value = 1 < \func_num_args() ? $value : $name; } /** * @return string */ public function __toString() { return (string) $this->value; } } Caster/SplCaster.php 0000644 00000017252 15173250124 0010405 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts SPL related classes to array representation. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class SplCaster { private const SPL_FILE_OBJECT_FLAGS = [ \SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE', \SplFileObject::READ_AHEAD => 'READ_AHEAD', \SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY', \SplFileObject::READ_CSV => 'READ_CSV', ]; public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested) { return self::castSplArray($c, $a, $stub, $isNested); } public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested) { return self::castSplArray($c, $a, $stub, $isNested); } public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested) { $a += [ Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c), ]; return $a; } public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $mode = $c->getIteratorMode(); $c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE); $a += [ $prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_DELETE) ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode), $prefix.'dllist' => iterator_to_array($c), ]; $c->setIteratorMode($mode); return $a; } public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested) { static $map = [ 'path' => 'getPath', 'filename' => 'getFilename', 'basename' => 'getBasename', 'pathname' => 'getPathname', 'extension' => 'getExtension', 'realPath' => 'getRealPath', 'aTime' => 'getATime', 'mTime' => 'getMTime', 'cTime' => 'getCTime', 'inode' => 'getInode', 'size' => 'getSize', 'perms' => 'getPerms', 'owner' => 'getOwner', 'group' => 'getGroup', 'type' => 'getType', 'writable' => 'isWritable', 'readable' => 'isReadable', 'executable' => 'isExecutable', 'file' => 'isFile', 'dir' => 'isDir', 'link' => 'isLink', 'linkTarget' => 'getLinkTarget', ]; $prefix = Caster::PREFIX_VIRTUAL; unset($a["\0SplFileInfo\0fileName"]); unset($a["\0SplFileInfo\0pathName"]); if (\PHP_VERSION_ID < 80000) { if (false === $c->getPathname()) { $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; return $a; } } else { try { $c->isReadable(); } catch (\RuntimeException $e) { if ('Object not initialized' !== $e->getMessage()) { throw $e; } $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; return $a; } catch (\Error $e) { if ('Object not initialized' !== $e->getMessage()) { throw $e; } $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; return $a; } } foreach ($map as $key => $accessor) { try { $a[$prefix.$key] = $c->$accessor(); } catch (\Exception $e) { } } if ($a[$prefix.'realPath'] ?? false) { $a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']); } if (isset($a[$prefix.'perms'])) { $a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']); } static $mapDate = ['aTime', 'mTime', 'cTime']; foreach ($mapDate as $key) { if (isset($a[$prefix.$key])) { $a[$prefix.$key] = new ConstStub(date('Y-m-d H:i:s', $a[$prefix.$key]), $a[$prefix.$key]); } } return $a; } public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested) { static $map = [ 'csvControl' => 'getCsvControl', 'flags' => 'getFlags', 'maxLineLen' => 'getMaxLineLen', 'fstat' => 'fstat', 'eof' => 'eof', 'key' => 'key', ]; $prefix = Caster::PREFIX_VIRTUAL; foreach ($map as $key => $accessor) { try { $a[$prefix.$key] = $c->$accessor(); } catch (\Exception $e) { } } if (isset($a[$prefix.'flags'])) { $flagsArray = []; foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) { if ($a[$prefix.'flags'] & $value) { $flagsArray[] = $name; } } $a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']); } if (isset($a[$prefix.'fstat'])) { $a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']); } return $a; } public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested) { $storage = []; unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967 unset($a["\0SplObjectStorage\0storage"]); $clone = clone $c; foreach ($clone as $obj) { $storage[] = [ 'object' => $obj, 'info' => $clone->getInfo(), ]; } $a += [ Caster::PREFIX_VIRTUAL.'storage' => $storage, ]; return $a; } public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator(); return $a; } public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get(); return $a; } private static function castSplArray($c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; $flags = $c->getFlags(); if (!($flags & \ArrayObject::STD_PROP_LIST)) { $c->setFlags(\ArrayObject::STD_PROP_LIST); $a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class); $c->setFlags($flags); } unset($a["\0ArrayObject\0storage"], $a["\0ArrayIterator\0storage"]); $a += [ $prefix.'storage' => $c->getArrayCopy(), $prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST), $prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS), ]; if ($c instanceof \ArrayObject) { $a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass()); } return $a; } } Caster/StubCaster.php 0000644 00000004134 15173250124 0010557 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts a caster's Stub. * * @author Nicolas Grekas <p@tchwork.com> * * @final */ class StubCaster { public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) { if ($isNested) { $stub->type = $c->type; $stub->class = $c->class; $stub->value = $c->value; $stub->handle = $c->handle; $stub->cut = $c->cut; $stub->attr = $c->attr; if (Stub::TYPE_REF === $c->type && !$c->class && \is_string($c->value) && !preg_match('//u', $c->value)) { $stub->type = Stub::TYPE_STRING; $stub->class = Stub::STRING_BINARY; } $a = []; } return $a; } public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool $isNested) { return $isNested ? $c->preservedSubset : $a; } public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) { if ($isNested) { $stub->cut += \count($a); return []; } return $a; } public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNested) { if ($isNested) { $stub->class = $c->dumpKeys ? '' : null; $stub->handle = 0; $stub->value = null; $stub->cut = $c->cut; $stub->attr = $c->attr; $a = []; if ($c->value) { foreach (array_keys($c->value) as $k) { $keys[] = !isset($k[0]) || "\0" !== $k[0] ? Caster::PREFIX_VIRTUAL.$k : $k; } // Preserve references with array_combine() $a = array_combine($keys, $c->value); } } return $a; } } Caster/RdKafkaCaster.php 0000644 00000011024 15173250124 0011141 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use RdKafka\Conf; use RdKafka\Exception as RdKafkaException; use RdKafka\KafkaConsumer; use RdKafka\Message; use RdKafka\Metadata\Broker as BrokerMetadata; use RdKafka\Metadata\Collection as CollectionMetadata; use RdKafka\Metadata\Partition as PartitionMetadata; use RdKafka\Metadata\Topic as TopicMetadata; use RdKafka\Topic; use RdKafka\TopicConf; use RdKafka\TopicPartition; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts RdKafka related classes to array representation. * * @author Romain Neutron <imprec@gmail.com> */ class RdKafkaCaster { public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; try { $assignment = $c->getAssignment(); } catch (RdKafkaException $e) { $assignment = []; } $a += [ $prefix.'subscription' => $c->getSubscription(), $prefix.'assignment' => $assignment, ]; $a += self::extractMetadata($c); return $a; } public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'name' => $c->getName(), ]; return $a; } public static function castTopicPartition(TopicPartition $c, array $a) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'offset' => $c->getOffset(), $prefix.'partition' => $c->getPartition(), $prefix.'topic' => $c->getTopic(), ]; return $a; } public static function castMessage(Message $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'errstr' => $c->errstr(), ]; return $a; } public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; foreach ($c->dump() as $key => $value) { $a[$prefix.$key] = $value; } return $a; } public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; foreach ($c->dump() as $key => $value) { $a[$prefix.$key] = $value; } return $a; } public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'out_q_len' => $c->getOutQLen(), ]; $a += self::extractMetadata($c); return $a; } public static function castCollectionMetadata(CollectionMetadata $c, array $a, Stub $stub, bool $isNested) { $a += iterator_to_array($c); return $a; } public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'name' => $c->getTopic(), $prefix.'partitions' => $c->getPartitions(), ]; return $a; } public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'id' => $c->getId(), $prefix.'err' => $c->getErr(), $prefix.'leader' => $c->getLeader(), ]; return $a; } public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'id' => $c->getId(), $prefix.'host' => $c->getHost(), $prefix.'port' => $c->getPort(), ]; return $a; } private static function extractMetadata($c) { $prefix = Caster::PREFIX_VIRTUAL; try { $m = $c->getMetadata(true, null, 500); } catch (RdKafkaException $e) { return []; } return [ $prefix.'orig_broker_id' => $m->getOrigBrokerId(), $prefix.'orig_broker_name' => $m->getOrigBrokerName(), $prefix.'brokers' => $m->getBrokers(), $prefix.'topics' => $m->getTopics(), ]; } } Caster/UuidCaster.php 0000644 00000001234 15173250124 0010546 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Ramsey\Uuid\UuidInterface; use Symfony\Component\VarDumper\Cloner\Stub; /** * @author Grégoire Pineau <lyrixx@lyrixx.info> */ final class UuidCaster { public static function castRamseyUuid(UuidInterface $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'uuid' => (string) $c, ]; return $a; } } Caster/EnumStub.php 0000644 00000001175 15173250124 0010244 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Represents an enumeration of values. * * @author Nicolas Grekas <p@tchwork.com> */ class EnumStub extends Stub { public $dumpKeys = true; public function __construct(array $values, bool $dumpKeys = true) { $this->value = $values; $this->dumpKeys = $dumpKeys; } } Caster/SymfonyCaster.php 0000644 00000005312 15173250124 0011305 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Uid\Ulid; use Symfony\Component\Uid\Uuid; use Symfony\Component\VarDumper\Cloner\Stub; /** * @final */ class SymfonyCaster { private const REQUEST_GETTERS = [ 'pathInfo' => 'getPathInfo', 'requestUri' => 'getRequestUri', 'baseUrl' => 'getBaseUrl', 'basePath' => 'getBasePath', 'method' => 'getMethod', 'format' => 'getRequestFormat', ]; public static function castRequest(Request $request, array $a, Stub $stub, bool $isNested) { $clone = null; foreach (self::REQUEST_GETTERS as $prop => $getter) { $key = Caster::PREFIX_PROTECTED.$prop; if (\array_key_exists($key, $a) && null === $a[$key]) { if (null === $clone) { $clone = clone $request; } $a[Caster::PREFIX_VIRTUAL.$prop] = $clone->{$getter}(); } } return $a; } public static function castHttpClient($client, array $a, Stub $stub, bool $isNested) { $multiKey = sprintf("\0%s\0multi", \get_class($client)); if (isset($a[$multiKey])) { $a[$multiKey] = new CutStub($a[$multiKey]); } return $a; } public static function castHttpClientResponse($response, array $a, Stub $stub, bool $isNested) { $stub->cut += \count($a); $a = []; foreach ($response->getInfo() as $k => $v) { $a[Caster::PREFIX_VIRTUAL.$k] = $v; } return $a; } public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $uuid->toBase58(); $a[Caster::PREFIX_VIRTUAL.'toBase32'] = $uuid->toBase32(); // symfony/uid >= 5.3 if (method_exists($uuid, 'getDateTime')) { $a[Caster::PREFIX_VIRTUAL.'time'] = $uuid->getDateTime()->format('Y-m-d H:i:s.u \U\T\C'); } return $a; } public static function castUlid(Ulid $ulid, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $ulid->toBase58(); $a[Caster::PREFIX_VIRTUAL.'toRfc4122'] = $ulid->toRfc4122(); // symfony/uid >= 5.3 if (method_exists($ulid, 'getDateTime')) { $a[Caster::PREFIX_VIRTUAL.'time'] = $ulid->getDateTime()->format('Y-m-d H:i:s.v \U\T\C'); } return $a; } } Caster/GmpCaster.php 0000644 00000001355 15173250124 0010367 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts GMP objects to array representation. * * @author Hamza Amrouche <hamza.simperfit@gmail.com> * @author Nicolas Grekas <p@tchwork.com> * * @final */ class GmpCaster { public static function castGmp(\GMP $gmp, array $a, Stub $stub, bool $isNested, int $filter): array { $a[Caster::PREFIX_VIRTUAL.'value'] = new ConstStub(gmp_strval($gmp), gmp_strval($gmp)); return $a; } } Caster/ImgStub.php 0000644 00000001175 15173250124 0010054 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; /** * @author Grégoire Pineau <lyrixx@lyrixx.info> */ class ImgStub extends ConstStub { public function __construct(string $data, string $contentType, string $size = '') { $this->value = ''; $this->attr['img-data'] = $data; $this->attr['img-size'] = $size; $this->attr['content-type'] = $contentType; } } Caster/IntlCaster.php 0000644 00000021344 15173250124 0010552 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * @author Nicolas Grekas <p@tchwork.com> * @author Jan Schädlich <jan.schaedlich@sensiolabs.de> * * @final */ class IntlCaster { public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, bool $isNested) { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), ]; return self::castError($c, $a); } public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), ]; if ($filter & Caster::EXCLUDE_VERBOSE) { $stub->cut += 3; return self::castError($c, $a); } $a += [ Caster::PREFIX_VIRTUAL.'attributes' => new EnumStub( [ 'PARSE_INT_ONLY' => $c->getAttribute(\NumberFormatter::PARSE_INT_ONLY), 'GROUPING_USED' => $c->getAttribute(\NumberFormatter::GROUPING_USED), 'DECIMAL_ALWAYS_SHOWN' => $c->getAttribute(\NumberFormatter::DECIMAL_ALWAYS_SHOWN), 'MAX_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_INTEGER_DIGITS), 'MIN_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_INTEGER_DIGITS), 'INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::INTEGER_DIGITS), 'MAX_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_FRACTION_DIGITS), 'MIN_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_FRACTION_DIGITS), 'FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::FRACTION_DIGITS), 'MULTIPLIER' => $c->getAttribute(\NumberFormatter::MULTIPLIER), 'GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::GROUPING_SIZE), 'ROUNDING_MODE' => $c->getAttribute(\NumberFormatter::ROUNDING_MODE), 'ROUNDING_INCREMENT' => $c->getAttribute(\NumberFormatter::ROUNDING_INCREMENT), 'FORMAT_WIDTH' => $c->getAttribute(\NumberFormatter::FORMAT_WIDTH), 'PADDING_POSITION' => $c->getAttribute(\NumberFormatter::PADDING_POSITION), 'SECONDARY_GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::SECONDARY_GROUPING_SIZE), 'SIGNIFICANT_DIGITS_USED' => $c->getAttribute(\NumberFormatter::SIGNIFICANT_DIGITS_USED), 'MIN_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_SIGNIFICANT_DIGITS), 'MAX_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_SIGNIFICANT_DIGITS), 'LENIENT_PARSE' => $c->getAttribute(\NumberFormatter::LENIENT_PARSE), ] ), Caster::PREFIX_VIRTUAL.'text_attributes' => new EnumStub( [ 'POSITIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_PREFIX), 'POSITIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_SUFFIX), 'NEGATIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_PREFIX), 'NEGATIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_SUFFIX), 'PADDING_CHARACTER' => $c->getTextAttribute(\NumberFormatter::PADDING_CHARACTER), 'CURRENCY_CODE' => $c->getTextAttribute(\NumberFormatter::CURRENCY_CODE), 'DEFAULT_RULESET' => $c->getTextAttribute(\NumberFormatter::DEFAULT_RULESET), 'PUBLIC_RULESETS' => $c->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS), ] ), Caster::PREFIX_VIRTUAL.'symbols' => new EnumStub( [ 'DECIMAL_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL), 'GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL), 'PATTERN_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::PATTERN_SEPARATOR_SYMBOL), 'PERCENT_SYMBOL' => $c->getSymbol(\NumberFormatter::PERCENT_SYMBOL), 'ZERO_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::ZERO_DIGIT_SYMBOL), 'DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::DIGIT_SYMBOL), 'MINUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL), 'PLUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::PLUS_SIGN_SYMBOL), 'CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::CURRENCY_SYMBOL), 'INTL_CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::INTL_CURRENCY_SYMBOL), 'MONETARY_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL), 'EXPONENTIAL_SYMBOL' => $c->getSymbol(\NumberFormatter::EXPONENTIAL_SYMBOL), 'PERMILL_SYMBOL' => $c->getSymbol(\NumberFormatter::PERMILL_SYMBOL), 'PAD_ESCAPE_SYMBOL' => $c->getSymbol(\NumberFormatter::PAD_ESCAPE_SYMBOL), 'INFINITY_SYMBOL' => $c->getSymbol(\NumberFormatter::INFINITY_SYMBOL), 'NAN_SYMBOL' => $c->getSymbol(\NumberFormatter::NAN_SYMBOL), 'SIGNIFICANT_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL), 'MONETARY_GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL), ] ), ]; return self::castError($c, $a); } public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, bool $isNested) { $a += [ Caster::PREFIX_VIRTUAL.'display_name' => $c->getDisplayName(), Caster::PREFIX_VIRTUAL.'id' => $c->getID(), Caster::PREFIX_VIRTUAL.'raw_offset' => $c->getRawOffset(), ]; if ($c->useDaylightTime()) { $a += [ Caster::PREFIX_VIRTUAL.'dst_savings' => $c->getDSTSavings(), ]; } return self::castError($c, $a); } public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ Caster::PREFIX_VIRTUAL.'type' => $c->getType(), Caster::PREFIX_VIRTUAL.'first_day_of_week' => $c->getFirstDayOfWeek(), Caster::PREFIX_VIRTUAL.'minimal_days_in_first_week' => $c->getMinimalDaysInFirstWeek(), Caster::PREFIX_VIRTUAL.'repeated_wall_time_option' => $c->getRepeatedWallTimeOption(), Caster::PREFIX_VIRTUAL.'skipped_wall_time_option' => $c->getSkippedWallTimeOption(), Caster::PREFIX_VIRTUAL.'time' => $c->getTime(), Caster::PREFIX_VIRTUAL.'in_daylight_time' => $c->inDaylightTime(), Caster::PREFIX_VIRTUAL.'is_lenient' => $c->isLenient(), Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(), ]; return self::castError($c, $a); } public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), Caster::PREFIX_VIRTUAL.'calendar' => $c->getCalendar(), Caster::PREFIX_VIRTUAL.'time_zone_id' => $c->getTimeZoneId(), Caster::PREFIX_VIRTUAL.'time_type' => $c->getTimeType(), Caster::PREFIX_VIRTUAL.'date_type' => $c->getDateType(), Caster::PREFIX_VIRTUAL.'calendar_object' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getCalendarObject()) : $c->getCalendarObject(), Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(), ]; return self::castError($c, $a); } private static function castError(object $c, array $a): array { if ($errorCode = $c->getErrorCode()) { $a += [ Caster::PREFIX_VIRTUAL.'error_code' => $errorCode, Caster::PREFIX_VIRTUAL.'error_message' => $c->getErrorMessage(), ]; } return $a; } } Caster/ImagineCaster.php 0000644 00000001665 15173250124 0011221 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Imagine\Image\ImageInterface; use Symfony\Component\VarDumper\Cloner\Stub; /** * @author Grégoire Pineau <lyrixx@lyrixx.info> */ final class ImagineCaster { public static function castImage(ImageInterface $c, array $a, Stub $stub, bool $isNested): array { $imgData = $c->get('png'); if (\strlen($imgData) > 1 * 1000 * 1000) { $a += [ Caster::PREFIX_VIRTUAL.'image' => new ConstStub($c->getSize()), ]; } else { $a += [ Caster::PREFIX_VIRTUAL.'image' => new ImgStub($imgData, 'image/png', $c->getSize()), ]; } return $a; } } Caster/DateCaster.php 0000644 00000011432 15173250124 0010516 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts DateTimeInterface related classes to array representation. * * @author Dany Maillard <danymaillard93b@gmail.com> * * @final */ class DateCaster { private const PERIOD_LIMIT = 3; public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, bool $isNested, int $filter) { $prefix = Caster::PREFIX_VIRTUAL; $location = $d->getTimezone() ? $d->getTimezone()->getLocation() : null; $fromNow = (new \DateTime())->diff($d); $title = $d->format('l, F j, Y') ."\n".self::formatInterval($fromNow).' from now' .($location ? ($d->format('I') ? "\nDST On" : "\nDST Off") : '') ; unset( $a[Caster::PREFIX_DYNAMIC.'date'], $a[Caster::PREFIX_DYNAMIC.'timezone'], $a[Caster::PREFIX_DYNAMIC.'timezone_type'] ); $a[$prefix.'date'] = new ConstStub(self::formatDateTime($d, $location ? ' e (P)' : ' P'), $title); $stub->class .= $d->format(' @U'); return $a; } public static function castInterval(\DateInterval $interval, array $a, Stub $stub, bool $isNested, int $filter) { $now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC')); $numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp(); $title = number_format($numberOfSeconds, 0, '.', ' ').'s'; $i = [Caster::PREFIX_VIRTUAL.'interval' => new ConstStub(self::formatInterval($interval), $title)]; return $filter & Caster::EXCLUDE_VERBOSE ? $i : $i + $a; } private static function formatInterval(\DateInterval $i): string { $format = '%R '; if (0 === $i->y && 0 === $i->m && ($i->h >= 24 || $i->i >= 60 || $i->s >= 60)) { $d = new \DateTimeImmutable('@0', new \DateTimeZone('UTC')); $i = $d->diff($d->add($i)); // recalculate carry over points $format .= 0 < $i->days ? '%ad ' : ''; } else { $format .= ($i->y ? '%yy ' : '').($i->m ? '%mm ' : '').($i->d ? '%dd ' : ''); } $format .= $i->h || $i->i || $i->s || $i->f ? '%H:%I:'.self::formatSeconds($i->s, substr($i->f, 2)) : ''; $format = '%R ' === $format ? '0s' : $format; return $i->format(rtrim($format)); } public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, bool $isNested, int $filter) { $location = $timeZone->getLocation(); $formatted = (new \DateTime('now', $timeZone))->format($location ? 'e (P)' : 'P'); $title = $location && \extension_loaded('intl') ? \Locale::getDisplayRegion('-'.$location['country_code']) : ''; $z = [Caster::PREFIX_VIRTUAL.'timezone' => new ConstStub($formatted, $title)]; return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a; } public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $isNested, int $filter) { $dates = []; foreach (clone $p as $i => $d) { if (self::PERIOD_LIMIT === $i) { $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); $dates[] = sprintf('%s more', ($end = $p->getEndDate()) ? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u'))) : $p->recurrences - $i ); break; } $dates[] = sprintf('%s) %s', $i + 1, self::formatDateTime($d)); } $period = sprintf( 'every %s, from %s%s %s', self::formatInterval($p->getDateInterval()), $p->include_start_date ? '[' : ']', self::formatDateTime($p->getStartDate()), ($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).(\PHP_VERSION_ID >= 80200 && $p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s' ); $p = [Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates))]; return $filter & Caster::EXCLUDE_VERBOSE ? $p : $p + $a; } private static function formatDateTime(\DateTimeInterface $d, string $extra = ''): string { return $d->format('Y-m-d H:i:'.self::formatSeconds($d->format('s'), $d->format('u')).$extra); } private static function formatSeconds(string $s, string $us): string { return sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us)); } } Caster/AmqpCaster.php 0000644 00000015046 15173250124 0010544 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts Amqp related classes to array representation. * * @author Grégoire Pineau <lyrixx@lyrixx.info> * * @final */ class AmqpCaster { private const FLAGS = [ \AMQP_DURABLE => 'AMQP_DURABLE', \AMQP_PASSIVE => 'AMQP_PASSIVE', \AMQP_EXCLUSIVE => 'AMQP_EXCLUSIVE', \AMQP_AUTODELETE => 'AMQP_AUTODELETE', \AMQP_INTERNAL => 'AMQP_INTERNAL', \AMQP_NOLOCAL => 'AMQP_NOLOCAL', \AMQP_AUTOACK => 'AMQP_AUTOACK', \AMQP_IFEMPTY => 'AMQP_IFEMPTY', \AMQP_IFUNUSED => 'AMQP_IFUNUSED', \AMQP_MANDATORY => 'AMQP_MANDATORY', \AMQP_IMMEDIATE => 'AMQP_IMMEDIATE', \AMQP_MULTIPLE => 'AMQP_MULTIPLE', \AMQP_NOWAIT => 'AMQP_NOWAIT', \AMQP_REQUEUE => 'AMQP_REQUEUE', ]; private const EXCHANGE_TYPES = [ \AMQP_EX_TYPE_DIRECT => 'AMQP_EX_TYPE_DIRECT', \AMQP_EX_TYPE_FANOUT => 'AMQP_EX_TYPE_FANOUT', \AMQP_EX_TYPE_TOPIC => 'AMQP_EX_TYPE_TOPIC', \AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS', ]; public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'is_connected' => $c->isConnected(), ]; // Recent version of the extension already expose private properties if (isset($a["\x00AMQPConnection\x00login"])) { return $a; } // BC layer in the amqp lib if (method_exists($c, 'getReadTimeout')) { $timeout = $c->getReadTimeout(); } else { $timeout = $c->getTimeout(); } $a += [ $prefix.'is_connected' => $c->isConnected(), $prefix.'login' => $c->getLogin(), $prefix.'password' => $c->getPassword(), $prefix.'host' => $c->getHost(), $prefix.'vhost' => $c->getVhost(), $prefix.'port' => $c->getPort(), $prefix.'read_timeout' => $timeout, ]; return $a; } public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'is_connected' => $c->isConnected(), $prefix.'channel_id' => $c->getChannelId(), ]; // Recent version of the extension already expose private properties if (isset($a["\x00AMQPChannel\x00connection"])) { return $a; } $a += [ $prefix.'connection' => $c->getConnection(), $prefix.'prefetch_size' => $c->getPrefetchSize(), $prefix.'prefetch_count' => $c->getPrefetchCount(), ]; return $a; } public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'flags' => self::extractFlags($c->getFlags()), ]; // Recent version of the extension already expose private properties if (isset($a["\x00AMQPQueue\x00name"])) { return $a; } $a += [ $prefix.'connection' => $c->getConnection(), $prefix.'channel' => $c->getChannel(), $prefix.'name' => $c->getName(), $prefix.'arguments' => $c->getArguments(), ]; return $a; } public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; $a += [ $prefix.'flags' => self::extractFlags($c->getFlags()), ]; $type = isset(self::EXCHANGE_TYPES[$c->getType()]) ? new ConstStub(self::EXCHANGE_TYPES[$c->getType()], $c->getType()) : $c->getType(); // Recent version of the extension already expose private properties if (isset($a["\x00AMQPExchange\x00name"])) { $a["\x00AMQPExchange\x00type"] = $type; return $a; } $a += [ $prefix.'connection' => $c->getConnection(), $prefix.'channel' => $c->getChannel(), $prefix.'name' => $c->getName(), $prefix.'type' => $type, $prefix.'arguments' => $c->getArguments(), ]; return $a; } public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; $deliveryMode = new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode()); // Recent version of the extension already expose private properties if (isset($a["\x00AMQPEnvelope\x00body"])) { $a["\0AMQPEnvelope\0delivery_mode"] = $deliveryMode; return $a; } if (!($filter & Caster::EXCLUDE_VERBOSE)) { $a += [$prefix.'body' => $c->getBody()]; } $a += [ $prefix.'delivery_tag' => $c->getDeliveryTag(), $prefix.'is_redelivery' => $c->isRedelivery(), $prefix.'exchange_name' => $c->getExchangeName(), $prefix.'routing_key' => $c->getRoutingKey(), $prefix.'content_type' => $c->getContentType(), $prefix.'content_encoding' => $c->getContentEncoding(), $prefix.'headers' => $c->getHeaders(), $prefix.'delivery_mode' => $deliveryMode, $prefix.'priority' => $c->getPriority(), $prefix.'correlation_id' => $c->getCorrelationId(), $prefix.'reply_to' => $c->getReplyTo(), $prefix.'expiration' => $c->getExpiration(), $prefix.'message_id' => $c->getMessageId(), $prefix.'timestamp' => $c->getTimeStamp(), $prefix.'type' => $c->getType(), $prefix.'user_id' => $c->getUserId(), $prefix.'app_id' => $c->getAppId(), ]; return $a; } private static function extractFlags(int $flags): ConstStub { $flagsArray = []; foreach (self::FLAGS as $value => $name) { if ($flags & $value) { $flagsArray[] = $name; } } if (!$flagsArray) { $flagsArray = ['AMQP_NOPARAM']; } return new ConstStub(implode('|', $flagsArray), $flags); } } Caster/ClassStub.php 0000644 00000007371 15173250124 0010411 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Represents a PHP class identifier. * * @author Nicolas Grekas <p@tchwork.com> */ class ClassStub extends ConstStub { /** * @param string $identifier A PHP identifier, e.g. a class, method, interface, etc. name * @param callable $callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier */ public function __construct(string $identifier, $callable = null) { $this->value = $identifier; try { if (null !== $callable) { if ($callable instanceof \Closure) { $r = new \ReflectionFunction($callable); } elseif (\is_object($callable)) { $r = [$callable, '__invoke']; } elseif (\is_array($callable)) { $r = $callable; } elseif (false !== $i = strpos($callable, '::')) { $r = [substr($callable, 0, $i), substr($callable, 2 + $i)]; } else { $r = new \ReflectionFunction($callable); } } elseif (0 < $i = strpos($identifier, '::') ?: strpos($identifier, '->')) { $r = [substr($identifier, 0, $i), substr($identifier, 2 + $i)]; } else { $r = new \ReflectionClass($identifier); } if (\is_array($r)) { try { $r = new \ReflectionMethod($r[0], $r[1]); } catch (\ReflectionException $e) { $r = new \ReflectionClass($r[0]); } } if (str_contains($identifier, "@anonymous\0")) { $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; }, $identifier); } if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) { $s = ReflectionCaster::castFunctionAbstract($r, [], new Stub(), true, Caster::EXCLUDE_VERBOSE); $s = ReflectionCaster::getSignature($s); if (str_ends_with($identifier, '()')) { $this->value = substr_replace($identifier, $s, -2); } else { $this->value .= $s; } } } catch (\ReflectionException $e) { return; } finally { if (0 < $i = strrpos($this->value, '\\')) { $this->attr['ellipsis'] = \strlen($this->value) - $i; $this->attr['ellipsis-type'] = 'class'; $this->attr['ellipsis-tail'] = 1; } } if ($f = $r->getFileName()) { $this->attr['file'] = $f; $this->attr['line'] = $r->getStartLine(); } } public static function wrapCallable($callable) { if (\is_object($callable) || !\is_callable($callable)) { return $callable; } if (!\is_array($callable)) { $callable = new static($callable, $callable); } elseif (\is_string($callable[0])) { $callable[0] = new static($callable[0], $callable); } else { $callable[1] = new static($callable[1], $callable); } return $callable; } } Caster/XmlReaderCaster.php 0000644 00000006351 15173250124 0011530 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Casts XmlReader class to array representation. * * @author Baptiste Clavié <clavie.b@gmail.com> * * @final */ class XmlReaderCaster { private const NODE_TYPES = [ \XMLReader::NONE => 'NONE', \XMLReader::ELEMENT => 'ELEMENT', \XMLReader::ATTRIBUTE => 'ATTRIBUTE', \XMLReader::TEXT => 'TEXT', \XMLReader::CDATA => 'CDATA', \XMLReader::ENTITY_REF => 'ENTITY_REF', \XMLReader::ENTITY => 'ENTITY', \XMLReader::PI => 'PI (Processing Instruction)', \XMLReader::COMMENT => 'COMMENT', \XMLReader::DOC => 'DOC', \XMLReader::DOC_TYPE => 'DOC_TYPE', \XMLReader::DOC_FRAGMENT => 'DOC_FRAGMENT', \XMLReader::NOTATION => 'NOTATION', \XMLReader::WHITESPACE => 'WHITESPACE', \XMLReader::SIGNIFICANT_WHITESPACE => 'SIGNIFICANT_WHITESPACE', \XMLReader::END_ELEMENT => 'END_ELEMENT', \XMLReader::END_ENTITY => 'END_ENTITY', \XMLReader::XML_DECLARATION => 'XML_DECLARATION', ]; public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, bool $isNested) { try { $properties = [ 'LOADDTD' => @$reader->getParserProperty(\XMLReader::LOADDTD), 'DEFAULTATTRS' => @$reader->getParserProperty(\XMLReader::DEFAULTATTRS), 'VALIDATE' => @$reader->getParserProperty(\XMLReader::VALIDATE), 'SUBST_ENTITIES' => @$reader->getParserProperty(\XMLReader::SUBST_ENTITIES), ]; } catch (\Error $e) { $properties = [ 'LOADDTD' => false, 'DEFAULTATTRS' => false, 'VALIDATE' => false, 'SUBST_ENTITIES' => false, ]; } $props = Caster::PREFIX_VIRTUAL.'parserProperties'; $info = [ 'localName' => $reader->localName, 'prefix' => $reader->prefix, 'nodeType' => new ConstStub(self::NODE_TYPES[$reader->nodeType], $reader->nodeType), 'depth' => $reader->depth, 'isDefault' => $reader->isDefault, 'isEmptyElement' => \XMLReader::NONE === $reader->nodeType ? null : $reader->isEmptyElement, 'xmlLang' => $reader->xmlLang, 'attributeCount' => $reader->attributeCount, 'value' => $reader->value, 'namespaceURI' => $reader->namespaceURI, 'baseURI' => $reader->baseURI ? new LinkStub($reader->baseURI) : $reader->baseURI, $props => $properties, ]; if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, [], $count)) { $info[$props] = new EnumStub($info[$props]); $info[$props]->cut = $count; } $info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count); // +2 because hasValue and hasAttributes are always filtered $stub->cut += $count + 2; return $a + $info; } } Caster/ArgsStub.php 0000644 00000004367 15173250124 0010242 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Caster; use Symfony\Component\VarDumper\Cloner\Stub; /** * Represents a list of function arguments. * * @author Nicolas Grekas <p@tchwork.com> */ class ArgsStub extends EnumStub { private static $parameters = []; public function __construct(array $args, string $function, ?string $class) { [$variadic, $params] = self::getParameters($function, $class); $values = []; foreach ($args as $k => $v) { $values[$k] = !\is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v; } if (null === $params) { parent::__construct($values, false); return; } if (\count($values) < \count($params)) { $params = \array_slice($params, 0, \count($values)); } elseif (\count($values) > \count($params)) { $values[] = new EnumStub(array_splice($values, \count($params)), false); $params[] = $variadic; } if (['...'] === $params) { $this->dumpKeys = false; $this->value = $values[0]->value; } else { $this->value = array_combine($params, $values); } } private static function getParameters(string $function, ?string $class): array { if (isset(self::$parameters[$k = $class.'::'.$function])) { return self::$parameters[$k]; } try { $r = null !== $class ? new \ReflectionMethod($class, $function) : new \ReflectionFunction($function); } catch (\ReflectionException $e) { return [null, null]; } $variadic = '...'; $params = []; foreach ($r->getParameters() as $v) { $k = '$'.$v->name; if ($v->isPassedByReference()) { $k = '&'.$k; } if ($v->isVariadic()) { $variadic .= $k; } else { $params[] = $k; } } return self::$parameters[$k] = [$variadic, $params]; } } Exception/ThrowingCasterException.php 0000644 00000001217 15173250124 0014036 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\VarDumper\Exception; /** * @author Nicolas Grekas <p@tchwork.com> */ class ThrowingCasterException extends \Exception { /** * @param \Throwable $prev The exception thrown from the caster */ public function __construct(\Throwable $prev) { parent::__construct('Unexpected '.\get_class($prev).' thrown from a caster: '.$prev->getMessage(), 0, $prev); } } Resources/bin/var-dump-server 0000644 00000004136 15173250124 0012254 0 ustar 00 #!/usr/bin/env php <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if ('cli' !== PHP_SAPI) { throw new Exception('This script must be run from the command line.'); } /** * Starts a dump server to collect and output dumps on a single place with multiple formats support. * * @author Maxime Steinhausser <maxime.steinhausser@gmail.com> */ use Psr\Log\LoggerInterface; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Logger\ConsoleLogger; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\VarDumper\Command\ServerDumpCommand; use Symfony\Component\VarDumper\Server\DumpServer; function includeIfExists(string $file): bool { return file_exists($file) && include $file; } if ( !includeIfExists(__DIR__ . '/../../../../autoload.php') && !includeIfExists(__DIR__ . '/../../vendor/autoload.php') && !includeIfExists(__DIR__ . '/../../../../../../vendor/autoload.php') ) { fwrite(STDERR, 'Install dependencies using Composer.'.PHP_EOL); exit(1); } if (!class_exists(Application::class)) { fwrite(STDERR, 'You need the "symfony/console" component in order to run the VarDumper server.'.PHP_EOL); exit(1); } $input = new ArgvInput(); $output = new ConsoleOutput(); $defaultHost = '127.0.0.1:9912'; $host = $input->getParameterOption(['--host'], $_SERVER['VAR_DUMPER_SERVER'] ?? $defaultHost, true); $logger = interface_exists(LoggerInterface::class) ? new ConsoleLogger($output->getErrorOutput()) : null; $app = new Application(); $app->getDefinition()->addOption( new InputOption('--host', null, InputOption::VALUE_REQUIRED, 'The address the server should listen to', $defaultHost) ); $app->add($command = new ServerDumpCommand(new DumpServer($host, $logger))) ->getApplication() ->setDefaultCommand($command->getName(), true) ->run($input, $output) ; Resources/functions/dump.php 0000644 00000001741 15173250124 0012207 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Component\VarDumper\VarDumper; if (!function_exists('dump')) { /** * @author Nicolas Grekas <p@tchwork.com> */ function dump($var, ...$moreVars) { VarDumper::dump($var); foreach ($moreVars as $v) { VarDumper::dump($v); } if (1 < func_num_args()) { return func_get_args(); } return $var; } } if (!function_exists('dd')) { /** * @return never */ function dd(...$vars) { if (!in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !headers_sent()) { header('HTTP/1.1 500 Internal Server Error'); } foreach ($vars as $v) { VarDumper::dump($v); } exit(1); } } Resources/css/htmlDescriptor.css 0000644 00000005702 15173250124 0013027 0 ustar 00 body { display: flex; flex-direction: column-reverse; justify-content: flex-end; max-width: 1140px; margin: auto; padding: 15px; word-wrap: break-word; background-color: #F9F9F9; color: #222; font-family: Helvetica, Arial, sans-serif; font-size: 14px; line-height: 1.4; } p { margin: 0; } a { color: #218BC3; text-decoration: none; } a:hover { text-decoration: underline; } .text-small { font-size: 12px !important; } article { margin: 5px; margin-bottom: 10px; } article > header > .row { display: flex; flex-direction: row; align-items: baseline; margin-bottom: 10px; } article > header > .row > .col { flex: 1; display: flex; align-items: baseline; } article > header > .row > h2 { font-size: 14px; color: #222; font-weight: normal; font-family: "Lucida Console", monospace, sans-serif; word-break: break-all; margin: 20px 5px 0 0; user-select: all; } article > header > .row > h2 > code { white-space: nowrap; user-select: none; color: #cc2255; background-color: #f7f7f9; border: 1px solid #e1e1e8; border-radius: 3px; margin-right: 5px; padding: 0 3px; } article > header > .row > time.col { flex: 0; text-align: right; white-space: nowrap; color: #999; font-style: italic; } article > header ul.tags { list-style: none; padding: 0; margin: 0; font-size: 12px; } article > header ul.tags > li { user-select: all; margin-bottom: 2px; } article > header ul.tags > li > span.badge { display: inline-block; padding: .25em .4em; margin-right: 5px; border-radius: 4px; background-color: #6c757d3b; color: #524d4d; font-size: 12px; text-align: center; font-weight: 700; line-height: 1; white-space: nowrap; vertical-align: baseline; user-select: none; } article > section.body { border: 1px solid #d8d8d8; background: #FFF; padding: 10px; border-radius: 3px; } pre.sf-dump { border-radius: 3px; margin-bottom: 0; } .hidden { display: none !important; } .dumped-tag > .sf-dump { display: inline-block; margin: 0; padding: 1px 5px; line-height: 1.4; vertical-align: top; background-color: transparent; user-select: auto; } .dumped-tag > pre.sf-dump, .dumped-tag > .sf-dump-default { color: #CC7832; background: none; } .dumped-tag > .sf-dump .sf-dump-str { color: #629755; } .dumped-tag > .sf-dump .sf-dump-private, .dumped-tag > .sf-dump .sf-dump-protected, .dumped-tag > .sf-dump .sf-dump-public { color: #262626; } .dumped-tag > .sf-dump .sf-dump-note { color: #6897BB; } .dumped-tag > .sf-dump .sf-dump-key { color: #789339; } .dumped-tag > .sf-dump .sf-dump-ref { color: #6E6E6E; } .dumped-tag > .sf-dump .sf-dump-ellipsis { color: #CC7832; max-width: 100em; } .dumped-tag > .sf-dump .sf-dump-ellipsis-path { max-width: 5em; } .dumped-tag > .sf-dump .sf-dump-ns { user-select: none; } Resources/js/htmlDescriptor.js 0000644 00000000542 15173250124 0012474 0 ustar 00 document.addEventListener('DOMContentLoaded', function() { let prev = null; Array.from(document.getElementsByTagName('article')).reverse().forEach(function (article) { const dedupId = article.dataset.dedupId; if (dedupId === prev) { article.getElementsByTagName('header')[0].classList.add('hidden'); } prev = dedupId; }); }); LICENSE 0000644 00000002054 15173250124 0005552 0 ustar 00 Copyright (c) 2014-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0 |
proxy
|
phpinfo
|
Settings