Move functions for EscaperExtension

This commit is contained in:
Fabien Potencier
2023-12-10 11:49:57 +01:00
parent 196e91dd72
commit 72071e8ece
5 changed files with 307 additions and 269 deletions
+1
View File
@@ -37,6 +37,7 @@
"autoload": {
"files": [
"src/Resources/debug.php",
"src/Resources/escaper.php",
"src/Resources/string_loader.php"
],
"psr-4" : {
+245 -244
View File
@@ -9,12 +9,19 @@
* file that was distributed with this source code.
*/
namespace Twig\Extension {
namespace Twig\Extension;
use Twig\Environment;
use Twig\Error\RuntimeError;
use Twig\FileExtensionEscapingStrategy;
use Twig\Markup;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
use Twig\NodeVisitor\EscaperNodeVisitor;
use Twig\TokenParser\AutoEscapeTokenParser;
use Twig\TwigFilter;
final class EscaperExtension extends AbstractExtension
{
private $defaultStrategy;
@@ -49,9 +56,9 @@ final class EscaperExtension extends AbstractExtension
public function getFilters(): array
{
return [
new TwigFilter('escape', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
new TwigFilter('e', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
new TwigFilter('raw', 'twig_raw_filter', ['is_safe' => ['all']]),
new TwigFilter('escape', [self::class, 'escape'], ['needs_environment' => true, 'is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
new TwigFilter('e', [self::class, 'escape'], ['needs_environment' => true, 'is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
new TwigFilter('raw', [self::class, 'raw'], ['is_safe' => ['all']]),
];
}
@@ -132,285 +139,279 @@ final class EscaperExtension extends AbstractExtension
$this->safeLookup[$strategy][$class] = true;
}
}
}
}
namespace {
use Twig\Environment;
use Twig\Error\RuntimeError;
use Twig\Extension\EscaperExtension;
use Twig\Markup;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*/
function twig_raw_filter($string)
{
return $string;
}
/**
* Escapes a string.
*
* @param mixed $string The value to be escaped
* @param string $strategy The escaping strategy
* @param string $charset The charset
* @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
*
* @return string
*/
function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
{
if ($autoescape && $string instanceof Markup) {
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*
* @internal
*/
public static function raw($string)
{
return $string;
}
if (!\is_string($string)) {
if (\is_object($string) && method_exists($string, '__toString')) {
if ($autoescape) {
$c = \get_class($string);
$ext = $env->getExtension(EscaperExtension::class);
if (!isset($ext->safeClasses[$c])) {
$ext->safeClasses[$c] = [];
foreach (class_parents($string) + class_implements($string) as $class) {
if (isset($ext->safeClasses[$class])) {
$ext->safeClasses[$c] = array_unique(array_merge($ext->safeClasses[$c], $ext->safeClasses[$class]));
foreach ($ext->safeClasses[$class] as $s) {
$ext->safeLookup[$s][$c] = true;
/**
* @internal
*/
public static function escapeFilterIsSafe(Node $filterArgs)
{
foreach ($filterArgs as $arg) {
if ($arg instanceof ConstantExpression) {
return [$arg->getAttribute('value')];
}
return [];
}
return ['html'];
}
/**
* Escapes a string.
*
* @param mixed $string The value to be escaped
* @param string $strategy The escaping strategy
* @param string $charset The charset
* @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
*
* @return string
*
* @internal
*/
public static function escape(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
{
if ($autoescape && $string instanceof Markup) {
return $string;
}
if (!\is_string($string)) {
if (\is_object($string) && method_exists($string, '__toString')) {
if ($autoescape) {
$c = \get_class($string);
$ext = $env->getExtension(EscaperExtension::class);
if (!isset($ext->safeClasses[$c])) {
$ext->safeClasses[$c] = [];
foreach (class_parents($string) + class_implements($string) as $class) {
if (isset($ext->safeClasses[$class])) {
$ext->safeClasses[$c] = array_unique(array_merge($ext->safeClasses[$c], $ext->safeClasses[$class]));
foreach ($ext->safeClasses[$class] as $s) {
$ext->safeLookup[$s][$c] = true;
}
}
}
}
if (isset($ext->safeLookup[$strategy][$c]) || isset($ext->safeLookup['all'][$c])) {
return (string) $string;
}
}
if (isset($ext->safeLookup[$strategy][$c]) || isset($ext->safeLookup['all'][$c])) {
return (string) $string;
}
}
$string = (string) $string;
} elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) {
return $string;
$string = (string) $string;
} elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) {
return $string;
}
}
}
if ('' === $string) {
return '';
}
if ('' === $string) {
return '';
}
if (null === $charset) {
$charset = $env->getCharset();
}
if (null === $charset) {
$charset = $env->getCharset();
}
switch ($strategy) {
case 'html':
// see https://www.php.net/htmlspecialchars
switch ($strategy) {
case 'html':
// see https://www.php.net/htmlspecialchars
// Using a static variable to avoid initializing the array
// each time the function is called. Moving the declaration on the
// top of the function slow downs other escaping strategies.
static $htmlspecialcharsCharsets = [
'ISO-8859-1' => true, 'ISO8859-1' => true,
'ISO-8859-15' => true, 'ISO8859-15' => true,
'utf-8' => true, 'UTF-8' => true,
'CP866' => true, 'IBM866' => true, '866' => true,
'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
'1251' => true,
'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
'BIG5' => true, '950' => true,
'GB2312' => true, '936' => true,
'BIG5-HKSCS' => true,
'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
'EUC-JP' => true, 'EUCJP' => true,
'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
];
if (isset($htmlspecialcharsCharsets[$charset])) {
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
}
if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
// cache the lowercase variant for future iterations
$htmlspecialcharsCharsets[$charset] = true;
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
}
$string = twig_convert_encoding($string, 'UTF-8', $charset);
$string = htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8');
return iconv('UTF-8', $charset, $string);
case 'js':
// escape all non-alphanumeric characters
// into their \x or \uHHHH representations
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', function ($matches) {
$char = $matches[0];
/*
* A few characters have short escape sequences in JSON and JavaScript.
* Escape sequences supported only by JavaScript, not JSON, are omitted.
* \" is also supported but omitted, because the resulting string is not HTML safe.
*/
static $shortMap = [
'\\' => '\\\\',
'/' => '\\/',
"\x08" => '\b',
"\x0C" => '\f',
"\x0A" => '\n',
"\x0D" => '\r',
"\x09" => '\t',
// Using a static variable to avoid initializing the array
// each time the function is called. Moving the declaration on the
// top of the function slow downs other escaping strategies.
static $htmlspecialcharsCharsets = [
'ISO-8859-1' => true, 'ISO8859-1' => true,
'ISO-8859-15' => true, 'ISO8859-15' => true,
'utf-8' => true, 'UTF-8' => true,
'CP866' => true, 'IBM866' => true, '866' => true,
'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
'1251' => true,
'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
'BIG5' => true, '950' => true,
'GB2312' => true, '936' => true,
'BIG5-HKSCS' => true,
'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
'EUC-JP' => true, 'EUCJP' => true,
'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
];
if (isset($shortMap[$char])) {
return $shortMap[$char];
if (isset($htmlspecialcharsCharsets[$charset])) {
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
}
$codepoint = mb_ord($char, 'UTF-8');
if (0x10000 > $codepoint) {
return sprintf('\u%04X', $codepoint);
if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
// cache the lowercase variant for future iterations
$htmlspecialcharsCharsets[$charset] = true;
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
}
// Split characters outside the BMP into surrogate pairs
// https://tools.ietf.org/html/rfc2781.html#section-2.1
$u = $codepoint - 0x10000;
$high = 0xD800 | ($u >> 10);
$low = 0xDC00 | ($u & 0x3FF);
return sprintf('\u%04X\u%04X', $high, $low);
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'css':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
$string = htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8');
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
return iconv('UTF-8', $charset, $string);
$string = preg_replace_callback('#[^a-zA-Z0-9]#Su', function ($matches) {
$char = $matches[0];
return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : mb_ord($char, 'UTF-8'));
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'html_attr':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', function ($matches) {
/**
* This function is adapted from code coming from Zend Framework.
*
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com)
* @license https://framework.zend.com/license/new-bsd New BSD License
*/
$chr = $matches[0];
$ord = \ord($chr);
/*
* The following replaces characters undefined in HTML with the
* hex entity for the Unicode replacement character.
*/
if (($ord <= 0x1F && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7F && $ord <= 0x9F)) {
return '&#xFFFD;';
case 'js':
// escape all non-alphanumeric characters
// into their \x or \uHHHH representations
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
/*
* Check if the current character to escape has a name entity we should
* replace it with while grabbing the hex value of the character.
*/
if (1 === \strlen($chr)) {
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', function ($matches) {
$char = $matches[0];
/*
* While HTML supports far more named entities, the lowest common denominator
* has become HTML5's XML Serialisation which is restricted to the those named
* entities that XML supports. Using HTML entities would result in this error:
* XML Parsing Error: undefined entity
*/
static $entityMap = [
34 => '&quot;', /* quotation mark */
38 => '&amp;', /* ampersand */
60 => '&lt;', /* less-than sign */
62 => '&gt;', /* greater-than sign */
* A few characters have short escape sequences in JSON and JavaScript.
* Escape sequences supported only by JavaScript, not JSON, are omitted.
* \" is also supported but omitted, because the resulting string is not HTML safe.
*/
static $shortMap = [
'\\' => '\\\\',
'/' => '\\/',
"\x08" => '\b',
"\x0C" => '\f',
"\x0A" => '\n',
"\x0D" => '\r',
"\x09" => '\t',
];
if (isset($entityMap[$ord])) {
return $entityMap[$ord];
if (isset($shortMap[$char])) {
return $shortMap[$char];
}
return sprintf('&#x%02X;', $ord);
$codepoint = mb_ord($char, 'UTF-8');
if (0x10000 > $codepoint) {
return sprintf('\u%04X', $codepoint);
}
// Split characters outside the BMP into surrogate pairs
// https://tools.ietf.org/html/rfc2781.html#section-2.1
$u = $codepoint - 0x10000;
$high = 0xD800 | ($u >> 10);
$low = 0xDC00 | ($u & 0x3FF);
return sprintf('\u%04X\u%04X', $high, $low);
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
/*
* Per OWASP recommendations, we'll use hex entities for any other
* characters where a named entity does not exist.
*/
return sprintf('&#x%04X;', mb_ord($chr, 'UTF-8'));
}, $string);
return $string;
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
case 'css':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
return $string;
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
case 'url':
return rawurlencode($string);
$string = preg_replace_callback('#[^a-zA-Z0-9]#Su', function ($matches) {
$char = $matches[0];
default:
$escapers = $env->getExtension(EscaperExtension::class)->getEscapers();
if (\array_key_exists($strategy, $escapers)) {
return $escapers[$strategy]($env, $string, $charset);
}
return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : mb_ord($char, 'UTF-8'));
}, $string);
$validStrategies = implode(', ', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($escapers)));
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
}
}
return $string;
/**
* @internal
*/
function twig_escape_filter_is_safe(Node $filterArgs)
{
foreach ($filterArgs as $arg) {
if ($arg instanceof ConstantExpression) {
return [$arg->getAttribute('value')];
case 'html_attr':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', function ($matches) {
/**
* This function is adapted from code coming from Zend Framework.
*
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com)
* @license https://framework.zend.com/license/new-bsd New BSD License
*/
$chr = $matches[0];
$ord = \ord($chr);
/*
* The following replaces characters undefined in HTML with the
* hex entity for the Unicode replacement character.
*/
if (($ord <= 0x1F && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7F && $ord <= 0x9F)) {
return '&#xFFFD;';
}
/*
* Check if the current character to escape has a name entity we should
* replace it with while grabbing the hex value of the character.
*/
if (1 === \strlen($chr)) {
/*
* While HTML supports far more named entities, the lowest common denominator
* has become HTML5's XML Serialisation which is restricted to the those named
* entities that XML supports. Using HTML entities would result in this error:
* XML Parsing Error: undefined entity
*/
static $entityMap = [
34 => '&quot;', /* quotation mark */
38 => '&amp;', /* ampersand */
60 => '&lt;', /* less-than sign */
62 => '&gt;', /* greater-than sign */
];
if (isset($entityMap[$ord])) {
return $entityMap[$ord];
}
return sprintf('&#x%02X;', $ord);
}
/*
* Per OWASP recommendations, we'll use hex entities for any other
* characters where a named entity does not exist.
*/
return sprintf('&#x%04X;', mb_ord($chr, 'UTF-8'));
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'url':
return rawurlencode($string);
default:
$escapers = $env->getExtension(EscaperExtension::class)->getEscapers();
if (\array_key_exists($strategy, $escapers)) {
return $escapers[$strategy]($env, $string, $charset);
}
$validStrategies = implode(', ', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($escapers)));
throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
}
return [];
}
return ['html'];
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Environment;
use Twig\Extension\EscaperExtension;
/**
* @internal
* @deprecated since Twig 3.9.0
*/
function twig_raw_filter($string)
{
trigger_deprecation('twig/twig', '3.9.0', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
return $string;
}
/**
* @internal
* @deprecated since Twig 3.9.0
*/
function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
{
trigger_deprecation('twig/twig', '3.9.0', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
return EscaperExtension::escape($env, $string, $strategy, $charset, $autoescape);
}
+24 -24
View File
@@ -162,7 +162,7 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
{
$twig = new Environment($this->createMock(LoaderInterface::class));
foreach ($this->htmlSpecialChars as $key => $value) {
$this->assertEquals($value, twig_escape_filter($twig, $key, 'html'), 'Failed to escape: '.$key);
$this->assertEquals($value, EscaperExtension::escape($twig, $key, 'html'), 'Failed to escape: '.$key);
}
}
@@ -170,7 +170,7 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
{
$twig = new Environment($this->createMock(LoaderInterface::class));
foreach ($this->htmlAttrSpecialChars as $key => $value) {
$this->assertEquals($value, twig_escape_filter($twig, $key, 'html_attr'), 'Failed to escape: '.$key);
$this->assertEquals($value, EscaperExtension::escape($twig, $key, 'html_attr'), 'Failed to escape: '.$key);
}
}
@@ -178,7 +178,7 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
{
$twig = new Environment($this->createMock(LoaderInterface::class));
foreach ($this->jsSpecialChars as $key => $value) {
$this->assertEquals($value, twig_escape_filter($twig, $key, 'js'), 'Failed to escape: '.$key);
$this->assertEquals($value, EscaperExtension::escape($twig, $key, 'js'), 'Failed to escape: '.$key);
}
}
@@ -189,7 +189,7 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
try {
mb_internal_encoding('ISO-8859-1');
foreach ($this->jsSpecialChars as $key => $value) {
$this->assertEquals($value, twig_escape_filter($twig, $key, 'js'), 'Failed to escape: '.$key);
$this->assertEquals($value, EscaperExtension::escape($twig, $key, 'js'), 'Failed to escape: '.$key);
}
} finally {
if (false !== $previousInternalEncoding) {
@@ -201,40 +201,40 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
public function testJavascriptEscapingReturnsStringIfZeroLength()
{
$twig = new Environment($this->createMock(LoaderInterface::class));
$this->assertEquals('', twig_escape_filter($twig, '', 'js'));
$this->assertEquals('', EscaperExtension::escape($twig, '', 'js'));
}
public function testJavascriptEscapingReturnsStringIfContainsOnlyDigits()
{
$twig = new Environment($this->createMock(LoaderInterface::class));
$this->assertEquals('123', twig_escape_filter($twig, '123', 'js'));
$this->assertEquals('123', EscaperExtension::escape($twig, '123', 'js'));
}
public function testCssEscapingConvertsSpecialChars()
{
$twig = new Environment($this->createMock(LoaderInterface::class));
foreach ($this->cssSpecialChars as $key => $value) {
$this->assertEquals($value, twig_escape_filter($twig, $key, 'css'), 'Failed to escape: '.$key);
$this->assertEquals($value, EscaperExtension::escape($twig, $key, 'css'), 'Failed to escape: '.$key);
}
}
public function testCssEscapingReturnsStringIfZeroLength()
{
$twig = new Environment($this->createMock(LoaderInterface::class));
$this->assertEquals('', twig_escape_filter($twig, '', 'css'));
$this->assertEquals('', EscaperExtension::escape($twig, '', 'css'));
}
public function testCssEscapingReturnsStringIfContainsOnlyDigits()
{
$twig = new Environment($this->createMock(LoaderInterface::class));
$this->assertEquals('123', twig_escape_filter($twig, '123', 'css'));
$this->assertEquals('123', EscaperExtension::escape($twig, '123', 'css'));
}
public function testUrlEscapingConvertsSpecialChars()
{
$twig = new Environment($this->createMock(LoaderInterface::class));
foreach ($this->urlSpecialChars as $key => $value) {
$this->assertEquals($value, twig_escape_filter($twig, $key, 'url'), 'Failed to escape: '.$key);
$this->assertEquals($value, EscaperExtension::escape($twig, $key, 'url'), 'Failed to escape: '.$key);
}
}
@@ -296,15 +296,15 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
|| $chr >= 0x41 && $chr <= 0x5A
|| $chr >= 0x61 && $chr <= 0x7A) {
$literal = $this->codepointToUtf8($chr);
$this->assertEquals($literal, twig_escape_filter($twig, $literal, 'js'));
$this->assertEquals($literal, EscaperExtension::escape($twig, $literal, 'js'));
} else {
$literal = $this->codepointToUtf8($chr);
if (\in_array($literal, $immune)) {
$this->assertEquals($literal, twig_escape_filter($twig, $literal, 'js'));
$this->assertEquals($literal, EscaperExtension::escape($twig, $literal, 'js'));
} else {
$this->assertNotEquals(
$literal,
twig_escape_filter($twig, $literal, 'js'),
EscaperExtension::escape($twig, $literal, 'js'),
"$literal should be escaped!");
}
}
@@ -320,15 +320,15 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
|| $chr >= 0x41 && $chr <= 0x5A
|| $chr >= 0x61 && $chr <= 0x7A) {
$literal = $this->codepointToUtf8($chr);
$this->assertEquals($literal, twig_escape_filter($twig, $literal, 'html_attr'));
$this->assertEquals($literal, EscaperExtension::escape($twig, $literal, 'html_attr'));
} else {
$literal = $this->codepointToUtf8($chr);
if (\in_array($literal, $immune)) {
$this->assertEquals($literal, twig_escape_filter($twig, $literal, 'html_attr'));
$this->assertEquals($literal, EscaperExtension::escape($twig, $literal, 'html_attr'));
} else {
$this->assertNotEquals(
$literal,
twig_escape_filter($twig, $literal, 'html_attr'),
EscaperExtension::escape($twig, $literal, 'html_attr'),
"$literal should be escaped!");
}
}
@@ -344,12 +344,12 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
|| $chr >= 0x41 && $chr <= 0x5A
|| $chr >= 0x61 && $chr <= 0x7A) {
$literal = $this->codepointToUtf8($chr);
$this->assertEquals($literal, twig_escape_filter($twig, $literal, 'css'));
$this->assertEquals($literal, EscaperExtension::escape($twig, $literal, 'css'));
} else {
$literal = $this->codepointToUtf8($chr);
$this->assertNotEquals(
$literal,
twig_escape_filter($twig, $literal, 'css'),
EscaperExtension::escape($twig, $literal, 'css'),
"$literal should be escaped!");
}
}
@@ -359,7 +359,7 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
{
$this->expectException(RuntimeError::class);
twig_escape_filter(new Environment($this->createMock(LoaderInterface::class)), 'foo', 'bar');
EscaperExtension::escape(new Environment($this->createMock(LoaderInterface::class)), 'foo', 'bar');
}
/**
@@ -370,7 +370,7 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
$twig = new Environment($this->createMock(LoaderInterface::class));
$twig->getExtension(EscaperExtension::class)->setEscaper('foo', 'Twig\Tests\foo_escaper_for_test');
$this->assertSame($expected, twig_escape_filter($twig, $string, $strategy));
$this->assertSame($expected, EscaperExtension::escape($twig, $string, $strategy));
}
public function provideCustomEscaperCases()
@@ -389,8 +389,8 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
$env2 = new Environment($this->createMock(LoaderInterface::class));
$env2->getExtension(EscaperExtension::class)->setEscaper('foo', 'Twig\Tests\foo_escaper_for_test1');
$this->assertSame('fooUTF-8', twig_escape_filter($env1, 'foo', 'foo'));
$this->assertSame('fooUTF-81', twig_escape_filter($env2, 'foo', 'foo'));
$this->assertSame('fooUTF-8', EscaperExtension::escape($env1, 'foo', 'foo'));
$this->assertSame('fooUTF-81', EscaperExtension::escape($env2, 'foo', 'foo'));
}
/**
@@ -401,8 +401,8 @@ class Twig_Tests_Extension_EscaperTest extends TestCase
$obj = new Extension_TestClass();
$twig = new Environment($this->createMock(LoaderInterface::class));
$twig->getExtension('\Twig\Extension\EscaperExtension')->setSafeClasses($safeClasses);
$this->assertSame($escapedHtml, twig_escape_filter($twig, $obj, 'html', null, true));
$this->assertSame($escapedJs, twig_escape_filter($twig, $obj, 'js', null, true));
$this->assertSame($escapedHtml, EscaperExtension::escape($twig, $obj, 'html', null, true));
$this->assertSame($escapedJs, EscaperExtension::escape($twig, $obj, 'js', null, true));
}
public function provideObjectsForEscaping()
+2 -1
View File
@@ -13,6 +13,7 @@ namespace Twig\Tests;
use Twig\Extension\AbstractExtension;
use Twig\Extension\DebugExtension;
use Twig\Extension\EscaperExtension;
use Twig\Extension\SandboxExtension;
use Twig\Extension\StringLoaderExtension;
use Twig\Node\Expression\ConstantExpression;
@@ -215,7 +216,7 @@ class TwigTestExtension extends AbstractExtension
*/
public function escape_and_nl2br($env, $value, $sep = '<br />')
{
return $this->nl2br(twig_escape_filter($env, $value, 'html'), $sep);
return $this->nl2br(EscaperExtension::escape($env, $value, 'html'), $sep);
}
/**