From: Arnaud Le Blanc Date: Tue, 24 Aug 2010 06:22:05 +0000 (+0200) Subject: fixed js escaper to be stricter, whilelist-based js escaper (closes #114) X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=4541e88e51102df4b0a9b9c337ede7866c302ce0;p=konrad%2Ftwig.git fixed js escaper to be stricter, whilelist-based js escaper (closes #114) --- diff --git a/CHANGELOG b/CHANGELOG index b783fd1..d202eb8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ Backward incompatibilities: * the odd and even filters are now tests: {{ foo|odd }} must now be written {{ foo is odd }} + * fixed js escaper to be stricter (now uses a whilelist-based js escaper) * added a "constant" filter * added a "constant" test * fixed objects with __toString() not being autoescaped diff --git a/lib/Twig/Extension/Core.php b/lib/Twig/Extension/Core.php index 695aa9f..6080e97 100644 --- a/lib/Twig/Extension/Core.php +++ b/lib/Twig/Extension/Core.php @@ -224,16 +224,62 @@ function twig_escape_filter(Twig_Environment $env, $string, $type = 'html') switch ($type) { case 'js': - // a function the c-escapes a string, making it suitable to be placed in a JavaScript string - return str_replace(array("\\" , "\n" , "\r" , "\"" , "'"), - array("\\\\", "\\n" , "\\r", "\\\"", "\\'"), - $string); + // escape all non-alphanumeric characters + // into their \xHH or \uHHHH representations + $charset = $env->getCharset(); + + if ('UTF-8' != $charset) { + $string = _twig_convert_encoding($string, 'UTF-8', $charset); + } + + if (null === $string = preg_replace_callback('#[^\p{L}\p{N} ]#u', '_twig_escape_js_callback', $string)) { + throw new InvalidArgumentException('The string to escape is not a valid UTF-8 string.'); + } + + if ('UTF-8' != $charset) { + $string = _twig_convert_encoding($string, $charset, 'UTF-8'); + } + + return $string; + case 'html': default: return htmlspecialchars($string, ENT_QUOTES, $env->getCharset()); } } +if (function_exists('iconv')) { + function _twig_convert_encoding($string, $to, $from) + { + return iconv($from, $to, $string); + } +} elseif (function_exists('mb_convert_encoding')) { + function _twig_convert_encoding($string, $to, $from) + { + return mb_convert_encoding($string, $to, $from); + } +} else { + function _twig_convert_encoding($string, $to, $from) + { + throw new RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); + } +} + +function _twig_escape_js_callback($matches) +{ + $char = $matches[0]; + + // \xHH + if (!isset($char[1])) { + return '\\x'.substr('00'.bin2hex($char), -2); + } + + // \uHHHH + $char = _twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); + + return '\\u'.substr('0000'.bin2hex($char), -4); +} + // add multibyte extensions if possible if (function_exists('mb_get_info')) { function twig_length_filter(Twig_Environment $env, $thing) diff --git a/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test b/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test index f3e09dd..a2c9e40 100644 --- a/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test +++ b/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test @@ -7,5 +7,5 @@ --DATA-- return array('var' => '
"') --EXPECT-- -
\" +\x3cbr \x2f\x3e\x22 <br />"