From 5372571e4fb85da04ee900c81fb236515425a2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bouc=CC=8Cek?= Date: Thu, 21 Apr 2022 19:14:55 +0200 Subject: [PATCH 1/2] Html: Concatenate more arguments --- src/Escape.php | 19 +++++++++++++------ tests/EscapeTest.php | 45 ++++++++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/Escape.php b/src/Escape.php index 5109d01..e41eddc 100644 --- a/src/Escape.php +++ b/src/Escape.php @@ -19,18 +19,25 @@ class Escape { /** - * Escapes string for use everywhere inside HTML (except for comments). - * @param string|HtmlStringable|IHtmlString|mixed $data + * Escapes strings for use everywhere inside HTML (except for comments) and concatenate it to string. + * @param string|HtmlStringable|IHtmlString|mixed ...$data * @return string * * @link https://api.nette.org/2.4/source-Latte.Runtime.Filters.php.html#27-35 */ - public static function html($data): string + public static function html(...$data): string { - if ($data instanceof HtmlStringable || $data instanceof IHtmlString) { - return (string)$data; + $output = ''; + + foreach ($data as $item) { + if ($item instanceof HtmlStringable || $item instanceof IHtmlString) { + $output .= $item; + } else { + $output .= htmlspecialchars((string)$item, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE); + } } - return htmlspecialchars((string)$data, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE); + + return $output; } /** diff --git a/tests/EscapeTest.php b/tests/EscapeTest.php index 9d0a876..8a84a2c 100644 --- a/tests/EscapeTest.php +++ b/tests/EscapeTest.php @@ -18,31 +18,40 @@ class EscapeTest extends TestCase public function getHtmlArgs(): array { return [ - ['', null], - ['', ''], - ['1', 1], - ['string', 'string'], - ['<br>', '
'], - ['< & ' " >', '< & \' " >'], - ['&quot;', '"'], - ['`hello', '`hello'], - ["foo \u{FFFD} bar", "foo \u{D800} bar"], // invalid codepoint high surrogates - ["foo \u{FFFD}" bar", "foo \xE3\x80\x22 bar"], // stripped UTF - ['Hello World', 'Hello World'], - ['Hello <World>', 'Hello '], - ['" ' < > & �', "\" ' < > & \x8F"], - ['`hello`', '`hello`'], - ['` <br> `', '`
`'], - ['Foo
bar', Html::fromHtml('Foo
bar')] + ['', []], + ['', [null]], + ['', ['']], + ['1', [1]], + ['string', ['string']], + ['<br>', ['
']], + ['< & ' " >', ['< & \' " >']], + ['&quot;', ['"']], + ['`hello', ['`hello']], + ["foo \u{FFFD} bar", ["foo \u{D800} bar"]], // invalid codepoint high surrogates + ["foo \u{FFFD}" bar", ["foo \xE3\x80\x22 bar"]], // stripped UTF + ['Hello World', ['Hello World']], + ['Hello <World>', ['Hello ']], + ['Hello World', [Html::fromText('Hello World')]], + ['Hello <World>', [Html::fromText('Hello ')]], + ['" ' < > & �', ["\" ' < > & \x8F"]], + ['`hello`', ['`hello`']], + ['` <br> `', ['`
`']], + ['Foo
bar', [Html::fromHtml('Foo
bar')]], + ['Foo<br>bar', [Html::fromText('Foo
bar')]], + ['Hello <World>Hello <World>', ['Hello ', 'Hello ']], + ['Hello <World>Hello ', ['Hello ', Html::fromHtml('Hello ')]], + ['Hello Hello <World>', [Html::fromHtml('Hello '), 'Hello ']], + ['Hello Hello ', [Html::fromHtml('Hello '), Html::fromHtml('Hello ')]], ]; } /** + * @param array $data * @dataProvider getHtmlArgs */ - public function testHtml(string $expected, $data): void + public function testHtml(string $expected, array $data): void { - Assert::same($expected, Escape::html($data)); + Assert::same($expected, Escape::html(...$data)); } public function getHtmlAttrArgs(): array From f9b5674b155e084cd141c2ea39c45705235c0329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bouc=CC=8Cek?= Date: Thu, 21 Apr 2022 19:15:11 +0200 Subject: [PATCH 2/2] Readme: Html: Concatenate more arguments --- README.md | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cb79a66..afacc90 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,21 @@ echo 'Registered user: ' . $username; Use: ```php -echo 'Registered user: ' . \JakubBoucek\Escape\Escape::html($username); +use JakubBoucek\Escape\Escape; + +echo 'Registered user: ' . Escape::html($username); +``` + +You can use shortcut by aliasing too: +```php +use JakubBoucek\Escape\Escape as E; + +echo 'Registered user: ' . E::html($username); ``` ## CSS specifics -In few cases you cannot use `\JakubBoucek\Escape\Escape::css($cssColor)` to escape +In few cases you cannot use `Escape::css($cssColor)` to escape some known format, because standard escaping is broke CSS format. Class `EscapeCss` has prepared limited set of known propetries with specefics format: @@ -48,7 +57,9 @@ limited set of known propetries with specefics format: Sanitize value od CSS `color` property to safe format, example: ```php -echo ''; +use JakubBoucek\Escape\EscapeCss; + +echo ''; ``` It's prevent attact by escaping color value context. @@ -57,6 +68,20 @@ It's prevent attact by escaping color value context. Package supports escaping HTML with included [safe HTML content](https://doc.nette.org/en/3.1/html-elements). +Usage: +```php +use JakubBoucek\Escape\Escape; +use Nette\Utils\Html; + +$avatarUrl = 'http:/example.com/avatar.png'; +$username = 'John Doe '; + +$avatarImage = Html::el('img')->src($avatarUrl)->width(16); +echo Escape::html($avatarImage, ' ', $username); + +// John Doe <script>hack</script> +``` + ## Output without any escaping In some cases you intentionally want to output variable without any escaping, but somebody other or your future self may