Skip to content

Commit 5b8c7b2

Browse files
[FrameworkBundle][TwigBundle][Form] Add Twig filter, form-type extension and improve service definitions for HtmlSanitizer
1 parent 5ceff21 commit 5b8c7b2

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed

Extension/HtmlSanitizerExtension.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Bridge\Twig\Extension;
13+
14+
use Psr\Container\ContainerInterface;
15+
use Twig\Extension\AbstractExtension;
16+
use Twig\TwigFilter;
17+
18+
/**
19+
* @author Titouan Galopin <[email protected]>
20+
*/
21+
final class HtmlSanitizerExtension extends AbstractExtension
22+
{
23+
public function __construct(
24+
private ContainerInterface $sanitizers,
25+
private string $defaultSanitizer = 'default',
26+
) {
27+
}
28+
29+
public function getFilters(): array
30+
{
31+
return [
32+
new TwigFilter('sanitize_html', $this->sanitize(...), ['is_safe' => ['html']]),
33+
];
34+
}
35+
36+
public function sanitize(string $html, string $sanitizer = null): string
37+
{
38+
return $this->sanitizers->get($sanitizer ?? $this->defaultSanitizer)->sanitize($html);
39+
}
40+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Bridge\Twig\Tests\Extension;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\Twig\Extension\HtmlSanitizerExtension;
16+
use Symfony\Component\DependencyInjection\ServiceLocator;
17+
use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface;
18+
use Twig\Environment;
19+
use Twig\Loader\ArrayLoader;
20+
21+
class HtmlSanitizerExtensionTest extends TestCase
22+
{
23+
public function testSanitizeHtml()
24+
{
25+
$loader = new ArrayLoader([
26+
'foo' => '{{ "foobar"|sanitize_html }}',
27+
'bar' => '{{ "foobar"|sanitize_html("bar") }}',
28+
]);
29+
30+
$twig = new Environment($loader, ['debug' => true, 'cache' => false, 'autoescape' => 'html', 'optimizations' => 0]);
31+
32+
$fooSanitizer = $this->createMock(HtmlSanitizerInterface::class);
33+
$fooSanitizer->expects($this->once())
34+
->method('sanitize')
35+
->with('foobar')
36+
->willReturn('foo');
37+
38+
$barSanitizer = $this->createMock(HtmlSanitizerInterface::class);
39+
$barSanitizer->expects($this->once())
40+
->method('sanitize')
41+
->with('foobar')
42+
->willReturn('bar');
43+
44+
$twig->addExtension(new HtmlSanitizerExtension(new ServiceLocator([
45+
'foo' => fn () => $fooSanitizer,
46+
'bar' => fn () => $barSanitizer,
47+
]), 'foo'));
48+
49+
$this->assertSame('foo', $twig->render('foo'));
50+
$this->assertSame('bar', $twig->render('bar'));
51+
}
52+
}

UndefinedCallableHandler.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class UndefinedCallableHandler
2424
private const FILTER_COMPONENTS = [
2525
'humanize' => 'form',
2626
'trans' => 'translation',
27+
'sanitize_html' => 'html-sanitizer',
2728
'yaml_encode' => 'yaml',
2829
'yaml_dump' => 'yaml',
2930
];
@@ -61,6 +62,7 @@ class UndefinedCallableHandler
6162
];
6263

6364
private const FULL_STACK_ENABLE = [
65+
'html-sanitizer' => 'enable "framework.html_sanitizer"',
6466
'form' => 'enable "framework.form"',
6567
'security-core' => 'add the "SecurityBundle"',
6668
'security-http' => 'add the "SecurityBundle"',

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"symfony/dependency-injection": "^5.4|^6.0",
2929
"symfony/finder": "^5.4|^6.0",
3030
"symfony/form": "^6.1",
31+
"symfony/html-sanitizer": "^6.1",
3132
"symfony/http-foundation": "^5.4|^6.0",
3233
"symfony/http-kernel": "^5.4|^6.0",
3334
"symfony/intl": "^5.4|^6.0",
@@ -65,6 +66,7 @@
6566
"symfony/finder": "",
6667
"symfony/asset": "For using the AssetExtension",
6768
"symfony/form": "For using the FormExtension",
69+
"symfony/html-sanitizer": "For using the HtmlSanitizerExtension",
6870
"symfony/http-kernel": "For using the HttpKernelExtension",
6971
"symfony/routing": "For using the RoutingExtension",
7072
"symfony/translation": "For using the TranslationExtension",

0 commit comments

Comments
 (0)