mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-30 03:57:21 +00:00
Move functions for EscaperExtension
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Resources/debug.php",
|
||||
"src/Resources/escaper.php",
|
||||
"src/Resources/string_loader.php"
|
||||
],
|
||||
"psr-4" : {
|
||||
|
||||
+245
-244
@@ -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 '�';
|
||||
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 => '"', /* quotation mark */
|
||||
38 => '&', /* ampersand */
|
||||
60 => '<', /* less-than sign */
|
||||
62 => '>', /* 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 '�';
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 => '"', /* quotation mark */
|
||||
38 => '&', /* ampersand */
|
||||
60 => '<', /* less-than sign */
|
||||
62 => '>', /* 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'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user