* * 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
*/ 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 = '
';
    protected $dumpSuffix = '';
    protected $dumpId = 'sf-dump';
    protected $colors = true;
    protected $headerIsDumped = false;
    protected $lastDepth = -1;
    protected $styles;
    private array $displayOptions = [
        'maxDepth' => 1,
        'maxStringLength' => 160,
        'fileLinkFormat' => null,
    ];
    private array $extraDisplayOptions = [];
    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'];
    }
    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;
    }
    public function dump(Data $data, $output = null, array $extraDisplayOptions = []): ?string
    {
        $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'
'.$this->dumpHeader;
    }
    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'] ? ' ' : ' ';
            $this->endValue($cursor);
            $this->line .= $this->indentPad;
            $this->line .= sprintf('%s', esc($attr['lang']), $v);
        }
        return $v;
    }
    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');
}