From 0cbf5a004c8e0bd34609725c05b913338120aaae Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 20 Apr 2012 16:23:51 +0200 Subject: [PATCH] Added an option to mark filters as preserving the safeness Closes #678 --- CHANGELOG | 1 + lib/Twig/Filter.php | 8 +++- lib/Twig/FilterInterface.php | 2 + lib/Twig/NodeVisitor/SafeAnalysis.php | 6 ++- .../autoescape/with_preserve_safety_filters.test | 50 ++++++++++++++++++++ test/Twig/Tests/integrationTest.php | 6 ++ 6 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 test/Twig/Tests/Fixtures/tags/autoescape/with_preserve_safety_filters.test diff --git a/CHANGELOG b/CHANGELOG index 1613419..3d31a12 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.7.0 (2012-XX-XX) + * added the preserve_safety option for filters * fixed a PHP notice when trying to access a key on a non-object/array variable * enhanced error reporting when the template file is an instance of SplFileInfo * added Twig_Environment::mergeGlobals() diff --git a/lib/Twig/Filter.php b/lib/Twig/Filter.php index f27f08e..b5e400d 100644 --- a/lib/Twig/Filter.php +++ b/lib/Twig/Filter.php @@ -26,6 +26,7 @@ abstract class Twig_Filter implements Twig_FilterInterface 'needs_environment' => false, 'needs_context' => false, 'pre_escape' => null, + 'preserve_safety' => null, ), $options); } @@ -59,7 +60,12 @@ abstract class Twig_Filter implements Twig_FilterInterface return call_user_func($this->options['is_safe_callback'], $filterArgs); } - return array(); + return null; + } + + public function getPreserveSafety() + { + return $this->options['preserve_safety']; } public function getPreEscape() diff --git a/lib/Twig/FilterInterface.php b/lib/Twig/FilterInterface.php index 866e932..20a29e5 100644 --- a/lib/Twig/FilterInterface.php +++ b/lib/Twig/FilterInterface.php @@ -30,6 +30,8 @@ interface Twig_FilterInterface function getSafe(Twig_Node $filterArgs); + function getPreserveSafety(); + function getPreEscape(); function setArguments($arguments); diff --git a/lib/Twig/NodeVisitor/SafeAnalysis.php b/lib/Twig/NodeVisitor/SafeAnalysis.php index 89d8794..c3fc9d3 100644 --- a/lib/Twig/NodeVisitor/SafeAnalysis.php +++ b/lib/Twig/NodeVisitor/SafeAnalysis.php @@ -61,7 +61,11 @@ class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface $name = $node->getNode('filter')->getAttribute('value'); $args = $node->getNode('arguments'); if (false !== $filter = $env->getFilter($name)) { - $this->setSafe($node, $filter->getSafe($args)); + $safe = $filter->getSafe($args); + if (null === $safe) { + $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreserveSafety()); + } + $this->setSafe($node, $safe); } else { $this->setSafe($node, array()); } diff --git a/test/Twig/Tests/Fixtures/tags/autoescape/with_preserve_safety_filters.test b/test/Twig/Tests/Fixtures/tags/autoescape/with_preserve_safety_filters.test new file mode 100644 index 0000000..cedd1bc --- /dev/null +++ b/test/Twig/Tests/Fixtures/tags/autoescape/with_preserve_safety_filters.test @@ -0,0 +1,50 @@ +--TEST-- +"autoescape" tag handles filters preserving the safety +--TEMPLATE-- +{% autoescape true %} + +(preserve_safety is preserving safety for "html") + +1. Unsafe values are still unsafe +( var|preserve_safety|escape ) +{{ var|preserve_safety }} + +2. Safe values are still safe +( var|escape|preserve_safety ) +{{ var|escape|preserve_safety }} + +3. Re-escape values that are escaped for an other contexts +( var|escape_something|preserve_safety|escape ) +{{ var|escape_something|preserve_safety }} + +4. Still escape when using filters not declared safe +( var|escape|preserve_safety|replace({'FABIEN': 'FABPOT'})|escape ) +{{ var|escape|preserve_safety|replace({'FABIEN': 'FABPOT'}) }} + +{% endautoescape %} +--DATA-- +return array('var' => "\nTwig") +--EXPECT-- + +(preserve_safety is preserving safety for "html") + +1. Unsafe values are still unsafe +( var|preserve_safety|escape ) +<FABIEN> +TWIG + +2. Safe values are still safe +( var|escape|preserve_safety ) +<FABIEN> +TWIG + +3. Re-escape values that are escaped for an other contexts +( var|escape_something|preserve_safety|escape ) +<FABIEN> +TWIG + +4. Still escape when using filters not declared safe +( var|escape|preserve_safety|replace({'FABIEN': 'FABPOT'})|escape ) +&LT;FABPOT&GT; +TWIG + diff --git a/test/Twig/Tests/integrationTest.php b/test/Twig/Tests/integrationTest.php index 866e86c..b716b86 100644 --- a/test/Twig/Tests/integrationTest.php +++ b/test/Twig/Tests/integrationTest.php @@ -238,6 +238,7 @@ class TestExtension extends Twig_Extension 'escape_and_nl2br' => new Twig_Filter_Method($this, 'escape_and_nl2br', array('needs_environment' => true, 'is_safe' => array('html'))), 'nl2br' => new Twig_Filter_Method($this, 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), 'escape_something' => new Twig_Filter_Method($this, 'escape_something', array('is_safe' => array('something'))), + 'preserve_safety' => new Twig_Filter_Method($this, 'preserve_safety', array('preserve_safety' => array('html'))), '*_path' => new Twig_Filter_Method($this, 'dynamic_path'), '*_foo_*_bar' => new Twig_Filter_Method($this, 'dynamic_foo'), ); @@ -297,6 +298,11 @@ class TestExtension extends Twig_Extension return strtoupper($value); } + public function preserve_safety($value) + { + return strtoupper($value); + } + public function br() { return '
'; -- 1.7.2.5