Repository: symfony/symfony
File: src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php (PHP)

Code before:
 */

namespace Symfony\Component\HtmlSanitizer;

use Symfony\Component\HtmlSanitizer\Parser\MastermindsParser;
use Symfony\Component\HtmlSanitizer\Parser\NativeParser;
use Symfony\Component\HtmlSanitizer\Parser\ParserInterface;
use Symfony\Component\HtmlSanitizer\Reference\W3CReference;
use Symfony\Component\HtmlSanitizer\TextSanitizer\StringSanitizer;
use Symfony\Component\HtmlSanitizer\Visitor\DomVisitor;

/**
 * @author Titouan Galopin <galopintitouan@gmail.com>
 */
final class HtmlSanitizer implements HtmlSanitizerInterface
{
    private ParserInterface $parser;

    /**
     * @var array<string, DomVisitor>
     */
    private array $domVisitors = [];

    /**
     * @param \Closure(string):\Dom\Node|\DOMNode|null $parser
     */
    public function __construct(
        private HtmlSanitizerConfig $config,
        ?ParserInterface $parser = null,
    ) {
        $this->config = $config;
        $this->parser = $parser ?? (\PHP_VERSION_ID < 80400 ? new MastermindsParser() : new NativeParser());
    }

    public function sanitize(string $input): string
    {
        return $this->sanitizeFor(W3CReference::CONTEXT_BODY, $input);
    }

    public function sanitizeFor(string $element, string $input): string
    {
        $element = StringSanitizer::htmlLower($element);
        $context = W3CReference::CONTEXTS_MAP[$element] ?? W3CReference::CONTEXT_BODY;
        $element = isset(W3CReference::BODY_ELEMENTS[$element]) ? $element : $context;

        // Text context: early return with HTML encoding
        if (W3CReference::CONTEXT_TEXT === $context) {
            return StringSanitizer::encodeHtmlEntities($input);
        }

        // Other context: build a DOM visitor

Review comment (suggestion):
```suggestion
        HtmlParserInterface|ParserInterface|null $parser = null,
```

Code after:
 */

namespace Symfony\Component\HtmlSanitizer;

use Symfony\Component\HtmlSanitizer\Parser\MastermindsParser;
use Symfony\Component\HtmlSanitizer\Parser\NativeParser;
use Symfony\Component\HtmlSanitizer\Parser\ParserInterface;
use Symfony\Component\HtmlSanitizer\Reference\W3CReference;
use Symfony\Component\HtmlSanitizer\TextSanitizer\StringSanitizer;
use Symfony\Component\HtmlSanitizer\Visitor\DomVisitor;

/**
 * @author Titouan Galopin <galopintitouan@gmail.com>
 */
final class HtmlSanitizer implements HtmlSanitizerInterface
{
    private ParserInterface $parser;

    /**
     * @var array<string, DomVisitor>
     */
    private array $domVisitors = [];

    public function __construct(
        private HtmlSanitizerConfig $config,
        ?ParserInterface $parser = null,
    ) {
        $this->config = $config;
        $this->parser = $parser ?? (\PHP_VERSION_ID < 80400 ? new MastermindsParser() : new NativeParser());
    }

    public function sanitize(string $input): string
    {
        return $this->sanitizeFor(W3CReference::CONTEXT_BODY, $input);
    }

    public function sanitizeFor(string $element, string $input): string
    {
        $element = StringSanitizer::htmlLower($element);
        $context = W3CReference::CONTEXTS_MAP[$element] ?? W3CReference::CONTEXT_BODY;
        $element = isset(W3CReference::BODY_ELEMENTS[$element]) ? $element : $context;

        // Text context: early return with HTML encoding
        if (W3CReference::CONTEXT_TEXT === $context) {
            return StringSanitizer::encodeHtmlEntities($input);
        }

        // Other context: build a DOM visitor
        $this->domVisitors[$context] ??= $this->createDomVisitorForContext($context);

        // Prevent DOS attack induced by extremely long HTML strings