Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit98f511e

Browse files
committed
feature#57399 [HtmlSanitizer] Add support for configuring the default action (Seldaek)
This PR was merged into the 7.2 branch.Discussion----------[HtmlSanitizer] Add support for configuring the default action| Q | A| ------------- | ---| Branch? | 7.2| Bug fix? | no| New feature? | yes| Deprecations? | no| Issues |Fix#48358| License | MITThe default action can be set to block or allow unconfigured elements instead of dropping themKinda replaces#49920 but it would need some work on the configuration handling side to allow configuring default actions. I am just using this as a library so I am not so keen on doing that part sorry but maybe `@Neirda24` might want to take care of it if this PR gets accepted.Commits-------4fd1c4c [HtmlSanitizer] Add support for configuring the default action to block or allow unconfigured elements instead of dropping them
2 parents837bcc5 +4fd1c4c commit98f511e

File tree

6 files changed

+150
-24
lines changed

6 files changed

+150
-24
lines changed

‎src/Symfony/Component/HtmlSanitizer/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.2
5+
---
6+
7+
* Add support for configuring the default action to block or allow unconfigured elements instead of dropping them
8+
49
6.4
510
---
611

‎src/Symfony/Component/HtmlSanitizer/HtmlSanitizer.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ private function createDomVisitorForContext(string $context): DomVisitor
103103

104104
foreach ($this->config->getBlockedElements()as$blockedElement =>$v) {
105105
if (\array_key_exists($blockedElement, W3CReference::HEAD_ELEMENTS)) {
106-
$elementsConfig[$blockedElement] =false;
106+
$elementsConfig[$blockedElement] = HtmlSanitizerAction::Block;
107+
}
108+
}
109+
110+
foreach ($this->config->getDroppedElements()as$droppedElement =>$v) {
111+
if (\array_key_exists($droppedElement, W3CReference::HEAD_ELEMENTS)) {
112+
$elementsConfig[$droppedElement] = HtmlSanitizerAction::Drop;
107113
}
108114
}
109115

@@ -119,7 +125,13 @@ private function createDomVisitorForContext(string $context): DomVisitor
119125

120126
foreach ($this->config->getBlockedElements()as$blockedElement =>$v) {
121127
if (!\array_key_exists($blockedElement, W3CReference::HEAD_ELEMENTS)) {
122-
$elementsConfig[$blockedElement] =false;
128+
$elementsConfig[$blockedElement] = HtmlSanitizerAction::Block;
129+
}
130+
}
131+
132+
foreach ($this->config->getDroppedElements()as$droppedElement =>$v) {
133+
if (!\array_key_exists($droppedElement, W3CReference::HEAD_ELEMENTS)) {
134+
$elementsConfig[$droppedElement] = HtmlSanitizerAction::Drop;
123135
}
124136
}
125137

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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+
namespaceSymfony\Component\HtmlSanitizer;
13+
14+
enum HtmlSanitizerAction:string
15+
{
16+
/**
17+
* Dropped elements are elements the sanitizer should remove from the input, including their children.
18+
*/
19+
case Drop ='drop';
20+
21+
/**
22+
* Blocked elements are elements the sanitizer should remove from the input, but retain their children.
23+
*/
24+
case Block ='block';
25+
26+
/**
27+
* Allowed elements are elements the sanitizer should retain from the input.
28+
*/
29+
case Allow ='allow';
30+
}

‎src/Symfony/Component/HtmlSanitizer/HtmlSanitizerConfig.php

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@
1919
*/
2020
class HtmlSanitizerConfig
2121
{
22+
privateHtmlSanitizerAction$defaultAction = HtmlSanitizerAction::Drop;
23+
24+
/**
25+
* Elements that should be removed.
26+
*
27+
* @var array<string, true>
28+
*/
29+
privatearray$droppedElements = [];
30+
2231
/**
2332
* Elements that should be removed but their children should be retained.
2433
*
@@ -99,6 +108,19 @@ public function __construct()
99108
];
100109
}
101110

111+
/**
112+
* Sets the default action for elements which are not otherwise specifically allowed or blocked.
113+
*
114+
* Note that a default action of Allow will allow all tags but they will not have any attributes.
115+
*/
116+
publicfunctiondefaultAction(HtmlSanitizerAction$action):static
117+
{
118+
$clone =clone$this;
119+
$clone->defaultAction =$action;
120+
121+
return$clone;
122+
}
123+
102124
/**
103125
* Allows all static elements and attributes from the W3C Sanitizer API standard.
104126
*
@@ -261,8 +283,8 @@ public function allowElement(string $element, array|string $allowedAttributes =
261283
{
262284
$clone =clone$this;
263285

264-
// Unblock the elementis necessary
265-
unset($clone->blockedElements[$element]);
286+
// Unblock/undrop the elementif necessary
287+
unset($clone->blockedElements[$element],$clone->droppedElements[$element]);
266288

267289
$clone->allowedElements[$element] = [];
268290

@@ -284,8 +306,8 @@ public function blockElement(string $element): static
284306
{
285307
$clone =clone$this;
286308

287-
// Disallow the elementis necessary
288-
unset($clone->allowedElements[$element]);
309+
// Disallow/undrop the elementif necessary
310+
unset($clone->allowedElements[$element],$clone->droppedElements[$element]);
289311

290312
$clone->blockedElements[$element] =true;
291313

@@ -300,13 +322,15 @@ public function blockElement(string $element): static
300322
*
301323
* Note: when using an empty configuration, all unknown elements are dropped
302324
* automatically. This method let you drop elements that were allowed earlier
303-
* in the configuration.
325+
* in the configuration, or explicitly drop some if you changed the default action.
304326
*/
305327
publicfunctiondropElement(string$element):static
306328
{
307329
$clone =clone$this;
308330
unset($clone->allowedElements[$element],$clone->blockedElements[$element]);
309331

332+
$clone->droppedElements[$element] =true;
333+
310334
return$clone;
311335
}
312336

@@ -426,6 +450,11 @@ public function getMaxInputLength(): int
426450
return$this->maxInputLength;
427451
}
428452

453+
publicfunctiongetDefaultAction():HtmlSanitizerAction
454+
{
455+
return$this->defaultAction;
456+
}
457+
429458
/**
430459
* @return array<string, array<string, true>>
431460
*/
@@ -442,6 +471,14 @@ public function getBlockedElements(): array
442471
return$this->blockedElements;
443472
}
444473

474+
/**
475+
* @return array<string, true>
476+
*/
477+
publicfunctiongetDroppedElements():array
478+
{
479+
return$this->droppedElements;
480+
}
481+
445482
/**
446483
* @return array<string, array<string, string>>
447484
*/

‎src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerAllTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
usePHPUnit\Framework\TestCase;
1515
useSymfony\Component\HtmlSanitizer\HtmlSanitizer;
16+
useSymfony\Component\HtmlSanitizer\HtmlSanitizerAction;
1617
useSymfony\Component\HtmlSanitizer\HtmlSanitizerConfig;
1718

1819
class HtmlSanitizerAllTestextends TestCase
@@ -578,4 +579,25 @@ public function testUnlimitedLength()
578579

579580
$this->assertSame(\strlen($input),\strlen($sanitized));
580581
}
582+
583+
publicfunctiontestBlockByDefault()
584+
{
585+
$config = (newHtmlSanitizerConfig())
586+
->defaultAction(HtmlSanitizerAction::Block)
587+
->allowElement('p');
588+
589+
$sanitizer =newHtmlSanitizer($config);
590+
self::assertSame('<p>Hello</p>',$sanitizer->sanitize('<foo><div><p><a target="_blank">Hello</a></p></div></foo>'));
591+
}
592+
593+
publicfunctiontestAllowByDefault()
594+
{
595+
$config = (newHtmlSanitizerConfig())
596+
->defaultAction(HtmlSanitizerAction::Allow)
597+
->allowElement('p')
598+
->dropElement('span');
599+
600+
$sanitizer =newHtmlSanitizer($config);
601+
self::assertSame('<foo><div><p><a>Hello</a></p></div></foo>',$sanitizer->sanitize('<foo data-attr="value"><div class="foo"><p><a target="_blank">Hello<span> World</span></a></p></div></foo>'));
602+
}
581603
}

‎src/Symfony/Component/HtmlSanitizer/Visitor/DomVisitor.php

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespaceSymfony\Component\HtmlSanitizer\Visitor;
1313

14+
useSymfony\Component\HtmlSanitizer\HtmlSanitizerAction;
1415
useSymfony\Component\HtmlSanitizer\HtmlSanitizerConfig;
1516
useSymfony\Component\HtmlSanitizer\TextSanitizer\StringSanitizer;
1617
useSymfony\Component\HtmlSanitizer\Visitor\AttributeSanitizer\AttributeSanitizerInterface;
@@ -33,6 +34,8 @@
3334
*/
3435
finalclass DomVisitor
3536
{
37+
privateHtmlSanitizerAction$defaultAction = HtmlSanitizerAction::Drop;
38+
3639
/**
3740
* Registry of attributes to forcefully set on nodes, index by element and attribute.
3841
*
@@ -49,11 +52,11 @@ final class DomVisitor
4952
privatearray$attributeSanitizers = [];
5053

5154
/**
52-
* @param array<string,false|array<string, bool>> $elementsConfig Registry of allowed/blocked elements:
53-
* * If an element is present as a key and contains an array, the element should be allowed
54-
* and the array is the list of allowed attributes.
55-
* * If an element is present as a key and contains"false", the element should be blocked.
56-
* * If an element is not present as a key, theelement should be dropped.
55+
* @param array<string,HtmlSanitizerAction|array<string, bool>> $elementsConfig Registry of allowed/blocked elements:
56+
** If an element is present as a key and contains an array, the element should be allowed
57+
*and the array is the list of allowed attributes.
58+
** If an element is present as a key and containsan HtmlSanitizerAction, that action applies.
59+
** If an element is not present as a key, thedefault action applies.
5760
*/
5861
publicfunction__construct(
5962
privateHtmlSanitizerConfig$config,
@@ -68,6 +71,8 @@ public function __construct(
6871
}
6972
}
7073
}
74+
75+
$this->defaultAction =$config->getDefaultAction();
7176
}
7277

7378
publicfunctionvisit(\DOMDocumentFragment$domNode): ?NodeInterface
@@ -82,32 +87,45 @@ private function visitNode(\DOMNode $domNode, Cursor $cursor): void
8287
{
8388
$nodeName = StringSanitizer::htmlLower($domNode->nodeName);
8489

85-
// Element should be dropped, including its children
86-
if (!\array_key_exists($nodeName,$this->elementsConfig)) {
87-
return;
90+
// Visit recursively if the node was not dropped
91+
if ($this->enterNode($nodeName,$domNode,$cursor)) {
92+
$this->visitChildren($domNode,$cursor);
93+
$cursor->node =$cursor->node->getParent();
8894
}
89-
90-
// Otherwise, visit recursively
91-
$this->enterNode($nodeName,$domNode,$cursor);
92-
$this->visitChildren($domNode,$cursor);
93-
$cursor->node =$cursor->node->getParent();
9495
}
9596

96-
privatefunctionenterNode(string$domNodeName,\DOMNode$domNode,Cursor$cursor):void
97+
privatefunctionenterNode(string$domNodeName,\DOMNode$domNode,Cursor$cursor):bool
9798
{
99+
if (!\array_key_exists($domNodeName,$this->elementsConfig)) {
100+
$action =$this->defaultAction;
101+
$allowedAttributes = [];
102+
}else {
103+
if (\is_array($this->elementsConfig[$domNodeName])) {
104+
$action = HtmlSanitizerAction::Allow;
105+
$allowedAttributes =$this->elementsConfig[$domNodeName];
106+
}else {
107+
$action =$this->elementsConfig[$domNodeName];
108+
$allowedAttributes = [];
109+
}
110+
}
111+
112+
if (HtmlSanitizerAction::Drop ===$action) {
113+
returnfalse;
114+
}
115+
98116
// Element should be blocked, retaining its children
99-
if (false ===$this->elementsConfig[$domNodeName]) {
117+
if (HtmlSanitizerAction::Block ===$action) {
100118
$node =newBlockedNode($cursor->node);
101119

102120
$cursor->node->addChild($node);
103121
$cursor->node =$node;
104122

105-
return;
123+
returntrue;
106124
}
107125

108126
// Otherwise create the node
109127
$node =newNode($cursor->node,$domNodeName);
110-
$this->setAttributes($domNodeName,$domNode,$node,$this->elementsConfig[$domNodeName]);
128+
$this->setAttributes($domNodeName,$domNode,$node,$allowedAttributes);
111129

112130
// Force configured attributes
113131
foreach ($this->forcedAttributes[$domNodeName] ?? []as$attribute =>$value) {
@@ -116,6 +134,8 @@ private function enterNode(string $domNodeName, \DOMNode $domNode, Cursor $curso
116134

117135
$cursor->node->addChild($node);
118136
$cursor->node =$node;
137+
138+
returntrue;
119139
}
120140

121141
privatefunctionvisitChildren(\DOMNode$domNode,Cursor$cursor):void

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp