103 | // then IE8 will produce:
104 | //
105 | // as the value of nodeB.innerHTML and assign it to nodeA.
106 | // IE8's HTML parser treats `` as a blank attribute value and foo=bar becomes a separate attribute.
107 | // Adding a space at the end of the attribute prevents this by forcing IE8 to put double
108 | // quotes around the attribute when computing nodeB.innerHTML.
109 | if (str_contains($value, '`')) {
110 | $value .= ' ';
111 | }
112 |
113 | $attr .= '="'.StringSanitizer::encodeHtmlEntities($value).'"';
114 | }
115 |
116 | $rendered[] = $attr;
117 | }
118 |
119 | return $rendered ? ' '.implode(' ', $rendered) : '';
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/Visitor/Node/NodeInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Symfony\Component\HtmlSanitizer\Visitor\Node;
13 |
14 | /**
15 | * Represents the sanitized version of a DOM node in the sanitized tree.
16 | *
17 | * Once the sanitization is done, nodes are rendered into the final output string.
18 | *
19 | * @author Titouan Galopin
20 | */
21 | interface NodeInterface
22 | {
23 | /**
24 | * Add a child node to this node.
25 | */
26 | public function addChild(self $node): void;
27 |
28 | /**
29 | * Return the parent node of this node, or null if it has no parent node.
30 | */
31 | public function getParent(): ?self;
32 |
33 | /**
34 | * Render this node as a string, recursively rendering its children as well.
35 | */
36 | public function render(): string;
37 | }
38 |
--------------------------------------------------------------------------------
/Visitor/Node/TextNode.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Symfony\Component\HtmlSanitizer\Visitor\Node;
13 |
14 | use Symfony\Component\HtmlSanitizer\TextSanitizer\StringSanitizer;
15 |
16 | /**
17 | * @author Titouan Galopin
18 | */
19 | final class TextNode implements NodeInterface
20 | {
21 | public function __construct(private NodeInterface $parentNode, private string $text)
22 | {
23 | }
24 |
25 | public function addChild(NodeInterface $node): void
26 | {
27 | throw new \LogicException('Text nodes cannot have children.');
28 | }
29 |
30 | public function getParent(): ?NodeInterface
31 | {
32 | return $this->parentNode;
33 | }
34 |
35 | public function render(): string
36 | {
37 | return StringSanitizer::encodeHtmlEntities($this->text);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "symfony/html-sanitizer",
3 | "type": "library",
4 | "description": "Provides an object-oriented API to sanitize untrusted HTML input for safe insertion into a document's DOM.",
5 | "keywords": ["html", "sanitizer", "purifier"],
6 | "homepage": "https://symfony.com",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Titouan Galopin",
11 | "email": "galopintitouan@gmail.com"
12 | },
13 | {
14 | "name": "Symfony Community",
15 | "homepage": "https://symfony.com/contributors"
16 | }
17 | ],
18 | "require": {
19 | "php": ">=8.2",
20 | "ext-dom": "*",
21 | "league/uri": "^6.5|^7.0",
22 | "masterminds/html5": "^2.7.2"
23 | },
24 | "autoload": {
25 | "psr-4": { "Symfony\\Component\\HtmlSanitizer\\": "" },
26 | "exclude-from-classmap": [
27 | "/Tests/"
28 | ]
29 | },
30 | "minimum-stability": "dev"
31 | }
32 |
--------------------------------------------------------------------------------