From 510e96275cc2c9f0a4081a95d2ed3d3754e13489 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sun, 22 Aug 2010 02:30:25 +0200 Subject: [PATCH] Changed escaping rules (switched to post-escaping) Expression in Print nodes are always escaped before being printed, except in two conditions : * if the expression is an Expression_Constant node * if the last filter in the chain is an escaper --- lib/Twig/NodeVisitor/Escaper.php | 32 ++---- .../Fixtures/tags/autoescape/with_filters.test | 121 +++++++++++++++++++- .../tags/autoescape/with_filters_arguments.test | 7 +- test/Twig/Tests/integrationTest.php | 5 +- 4 files changed, 139 insertions(+), 26 deletions(-) diff --git a/lib/Twig/NodeVisitor/Escaper.php b/lib/Twig/NodeVisitor/Escaper.php index 8cfc08d..7190955 100644 --- a/lib/Twig/NodeVisitor/Escaper.php +++ b/lib/Twig/NodeVisitor/Escaper.php @@ -69,38 +69,30 @@ class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface $expression = $node instanceof Twig_Node_Print ? $node->getNode('expr') : $node; + if ($expression instanceof Twig_Node_Expression_Constant) { + + return $node; + } + if ($expression instanceof Twig_Node_Expression_Filter) { - // don't escape if the primary node of the filter is not a variable - if (!$expression->getNode('node') instanceof Twig_Node_Expression_GetAttr && !$expression->getNode('node') instanceof Twig_Node_Expression_Name) { - return $node; - } - // don't escape if there is already an "escaper" in the filter chain + // don't escape if the last filter in the chain is an "escaper" $filterMap = $env->getFilters(); - for ($i = 0; $i < count($expression->getNode('filters')); $i += 2) { - $name = $expression->getNode('filters')->getNode($i)->getAttribute('value'); - if (isset($filterMap[$name]) && $filterMap[$name]->isEscaper()) { - return $node; - } + $i = count($expression->getNode('filters')) - 2; + $name = $expression->getNode('filters')->getNode($i)->getAttribute('value'); + if (isset($filterMap[$name]) && $filterMap[$name]->isEscaper()) { + return $node; } - } elseif (!$expression instanceof Twig_Node_Expression_GetAttr && !$expression instanceof Twig_Node_Expression_Name) { - // don't escape if the node is not a variable - return $node; } // escape if ($expression instanceof Twig_Node_Expression_Filter) { - // escape all variables in filters arguments - for ($i = 0; $i < count($expression->getNode('filters')); $i += 2) { - foreach ($expression->getNode('filters')->getNode($i + 1) as $j => $n) { - $expression->getNode('filters')->getNode($i + 1)->setNode($j, $this->escapeNode($n, $env, $type)); - } - } $filter = $this->getEscaperFilter($type, $expression->getLine()); - $expression->prependFilter($filter[0], $filter[1]); + $expression->appendFilter($filter[0], $filter[1]); return $node; + } elseif ($node instanceof Twig_Node_Print) { return new Twig_Node_Print( new Twig_Node_Expression_Filter($expression, new Twig_Node($this->getEscaperFilter($type, $node->getLine())), $node->getLine()) diff --git a/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test b/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test index 3bb0dd4..ce75c45 100644 --- a/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test +++ b/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test @@ -1,14 +1,131 @@ --TEST-- -"autoescape" tag applies escaping before calling filters +"autoescape" tag applies escaping after calling filters --TEMPLATE-- {% autoescape on %} + +(nl2br is an escaper filter) + +1. Don't escape escaper filter output +( var is escaped by |nl2br, line-breaks are added, + the output is not escaped ) {{ var|nl2br }} + +2. Don't escape escaper filter output +( var is escaped by |nl2br, line-breaks are added, + the output is not escaped, |raw is redundant ) +{{ var|nl2br|raw }} + +3. Explicit escape +( var is escaped by |nl2br, line-breaks are added, + the output is explicitly escaped by |escape ) {{ var|nl2br|escape }} + +4. Escape non-escaper filter output +( var is upper-cased by |upper, + the output is auto-escaped ) +{{ var|upper }} + +5. Escape if last filter is not an escaper +( var is escaped by |nl2br, line-breaks are added, + the output is upper-cased by |upper, + the output is auto-escaped as |upper is not an escaper ) +{{ var|nl2br|upper }} + +6. Don't escape escaper filter output +( var is upper cased by upper, + the output is escaped by |nl2br, line-breaks are added, + the output is not escaped as |nl2br is an escaper ) +{{ var|upper|nl2br }} + +7. Escape if last filter is not an escaper +( the output of |format is "" ~ var ~ "", + the output is auto-escaped ) +{{ "%s"|format(var) }} + +8. Escape if last filter is not an escaper +( the output of |format is "" ~ var ~ "", + |raw is redundant, + the output is auto-escaped ) +{{ "%s"|raw|format(var) }} + +9. Don't escape escaper filter output +( the output of |format is "" ~ var ~ "", + the output is not escaped due to |raw filter at the end ) +{{ "%s"|format(var)|raw }} + +10. Don't escape escaper filter output +( the output of |format is "" ~ var ~ "", + the output is not escaped due to |raw filter at the end, + the |raw filter on var is redundant ) +{{ "%s"|format(var|raw)|raw }} + {% endautoescape %} --DATA-- return array('var' => "\nTwig") --EXPECT-- + +(nl2br is an escaper filter) + +1. Don't escape escaper filter output +( var is escaped by |nl2br, line-breaks are added, + the output is not escaped ) <Fabien>
Twig -<Fabien><br /> + +2. Don't escape escaper filter output +( var is escaped by |nl2br, line-breaks are added, + the output is not escaped, |raw is redundant ) +<Fabien>
+Twig + +3. Explicit escape +( var is escaped by |nl2br, line-breaks are added, + the output is explicitly escaped by |escape ) +&lt;Fabien&gt;<br /> Twig + +4. Escape non-escaper filter output +( var is upper-cased by |upper, + the output is auto-escaped ) +<FABIEN> +TWIG + +5. Escape if last filter is not an escaper +( var is escaped by |nl2br, line-breaks are added, + the output is upper-cased by |upper, + the output is auto-escaped as |upper is not an escaper ) +&LT;FABIEN&GT;<BR /> +TWIG + +6. Don't escape escaper filter output +( var is upper cased by upper, + the output is escaped by |nl2br, line-breaks are added, + the output is not escaped as |nl2br is an escaper ) +<FABIEN>
+TWIG + +7. Escape if last filter is not an escaper +( the output of |format is "" ~ var ~ "", + the output is auto-escaped ) +<b><Fabien> +Twig</b> + +8. Escape if last filter is not an escaper +( the output of |format is "" ~ var ~ "", + |raw is redundant, + the output is auto-escaped ) +<b><Fabien> +Twig</b> + +9. Don't escape escaper filter output +( the output of |format is "" ~ var ~ "", + the output is not escaped due to |raw filter at the end ) + +Twig + +10. Don't escape escaper filter output +( the output of |format is "" ~ var ~ "", + the output is not escaped due to |raw filter at the end, + the |raw filter on var is redundant ) + +Twig diff --git a/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test b/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test index c7a5aba..9cf12a1 100644 --- a/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test +++ b/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test @@ -1,11 +1,12 @@ --TEST-- -"autoescape" tag applies escaping on filter arguments, but not on literals +"autoescape" tag do not applies escaping on filter arguments --TEMPLATE-- {% autoescape on %} {{ var|nl2br("
") }} {{ var|nl2br("
"|escape) }} {{ var|nl2br(sep) }} {{ var|nl2br(sep|raw) }} +{{ var|nl2br(sep|escape) }} {% endautoescape %} --DATA-- return array('var' => "\nTwig", 'sep' => '
') @@ -14,7 +15,9 @@ return array('var' => "\nTwig", 'sep' => '
') Twig <Fabien><br /> Twig -<Fabien><br /> +<Fabien>
Twig <Fabien>
Twig +<Fabien><br /> +Twig diff --git a/test/Twig/Tests/integrationTest.php b/test/Twig/Tests/integrationTest.php index 14ac53a..ca6ae7d 100644 --- a/test/Twig/Tests/integrationTest.php +++ b/test/Twig/Tests/integrationTest.php @@ -103,11 +103,12 @@ class TestExtension extends Twig_Extension { public function getFilters() { - return array('nl2br' => new Twig_Filter_Method($this, 'nl2br')); + return array('nl2br' => new Twig_Filter_Method($this, 'nl2br', array('needs_environment' => true, 'is_escaper' => true))); } - public function nl2br($value, $sep = '
') + public function nl2br($env, $value, $sep = '
') { + $value = htmlspecialchars($value, ENT_QUOTES, $env->getCharset()); return str_replace("\n", $sep."\n", $value); } -- 1.7.2.5