From 0b98a8d7793c684cfb5cdcd14ffa7e0f2ff2b235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bouc=CC=8Cek?= Date: Mon, 28 Feb 2022 01:18:48 +0100 Subject: [PATCH 1/2] Escape: Unify string casting --- src/Escape.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Escape.php b/src/Escape.php index 3ba327f..dc3d322 100644 --- a/src/Escape.php +++ b/src/Escape.php @@ -28,7 +28,7 @@ class Escape public static function html($data): string { if ($data instanceof HtmlStringable || $data instanceof IHtmlString) { - return $data->__toString(); + return (string)$data; } return htmlspecialchars((string)$data, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE); } @@ -78,10 +78,11 @@ public static function htmlComment($data): string */ public static function xml($data): string { + $data = (string)$data; // XML 1.0: \x09 \x0A \x0D and C1 allowed directly, C0 forbidden // XML 1.1: \x00 forbidden directly and as a character reference, // \x09 \x0A \x0D \x85 allowed directly, C0, C1 and \x7F allowed as character references - $data = preg_replace('#[\x00-\x08\x0B\x0C\x0E-\x1F]#', "\u{FFFD}", (string)$data); + $data = preg_replace('#[\x00-\x08\x0B\x0C\x0E-\x1F]#', "\u{FFFD}", $data); return htmlspecialchars($data, ENT_QUOTES | ENT_XML1 | ENT_SUBSTITUTE, 'UTF-8'); } @@ -95,7 +96,7 @@ public static function xml($data): string public static function js($data): string { if ($data instanceof HtmlStringable || $data instanceof IHtmlString) { - $data = $data->__toString(); + $data = (string)$data; } $json = Json::encode($data); @@ -112,8 +113,9 @@ public static function js($data): string */ public static function css($data): string { + $data = (string)$data; // http://www.w3.org/TR/2006/WD-CSS21-20060411/syndata.html#q6 - return addcslashes((string)$data, "\x00..\x1F!\"#$%&'()*+,./:;<=>?@[\\]^`{|}~"); + return addcslashes($data, "\x00..\x1F!\"#$%&'()*+,./:;<=>?@[\\]^`{|}~"); } /** @@ -123,17 +125,18 @@ public static function css($data): string */ public static function url($url): string { - return urlencode((string)$url); + $url = (string)$url; + return urlencode($url); } /** * Just returns argument as is without any escaping * Method is useful to mark code as intentionally unescaped as opposed to simple neglected - * @param string|mixed $url + * @param string|mixed $data * @return string */ - public static function noescape($url): string + public static function noescape($data): string { - return (string)$url; + return (string)$data; } } From 3d18846073e8d689961b9dadf84eaa639d60454e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bouc=CC=8Cek?= Date: Mon, 28 Feb 2022 01:59:09 +0100 Subject: [PATCH 2/2] Package independent to Nette/Utils --- composer.json | 13 ++++++++++--- src/Escape.php | 8 ++++++-- src/EscapeCss.php | 10 ++++------ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index acc00b0..5398c21 100644 --- a/composer.json +++ b/composer.json @@ -16,11 +16,15 @@ ], "require": { "php": ">= 7.2", - "nette/utils": "^3.2.5" + "ext-json": "*" }, "require-dev": { - "phpstan/phpstan": "^0.12.98", - "nette/tester": "^2.4" + "nette/tester": "^2.4", + "nette/utils": "^3.2.5", + "phpstan/phpstan": "^0.12.98" + }, + "suggest": { + "nette/utils": "Allows to safe escape HTML with markup: https://doc.nette.org/en/utils/html-elements" }, "autoload": { "psr-4": { @@ -30,5 +34,8 @@ "scripts": { "phpstan": "phpstan analyze src -c phpstan.neon --level 7", "tester": "tester tests" + }, + "config": { + "sort-packages": true } } diff --git a/src/Escape.php b/src/Escape.php index dc3d322..cf8e403 100644 --- a/src/Escape.php +++ b/src/Escape.php @@ -7,7 +7,7 @@ use Nette\HtmlStringable; use Nette\Utils\IHtmlString; -use Nette\Utils\Json; +use RuntimeException; /** * Escape funxtions. Uses UTF-8 only. @@ -99,7 +99,11 @@ public static function js($data): string $data = (string)$data; } - $json = Json::encode($data); + $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION); + + if ($json === false) { + throw new RuntimeException("JSON encode failed: " . json_last_error_msg(), json_last_error()); + } return str_replace([']]>', '