From ad68092291c01ebcff8bec027c41a0863f0390c2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 23 Nov 2010 10:22:48 +0100 Subject: [PATCH] removed the OutputEscaper component, added escape mechanism in the Templating Engine class --- .../FrameworkExtension.php | 4 - .../Resources/config/schema/symfony-1.0.xsd | 1 - .../Resources/config/templating.xml | 3 - .../FrameworkBundle/Templating/Engine.php | 29 +- .../Templating/Helper/ActionsHelper.php | 5 +- .../Templating/Helper/FormHelper.php | 4 - .../Tests/Templating/EngineTest.php | 32 -- .../OutputEscaper/ArrayDecorator.php | 164 -------- .../Component/OutputEscaper/BaseEscaper.php | 69 ---- .../Component/OutputEscaper/Escaper.php | 355 ------------------ .../OutputEscaper/IteratorDecorator.php | 97 ----- .../OutputEscaper/ObjectDecorator.php | 191 ---------- .../Component/OutputEscaper/SafeDecorator.php | 42 --- .../OutputEscaper/SafeDecoratorInterface.php | 21 -- src/Symfony/Component/Templating/Engine.php | 135 ++++++- .../OutputEscaper/ArrayDecoratorTest.php | 84 ----- .../Component/OutputEscaper/EscaperTest.php | 190 ---------- .../OutputEscaper/ObjectDecoratorTest.php | 83 ---- .../OutputEscaper/SafeDecoratorTest.php | 23 -- 19 files changed, 134 insertions(+), 1398 deletions(-) delete mode 100644 src/Symfony/Component/OutputEscaper/ArrayDecorator.php delete mode 100644 src/Symfony/Component/OutputEscaper/BaseEscaper.php delete mode 100644 src/Symfony/Component/OutputEscaper/Escaper.php delete mode 100644 src/Symfony/Component/OutputEscaper/IteratorDecorator.php delete mode 100644 src/Symfony/Component/OutputEscaper/ObjectDecorator.php delete mode 100644 src/Symfony/Component/OutputEscaper/SafeDecorator.php delete mode 100644 src/Symfony/Component/OutputEscaper/SafeDecoratorInterface.php delete mode 100644 tests/Symfony/Tests/Component/OutputEscaper/ArrayDecoratorTest.php delete mode 100644 tests/Symfony/Tests/Component/OutputEscaper/EscaperTest.php delete mode 100644 tests/Symfony/Tests/Component/OutputEscaper/ObjectDecoratorTest.php delete mode 100644 tests/Symfony/Tests/Component/OutputEscaper/SafeDecoratorTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 4937e6fb98de..5f968906e325 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -157,10 +157,6 @@ protected function registerTemplatingConfiguration($config, ContainerBuilder $co } } - if (array_key_exists('escaping', $config)) { - $container->setParameter('templating.output_escaper', $config['escaping']); - } - if (array_key_exists('assets_version', $config)) { $container->setParameter('templating.assets.version', $config['assets_version']); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 20d9d1b00c80..3476c9cf7332 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -63,7 +63,6 @@ - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml index c6edded8519f..b4558b7035fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml @@ -21,7 +21,6 @@ Symfony\Bundle\FrameworkBundle\Templating\Helper\TranslatorHelper Symfony\Bundle\FrameworkBundle\Templating\Helper\SecurityHelper Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper - false null null @@ -31,8 +30,6 @@ - - %templating.output_escaper% %kernel.charset% diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php index 827c41598c4d..d59996fbf703 100755 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Engine.php @@ -4,7 +4,6 @@ use Symfony\Component\Templating\Engine as BaseEngine; use Symfony\Component\Templating\Loader\LoaderInterface; -use Symfony\Component\OutputEscaper\Escaper; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Response; @@ -18,15 +17,13 @@ */ /** - * This engine knows how to render Symfony templates and automatically - * escapes template parameters. + * This engine knows how to render Symfony templates. * * @author Fabien Potencier */ class Engine extends BaseEngine { protected $container; - protected $escaper; /** * Constructor. @@ -34,12 +31,10 @@ class Engine extends BaseEngine * @param ContainerInterface $container A ContainerInterface instance * @param LoaderInterface $loader A loader instance * @param array $renderers An array of renderer instances - * @param mixed $escaper The escaper to use (or false to disable escaping) */ - public function __construct(ContainerInterface $container, LoaderInterface $loader, array $renderers = array(), $escaper = false) + public function __construct(ContainerInterface $container, LoaderInterface $loader, array $renderers = array()) { $this->container = $container; - $this->escaper = $escaper; parent::__construct($loader, $renderers); @@ -68,10 +63,6 @@ public function render($name, array $parameters = array()) $this->renderers[$renderer]->setEngine($this); } - if ('php' === $renderer) { - $parameters = $this->escapeParameters($parameters); - } - return parent::render($name, $parameters); } @@ -117,22 +108,6 @@ public function get($name) return $this->helpers[$name]; } - protected function escapeParameters(array $parameters) - { - if (false !== $this->escaper) { - Escaper::setCharset($this->getCharset()); - - $parameters['_data'] = Escaper::escape($this->escaper, $parameters); - foreach ($parameters['_data'] as $key => $value) { - $parameters[$key] = $value; - } - } else { - $parameters['_data'] = Escaper::escape('raw', $parameters); - } - - return $parameters; - } - // parses template names following the following pattern: // bundle:section:template(.format).renderer public function splitTemplateName($name, array $defaults = array()) diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php index 137e5f2f165a..9e44153caa01 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php @@ -3,7 +3,6 @@ namespace Symfony\Bundle\FrameworkBundle\Templating\Helper; use Symfony\Component\Templating\Helper\Helper; -use Symfony\Component\OutputEscaper\Escaper; use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver; /* @@ -58,11 +57,11 @@ public function output($controller, array $attributes = array(), array $options */ public function render($controller, array $attributes = array(), array $options = array()) { - $options['attributes'] = Escaper::unescape($attributes); + $options['attributes'] = $attributes; if (isset($options['query'])) { - $options['query'] = Escaper::unescape($options['query']); + $options['query'] = $options['query']; } return $this->resolver->render($controller, $options); diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php index c002fe49de5c..fd6dbdc0501a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @@ -145,10 +145,6 @@ public function hidden(/*FieldGroupInterface */$group, array $parameters = array protected function lookupTemplate(/*FieldInterface */$field) { - if ($field instanceof \Symfony\Component\OutputEscaper\ObjectDecorator) { - $field = $field->getRawValue(); - } - $fqClassName = get_class($field); $template = null; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php index aa793581b8c3..3e8fe4389a82 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/EngineTest.php @@ -16,7 +16,6 @@ use Symfony\Component\Templating\Storage\StringStorage; use Symfony\Component\Templating\Storage\Storage; use Symfony\Component\Templating\Renderer\PhpRenderer; -use Symfony\Component\OutputEscaper\Escaper; // simulate the rendering of another controller function foo($engine) @@ -26,37 +25,6 @@ function foo($engine) class EngineTest extends TestCase { - public function testRenderEscaping() - { - $templates = array( - 'tpl1' => '', - 'tpl2' => 'render("FooBundle:Foo:tpl1.php", array("foo" => $foo)) ?>', - 'tpl3' => 'render("FooBundle:Foo:tpl1.php", array("foo" => "foo
")) ?>', - 'tpl4' => '', - ); - - $loader = $this->getMock('Symfony\Component\Templating\Loader\LoaderInterface'); - $loader->expects($this->exactly(4)) - ->method('load') - ->with($this->anything(), $this->anything()) - ->will($this->onConsecutiveCalls( - new StringStorage($templates['tpl1']), - new StringStorage($templates['tpl2']), - new StringStorage($templates['tpl3']), - new StringStorage($templates['tpl4']) - )) - ; - - $engine = new Engine($this->getContainerMock(), $loader, array('php' => new PhpRenderer()), 'htmlspecialchars'); - - $this->assertEquals('foo <br />', $engine->render('FooBundle:Foo:tpl1.php', array('foo' => 'foo
'))); - $this->assertEquals('foo <br />', $engine->render('FooBundle:Foo:tpl1.php', array('foo' => 'foo
'))); - - $this->assertEquals('foo <br />foo <br />', $engine->render('FooBundle:Foo:tpl2.php', array('foo' => 'foo
'))); - $this->assertEquals('foo <br />foo <br />', $engine->render('FooBundle:Foo:tpl3.php', array('foo' => 'foo
'))); - $this->assertEquals('foo <br />foo <br />', $engine->render('FooBundle:Foo:tpl4.php', array('foo' => 'foo
'))); - } - /** * @dataProvider getSplitTemplateNameTests */ diff --git a/src/Symfony/Component/OutputEscaper/ArrayDecorator.php b/src/Symfony/Component/OutputEscaper/ArrayDecorator.php deleted file mode 100644 index 44c603b29fa1..000000000000 --- a/src/Symfony/Component/OutputEscaper/ArrayDecorator.php +++ /dev/null @@ -1,164 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Output escaping decorator class for arrays. - * - * @see Escaper - * @author Fabien Potencier - * @author Mike Squire - */ -class ArrayDecorator extends BaseEscaper implements \Iterator, \ArrayAccess, \Countable -{ - /** - * Used by the iterator to know if the current element is valid. - * - * @var int - */ - private $count = 0; - - /** - * Reset the array to the beginning (as required for the Iterator interface). - */ - public function rewind() - { - reset($this->value); - - $this->count = count($this->value); - } - - /** - * Get the key associated with the current value (as required by the Iterator interface). - * - * @return string The key - */ - public function key() - { - return key($this->value); - } - - /** - * Escapes and return the current value (as required by the Iterator interface). - * - * This escapes the value using {@link Escaper::escape()} with - * whatever escaping method is set for this instance. - * - * @return mixed The escaped value - */ - public function current() - { - return Escaper::escape($this->escaper, current($this->value)); - } - - /** - * Moves to the next element (as required by the Iterator interface). - */ - public function next() - { - next($this->value); - - $this->count --; - } - - /** - * Returns true if the current element is valid (as required by the Iterator interface). - * - * The current element will not be valid if {@link next()} has fallen off the - * end of the array or if there are no elements in the array and {@link - * rewind()} was called. - * - * @return bool The validity of the current element; true if it is valid - */ - public function valid() - { - return $this->count > 0; - } - - /** - * Returns true if the supplied offset isset in the array (as required by the ArrayAccess interface). - * - * @param string $offset The offset of the value to check existence of - * - * @return bool true if the offset isset; false otherwise - */ - public function offsetExists($offset) - { - return isset($this->value[$offset]); - } - - /** - * Returns the element associated with the offset supplied (as required by the ArrayAccess interface). - * - * @param string $offset The offset of the value to get - * - * @return mixed The escaped value - */ - public function offsetGet($offset) - { - return Escaper::escape($this->escaper, $this->value[$offset]); - } - - /** - * Throws an exception saying that values cannot be set (this method is - * required for the ArrayAccess interface). - * - * This (and the other Escaper classes) are designed to be read only - * so this is an illegal operation. - * - * @param string $offset (ignored) - * @param string $value (ignored) - * - * @throws \LogicException When trying to set values - */ - public function offsetSet($offset, $value) - { - throw new \LogicException('Cannot set values.'); - } - - /** - * Throws an exception saying that values cannot be unset (this method is - * required for the ArrayAccess interface). - * - * This (and the other Escaper classes) are designed to be read only - * so this is an illegal operation. - * - * @param string $offset (ignored) - * - * @throws \LogicException When trying to unset values - */ - public function offsetUnset($offset) - { - throw new \LogicException('Cannot unset values.'); - } - - /** - * Escapes a key from the array using the specified escaper. - * - * @param string $key The array key - * @param string $escaper The escaping strategy prefixed with esc_ (see __call()) - */ - public function getEscapedKey($key, $escaper) - { - return Escaper::escape(substr($escaper, 4), $this->value[$key]); - } - - /** - * Returns the size of the array (are required by the Countable interface). - * - * @return int The size of the array - */ - public function count() - { - return count($this->value); - } -} diff --git a/src/Symfony/Component/OutputEscaper/BaseEscaper.php b/src/Symfony/Component/OutputEscaper/BaseEscaper.php deleted file mode 100644 index 8dc020c715ea..000000000000 --- a/src/Symfony/Component/OutputEscaper/BaseEscaper.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Abstract class that provides an interface for output escaping. - * - * @author Fabien Potencier - * @author Mike Squire - */ -abstract class BaseEscaper -{ - /** - * The value that is to be escaped. - */ - protected $value; - - /** - * The escaper (a PHP callable or a named escaper) that is going to be applied to the value and its children. - */ - protected $escaper; - - /** - * Constructor. - * - * Since BaseEscaper is an abstract class, instances cannot be created - * directly but the constructor will be inherited by sub-classes. - * - * @param mixed $escaper The escaping method (a PHP callable or a named escaper) - * @param string $value Escaping value - */ - public function __construct($escaper, $value) - { - $this->escaper = $escaper; - $this->value = $value; - } - - /** - * Sets the default escaper to use. - * - * @param mixed $escaper The escaping method (a PHP callable or a named escaper) - */ - public function setEscaper($escaper) - { - $this->escaper = $escaper; - } - - /** - * Returns the raw value associated with this instance. - * - * Concrete instances of BaseEscaper classes decorate a value which is - * stored by the constructor. This returns that original, unescaped, value. - * - * @return mixed The original value used to construct the decorator - */ - public function getRawValue() - { - return $this->value; - } -} diff --git a/src/Symfony/Component/OutputEscaper/Escaper.php b/src/Symfony/Component/OutputEscaper/Escaper.php deleted file mode 100644 index a4292e71909f..000000000000 --- a/src/Symfony/Component/OutputEscaper/Escaper.php +++ /dev/null @@ -1,355 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Escaper provides output escaping features. - * - * @author Fabien Potencier - * @author Mike Squire - */ -class Escaper -{ - static protected $charset = 'UTF-8'; - static protected $safeClasses = array(); - static protected $escapers; - static protected $safeObjects = array(); - - /** - * Decorates a PHP variable with something that will escape any data obtained - * from it. - * - * The following cases are dealt with: - * - * - The value is null or false: null or false is returned. - * - The value is scalar: the result of applying the escaping method is - * returned. - * - The value is an array or an object that implements the ArrayAccess - * interface: the array is decorated such that accesses to elements yield - * an escaped value. - * - The value implements the Traversable interface (either an Iterator, an - * IteratorAggregate or an internal PHP class that implements - * Traversable): decorated much like the array. - * - The value is another type of object: decorated such that the result of - * method calls is escaped. - * - * The escaping method is actually a PHP callable. This class hosts a set - * of standard escaping strategies. - * - * @param mixed $escaper The escaping method (a PHP callable or a named escaper) to apply to the value - * @param mixed $value The value to escape - * - * @return mixed Escaped value - * - * @throws \InvalidArgumentException If the escaping fails - */ - static public function escape($escaper, $value) - { - if (null === $value) { - return $value; - } - - if (null === self::$escapers) { - self::initializeEscapers(); - } - - if (is_string($escaper) && isset(self::$escapers[$escaper])) { - $escaper = self::$escapers[$escaper]; - } - - // Scalars are anything other than arrays, objects and resources. - if (is_scalar($value)) { - return call_user_func($escaper, $value); - } - - if (is_array($value)) { - return new ArrayDecorator($escaper, $value); - } - - if (is_object($value)) { - if (isset(self::$safeObjects[spl_object_hash($value)])) { - return $value; - } - - if ($value instanceof BaseEscaper) { - // avoid double decoration - $copy = clone $value; - $copy->setEscaper($escaper); - - return $copy; - } - - if ($value instanceof SafeDecorator) { - // do not escape objects marked as safe - // return the original object - return self::$safeObjects[spl_object_hash($value->getRawValue())] = $value->getRawValue(); - } - - if (self::isClassMarkedAsSafe(get_class($value)) || $value instanceof SafeDecoratorInterface) { - // the class or one of its children is marked as safe - // return the unescaped object - return $value; - } - - if ($value instanceof \Traversable) { - return new IteratorDecorator($escaper, $value); - } - - return new ObjectDecorator($escaper, $value); - - } - - // it must be a resource; cannot escape that. - throw new \InvalidArgumentException(sprintf('Unable to escape value "%s".', var_export($value, true))); - } - - /** - * Unescapes a value that has been escaped previously with the escape() method. - * - * @param mixed $value The value to unescape - * - * @return mixed Unescaped value - * - * @throws \InvalidArgumentException If the escaping fails - */ - static public function unescape($value) - { - if (null === $value || is_bool($value)) { - return $value; - } - - if (is_scalar($value)) { - return html_entity_decode($value, ENT_QUOTES, self::$charset); - } - - if (is_array($value)) { - foreach ($value as $name => $v) { - $value[$name] = self::unescape($v); - } - - return $value; - } - - if (is_object($value)) { - return $value instanceof BaseEscaper ? $value->getRawValue() : $value; - } - - return $value; - } - - /** - * Returns true if the class if marked as safe. - * - * @param string $class A class name - * - * @return bool true if the class if safe, false otherwise - */ - static public function isClassMarkedAsSafe($class) - { - if (in_array($class, self::$safeClasses)) { - return true; - } - - foreach (self::$safeClasses as $safeClass) { - if (is_subclass_of($class, $safeClass)) { - return true; - } - } - - return false; - } - - /** - * Marks an array of classes (and all its children) as being safe for output. - * - * @param array $classes An array of class names - */ - static public function markClassesAsSafe(array $classes) - { - self::$safeClasses = array_unique(array_merge(self::$safeClasses, $classes)); - } - - /** - * Marks a class (and all its children) as being safe for output. - * - * @param string $class A class name - */ - static public function markClassAsSafe($class) - { - self::markClassesAsSafe(array($class)); - } - - /** - * Sets the current charset. - * - * @param string $charset The current charset - */ - static public function setCharset($charset) - { - self::$charset = $charset; - } - - /** - * Gets the current charset. - * - * @return string The current charset - */ - static public function getCharset() - { - return self::$charset; - } - - /** - * Adds a named escaper. - * - * Warning: An escaper must be able to deal with - * double-escaping correctly. - * - * @param string $name The escaper name - * @param mixed $escaper A PHP callable - */ - static public function setEscaper($name, $escaper) - { - self::$escapers[$name] = $escaper; - } - - /** - * Gets a named escaper. - * - * @param string $name The escaper name - * - * @return mixed $escaper A PHP callable - */ - static public function getEscaper($escaper) - { - if (null === self::$escapers) { - self::initializeEscapers(); - } - - return is_string($escaper) && isset(self::$escapers[$escaper]) ? self::$escapers[$escaper] : $escaper; - } - - /** - * Initializes the built-in escapers. - * - * Each function specifies a way for applying a transformation to a string - * passed to it. The purpose is for the string to be "escaped" so it is - * suitable for the format it is being displayed in. - * - * For example, the string: "It's required that you enter a username & password.\n" - * If this were to be displayed as HTML it would be sensible to turn the - * ampersand into '&' and the apostrophe into '&aps;'. However if it were - * going to be used as a string in JavaScript to be displayed in an alert box - * it would be right to leave the string as-is, but c-escape the apostrophe and - * the new line. - * - * For each function there is a define to avoid problems with strings being - * incorrectly specified. - */ - static function initializeEscapers() - { - self::$escapers = array( - 'htmlspecialchars' => - /** - * Runs the PHP function htmlspecialchars on the value passed. - * - * @param string $value the value to escape - * - * @return string the escaped value - */ - function ($value) - { - // Numbers and boolean values get turned into strings which can cause problems - // with type comparisons (e.g. === or is_int() etc). - return is_string($value) ? htmlspecialchars($value, ENT_QUOTES, Escaper::getCharset(), false) : $value; - }, - - 'entities' => - /** - * Runs the PHP function htmlentities on the value passed. - * - * @param string $value the value to escape - * @return string the escaped value - */ - function ($value) - { - // Numbers and boolean values get turned into strings which can cause problems - // with type comparisons (e.g. === or is_int() etc). - return is_string($value) ? htmlentities($value, ENT_QUOTES, Escaper::getCharset(), false) : $value; - }, - - 'raw' => - /** - * An identity function that merely returns that which it is given, the purpose - * being to be able to specify that the value is not to be escaped in any way. - * - * @param string $value the value to escape - * @return string the escaped value - */ - function ($value) - { - return $value; - }, - - 'js' => - /** - * A function that escape all non-alphanumeric characters - * into their \xHH or \uHHHH representations - * - * @param string $value the value to escape - * @return string the escaped value - */ - function ($value) - { - if ('UTF-8' != Escaper::getCharset()) { - $string = Escaper::convertEncoding($string, 'UTF-8', Escaper::getCharset()); - } - - $callback = function ($matches) - { - $char = $matches[0]; - - // \xHH - if (!isset($char[1])) { - return '\\x'.substr('00'.bin2hex($char), -2); - } - - // \uHHHH - $char = Escaper::convertEncoding($char, 'UTF-16BE', 'UTF-8'); - - return '\\u'.substr('0000'.bin2hex($char), -4); - }; - - if (null === $string = preg_replace_callback('#[^\p{L}\p{N} ]#u', $callback, $string)) { - throw new InvalidArgumentException('The string to escape is not a valid UTF-8 string.'); - } - - if ('UTF-8' != Escaper::getCharset()) { - $string = Escaper::convertEncoding($string, Escaper::getCharset(), 'UTF-8'); - } - - return $string; - }, - ); - } - - static public function convertEncoding($string, $to, $from) - { - if (function_exists('iconv')) { - return iconv($from, $to, $string); - } elseif (function_exists('mb_convert_encoding')) { - return mb_convert_encoding($string, $to, $from); - } else { - throw new RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); - } - } -} diff --git a/src/Symfony/Component/OutputEscaper/IteratorDecorator.php b/src/Symfony/Component/OutputEscaper/IteratorDecorator.php deleted file mode 100644 index 3b2263bc7ee0..000000000000 --- a/src/Symfony/Component/OutputEscaper/IteratorDecorator.php +++ /dev/null @@ -1,97 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Output escaping iterator decorator. - * - * This takes an object that implements the Traversable interface and turns it - * into an iterator with each value escaped. - * - * @see Escaper - * @author Fabien Potencier - * @author Mike Squire - */ -class IteratorDecorator extends ObjectDecorator implements \Iterator -{ - /** - * The iterator to be used. - * - * @var \IteratorIterator - */ - private $iterator; - - /** - * Constructs a new escaping iterator using the escaping method and value supplied. - * - * @param string $escaper The escaping method to use - * @param \Traversable $value The iterator to escape - */ - public function __construct($escaper, \Traversable $value) - { - // Set the original value for __call(). Set our own iterator because passing - // it to IteratorIterator will lose any other method calls. - - parent::__construct($escaper, $value); - - $this->iterator = new \IteratorIterator($value); - } - - /** - * Resets the iterator (as required by the Iterator interface). - * - * @return bool true, if the iterator rewinds successfully otherwise false - */ - public function rewind() - { - return $this->iterator->rewind(); - } - - /** - * Escapes and gets the current element (as required by the Iterator interface). - * - * @return mixed The escaped value - */ - public function current() - { - return Escaper::escape($this->escaper, $this->iterator->current()); - } - - /** - * Gets the current key (as required by the Iterator interface). - * - * @return string Iterator key - */ - public function key() - { - return $this->iterator->key(); - } - - /** - * Moves to the next element in the iterator (as required by the Iterator interface). - */ - public function next() - { - return $this->iterator->next(); - } - - /** - * Returns whether the current element is valid or not (as required by the - * Iterator interface). - * - * @return bool true if the current element is valid; false otherwise - */ - public function valid() - { - return $this->iterator->valid(); - } -} diff --git a/src/Symfony/Component/OutputEscaper/ObjectDecorator.php b/src/Symfony/Component/OutputEscaper/ObjectDecorator.php deleted file mode 100644 index 830700e6f6fc..000000000000 --- a/src/Symfony/Component/OutputEscaper/ObjectDecorator.php +++ /dev/null @@ -1,191 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Output escaping object decorator that intercepts all method calls and escapes - * their return values. - * - * @see Escaper - * @author Fabien Potencier - * @author Mike Squire - */ -class ObjectDecorator extends BaseEscaper implements \ArrayAccess, \Countable -{ - /** - * Magic PHP method that intercepts method calls, calls them on the objects - * that is being escaped and escapes the result. - * - * The calling of the method is changed slightly to accommodate passing a - * specific escaping strategy. An additional parameter is appended to the - * argument list which is the escaping strategy. The decorator will remove - * and use this parameter as the escaping strategy if it begins with 'esc_'. - * - * For example if an object, $o, implements methods a() and b($arg): - * - * $o->a() // Escapes the return value of a() - * $o->a('esc_raw') // Uses the escaping strategy 'raw' with a() - * $o->b('a') // Escapes the return value of b('a') - * $o->b('a', 'esc_raw'); // Uses the escaping strategy 'raw' with b('a') - * - * @param string $method The method on the object to be called - * @param array $args An array of arguments to be passed to the method - * - * @return mixed The escaped value returned by the method - */ - public function __call($method, $args) - { - if (count($args) > 0) { - $escaper = $args[count($args) - 1]; - if (is_string($escaper) && 'esc_' === substr($escaper, 0, 4)) { - $escaper = substr($escaper, 4); - - array_pop($args); - } else { - $escaper = $this->escaper; - } - } else { - $escaper = $this->escaper; - } - - $value = call_user_func_array(array($this->value, $method), $args); - - return Escaper::escape($escaper, $value); - } - - /** - * Try to call decorated object __toString() method if exists. - * - * @return string - */ - public function __toString() - { - return Escaper::escape($this->escaper, (string) $this->value); - } - - /** - * Gets a value from the escaper. - * - * @param string $key The name of the value to get - * - * @return mixed The value from the wrapped object - */ - public function __get($key) - { - return Escaper::escape($this->escaper, $this->value->$key); - } - - /** - * Checks whether a value is set on the wrapped object. - * - * @param string $key The name of the value to check - * - * @return boolean Returns true if the value is set - */ - public function __isset($key) - { - return isset($this->value->$key); - } - - /** - * Escapes an object property using the specified escaper. - * - * @param string $key The object property name - * @param string $escaper The escaping strategy prefixed with esc_ (see __call()) - */ - public function getEscapedProperty($key, $escaper) - { - return Escaper::escape(substr($escaper, 4), $this->value->$key); - } - - /** - * Returns true if the supplied offset isset in the array (as required by the ArrayAccess interface). - * - * @param string $offset The offset of the value to check existence of - * - * @return bool true if the offset isset; false otherwise - */ - public function offsetExists($offset) - { - return isset($this->value[$offset]); - } - - /** - * Returns the element associated with the offset supplied (as required by the ArrayAccess interface). - * - * @param string $offset The offset of the value to get - * - * @return mixed The escaped value - */ - public function offsetGet($offset) - { - return Escaper::escape($this->escaper, $this->value[$offset]); - } - - /** - * Throws an exception saying that values cannot be set (this method is - * required for the ArrayAccess interface). - * - * This (and the other Escaper classes) are designed to be read only - * so this is an illegal operation. - * - * @param string $offset (ignored) - * @param string $value (ignored) - * - * @throws \LogicException When trying to set values - */ - public function offsetSet($offset, $value) - { - throw new \LogicException('Cannot set values.'); - } - - /** - * Throws an exception saying that values cannot be unset (this method is - * required for the ArrayAccess interface). - * - * This (and the other Escaper classes) are designed to be read only - * so this is an illegal operation. - * - * @param string $offset (ignored) - * - * @throws \LogicException When trying to unset values - */ - public function offsetUnset($offset) - { - throw new \LogicException('Cannot unset values.'); - } - - /** - * Escapes a key from the array using the specified escaper. - * - * @param string $key The array key - * @param string $escaper The escaping strategy prefixed with esc_ (see __call()) - */ - public function getEscapedKey($key, $escaper) - { - return Escaper::escape(substr($escaper, 4), $this->value[$key]); - } - - /** - * Returns the size of the array (are required by the Countable interface). - * - * @return int The size of the array - */ - public function count() - { - if ($this->value instanceof \Countable) { - return count($this->value); - } - - return call_user_func_array(array($this->value, 'count'), func_get_args()); - } -} diff --git a/src/Symfony/Component/OutputEscaper/SafeDecorator.php b/src/Symfony/Component/OutputEscaper/SafeDecorator.php deleted file mode 100644 index d37159c56e2a..000000000000 --- a/src/Symfony/Component/OutputEscaper/SafeDecorator.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Marks a variable as being safe for output. - * - * @author Fabien Potencier - */ -class SafeDecorator implements SafeDecoratorInterface -{ - protected $value; - - /** - * Constructor. - * - * @param mixed $value The value to mark as safe - */ - public function __construct($value) - { - $this->value = $value; - } - - /** - * Returns the raw value. - * - * @return mixed The raw value - */ - public function getRawValue() - { - return $this->value; - } -} diff --git a/src/Symfony/Component/OutputEscaper/SafeDecoratorInterface.php b/src/Symfony/Component/OutputEscaper/SafeDecoratorInterface.php deleted file mode 100644 index ea4252284647..000000000000 --- a/src/Symfony/Component/OutputEscaper/SafeDecoratorInterface.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Marks a class as being safe for output. - * - * @author Fabien Potencier - */ -interface SafeDecoratorInterface -{ -} diff --git a/src/Symfony/Component/Templating/Engine.php b/src/Symfony/Component/Templating/Engine.php index e90c2ed3f66b..733bd9746fd9 100644 --- a/src/Symfony/Component/Templating/Engine.php +++ b/src/Symfony/Component/Templating/Engine.php @@ -32,6 +32,7 @@ class Engine implements \ArrayAccess protected $stack; protected $charset; protected $cache; + protected $escapers; /** * Constructor. @@ -39,8 +40,9 @@ class Engine implements \ArrayAccess * @param LoaderInterface $loader A loader instance * @param array $renderers An array of renderer instances * @param array $helpers A array of helper instances + * @param array $escapers An array of escapers */ - public function __construct(LoaderInterface $loader, array $renderers = array(), array $helpers = array()) + public function __construct(LoaderInterface $loader, array $renderers = array(), array $helpers = array(), array $escapers = array()) { $this->loader = $loader; $this->renderers = $renderers; @@ -59,6 +61,12 @@ public function __construct(LoaderInterface $loader, array $renderers = array(), foreach ($this->renderers as $renderer) { $renderer->setEngine($this); } + + $this->initializeEscapers(); + + foreach ($this->escapers as $context => $escaper) { + $this->setEscaper($context, $escaper); + } } /** @@ -299,13 +307,13 @@ public function extend($template) /** * Escapes a string by using the current charset. * - * @param string $value A string to escape + * @param mixed $value A variable to escape * - * @return string The escaped string or the original value if not a string + * @return string The escaped value */ - public function escape($value) + public function escape($value, $context = 'html') { - return is_string($value) || (is_object($value) && method_exists($value, '__toString')) ? htmlspecialchars($value, ENT_QUOTES, $this->charset) : $value; + return call_user_func($this->getEscaper($context), $value); } /** @@ -361,4 +369,121 @@ public function splitTemplateName($name) return array($name, array('renderer' => $renderer)); } + + /** + * Adds an escaper for the given context. + * + * @param string $name The escaper context (html, js, ...) + * @param mixed $escaper A PHP callable + */ + public function setEscaper($context, $escaper) + { + $this->escapers[$context] = $escaper; + } + + /** + * Gets an escaper for a given context. + * + * @param string $name The context name + * + * @return mixed $escaper A PHP callable + */ + public function getEscaper($context) + { + if (!isset($this->escapers[$context])) { + throw new \InvalidArgumentException(sprintf('No registered escaper for context "%s".', $context)); + } + + return $this->escapers[$context]; + } + + /** + * Initializes the built-in escapers. + * + * Each function specifies a way for applying a transformation to a string + * passed to it. The purpose is for the string to be "escaped" so it is + * suitable for the format it is being displayed in. + * + * For example, the string: "It's required that you enter a username & password.\n" + * If this were to be displayed as HTML it would be sensible to turn the + * ampersand into '&' and the apostrophe into '&aps;'. However if it were + * going to be used as a string in JavaScript to be displayed in an alert box + * it would be right to leave the string as-is, but c-escape the apostrophe and + * the new line. + * + * For each function there is a define to avoid problems with strings being + * incorrectly specified. + */ + protected function initializeEscapers() + { + $that = $this; + + $this->escapers = array( + 'html' => + /** + * Runs the PHP function htmlspecialchars on the value passed. + * + * @param string $value the value to escape + * + * @return string the escaped value + */ + function ($value) use ($that) + { + // Numbers and boolean values get turned into strings which can cause problems + // with type comparisons (e.g. === or is_int() etc). + return is_string($value) ? htmlspecialchars($value, ENT_QUOTES, $that->getCharset(), false) : $value; + }, + + 'js' => + /** + * A function that escape all non-alphanumeric characters + * into their \xHH or \uHHHH representations + * + * @param string $value the value to escape + * @return string the escaped value + */ + function ($value) use ($that) + { + if ('UTF-8' != $that->getCharset()) { + $string = $that->convertEncoding($string, 'UTF-8', $that->getCharset()); + } + + $callback = function ($matches) use ($that) + { + $char = $matches[0]; + + // \xHH + if (!isset($char[1])) { + return '\\x'.substr('00'.bin2hex($char), -2); + } + + // \uHHHH + $char = $that->convertEncoding($char, 'UTF-16BE', 'UTF-8'); + + return '\\u'.substr('0000'.bin2hex($char), -4); + }; + + if (null === $string = preg_replace_callback('#[^\p{L}\p{N} ]#u', $callback, $string)) { + throw new \InvalidArgumentException('The string to escape is not a valid UTF-8 string.'); + } + + if ('UTF-8' != $that->getCharset()) { + $string = $that->convertEncoding($string, $that->getCharset(), 'UTF-8'); + } + + return $string; + }, + ); + } + + public function convertEncoding($string, $to, $from) + { + if (function_exists('iconv')) { + return iconv($from, $to, $string); + } elseif (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($string, $to, $from); + } else { + throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); + } + } } diff --git a/tests/Symfony/Tests/Component/OutputEscaper/ArrayDecoratorTest.php b/tests/Symfony/Tests/Component/OutputEscaper/ArrayDecoratorTest.php deleted file mode 100644 index 945394aa2627..000000000000 --- a/tests/Symfony/Tests/Component/OutputEscaper/ArrayDecoratorTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Tests\Component\OutputEscaper; - -use Symfony\Component\OutputEscaper\Escaper; - -class ArrayDecoratorTest extends \PHPUnit_Framework_TestCase -{ - static protected $escaped; - - static public function setUpBeforeClass() - { - $a = array('escaped!', 1, null, array(2, 'escaped!')); - - self::$escaped = Escaper::escape('entities', $a); - } - - public function testGetEscapedKey() - { - $this->assertEquals('escaped!', self::$escaped->getEscapedKey(0, 'esc_raw'), '->getEscapedKey() returns the value with an other escaper'); - } - - public function testArrayAccessInterface() - { - $this->assertEquals('<strong>escaped!</strong>', self::$escaped[0], 'The escaped object behaves like an array'); - $this->assertNull(self::$escaped[2], 'The escaped object behaves like an array'); - $this->assertEquals('<strong>escaped!</strong>', self::$escaped[3][1], 'The escaped object behaves like an array'); - - $this->assertTrue(isset(self::$escaped[1]), 'The escaped object behaves like an array (isset)'); - - try { - unset(self::$escaped[0]); - - $this->fail('The escaped object is read only (unset)'); - } catch (\Exception $e) { - $this->assertInstanceOf('\LogicException', $e, 'The escaped object is read only (unset)'); - $this->assertEquals('Cannot unset values.', $e->getMessage(), 'The escaped object is read only (unset)'); - } - - try { - self::$escaped[0] = 12; - - $this->fail('The escaped object is read only (set)'); - } catch (\Exception $e) { - $this->assertInstanceOf('\LogicException', $e, 'The escaped object is read only (set)'); - $this->assertEquals('Cannot set values.', $e->getMessage(), 'The escaped object is read only (set)'); - } - } - - public function testIteratorInterface() - { - foreach (self::$escaped as $key => $value) { - switch ($key) { - case 0: - $this->assertEquals('<strong>escaped!</strong>', $value, 'The escaped object behaves like an array'); - break; - case 1: - $this->assertEquals(1, $value, 'The escaped object behaves like an array'); - break; - case 2: - $this->assertNull($value, 'The escaped object behaves like an array'); - break; - case 3: - break; - default: - $this->fail('The escaped object behaves like an array'); - } - } - } - - public function testCountableInterface() - { - $this->assertEquals(4, count(self::$escaped), 'The escaped object implements the Countable interface'); - } -} diff --git a/tests/Symfony/Tests/Component/OutputEscaper/EscaperTest.php b/tests/Symfony/Tests/Component/OutputEscaper/EscaperTest.php deleted file mode 100644 index 95fc86bb382f..000000000000 --- a/tests/Symfony/Tests/Component/OutputEscaper/EscaperTest.php +++ /dev/null @@ -1,190 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Tests\Component\OutputEscaper; - -use Symfony\Component\OutputEscaper\Escaper; -use Symfony\Component\OutputEscaper\SafeDecorator; -use Symfony\Component\OutputEscaper\IteratorDecorator; -use Symfony\Component\OutputEscaper\ArrayDecorator; -use Symfony\Component\OutputEscaper\ObjectDecorator; - -class EscaperTest extends \PHPUnit_Framework_TestCase -{ - public function testEscapeDoesNotEscapeSpecialValues() - { - $this->assertNull(Escaper::escape('entities', null), '::escape() returns null if the value to escape is null'); - $this->assertFalse(Escaper::escape('entities', false), '::escape() returns false if the value to escape is false'); - $this->assertTrue(Escaper::escape('entities', true), '::escape() returns true if the value to escape is true'); - } - - public function testEscapeDoesNotEscapeAValueWhenEscapingMethodIsRAW() - { - $this->assertEquals('escaped!', Escaper::escape('raw', 'escaped!'), '::escape() takes an escaping strategy function name as its first argument'); - } - - public function testEscapeEscapesStrings() - { - $this->assertEquals('<strong>escaped!</strong>', Escaper::escape('entities', 'escaped!'), '::escape() returns an escaped string if the value to escape is a string'); - $this->assertEquals('<strong>échappé</strong>', Escaper::escape('entities', 'échappé'), '::escape() returns an escaped string if the value to escape is a string'); - } - - public function testEscapeEscapesArrays() - { - $input = array( - 'foo' => 'escaped!', - 'bar' => array('foo' => 'escaped!'), - ); - $output = Escaper::escape('entities', $input); - $this->assertInstanceOf('Symfony\Component\OutputEscaper\ArrayDecorator', $output, '::escape() returns a ArrayDecorator object if the value to escape is an array'); - $this->assertEquals('<strong>escaped!</strong>', $output['foo'], '::escape() escapes all elements of the original array'); - $this->assertEquals('<strong>escaped!</strong>', $output['bar']['foo'], '::escape() is recursive'); - $this->assertEquals($input, $output->getRawValue(), '->getRawValue() returns the unescaped value'); - } - - public function testEscapeEscapesObjects() - { - $input = new OutputEscaperTestClass(); - $output = Escaper::escape('entities', $input); - $this->assertInstanceOf('Symfony\Component\OutputEscaper\ObjectDecorator', $output, '::escape() returns a ObjectDecorator object if the value to escape is an object'); - $this->assertEquals('<strong>escaped!</strong>', $output->getTitle(), '::escape() escapes all methods of the original object'); - $this->assertEquals('<strong>escaped!</strong>', $output->title, '::escape() escapes all properties of the original object'); - $this->assertEquals('<strong>escaped!</strong>', $output->getTitleTitle(), '::escape() is recursive'); - $this->assertEquals($input, $output->getRawValue(), '->getRawValue() returns the unescaped value'); - - $this->assertEquals('<strong>escaped!</strong>', Escaper::escape('entities', $output)->getTitle(), '::escape() does not double escape an object'); - $this->assertInstanceOf('Symfony\Component\OutputEscaper\IteratorDecorator', Escaper::escape('entities', new \DirectoryIterator('.')), '::escape() returns a IteratorDecorator object if the value to escape is an object that implements the ArrayAccess interface'); - } - - public function testEscapeDoesNotEscapeObjectMarkedAsBeingSafe() - { - $this->assertInstanceOf('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass', Escaper::escape('entities', new SafeDecorator(new OutputEscaperTestClass())), '::escape() returns the original value if it is marked as being safe'); - - Escaper::markClassAsSafe('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass'); - $this->assertInstanceOf('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass', Escaper::escape('entities', new OutputEscaperTestClass()), '::escape() returns the original value if the object class is marked as being safe'); - $this->assertInstanceOf('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass', Escaper::escape('entities', new OutputEscaperTestClassChild()), '::escape() returns the original value if one of the object parent class is marked as being safe'); - } - - public function testEscapeCannotEscapeResources() - { - $fh = fopen(__FILE__, 'r'); - try { - Escaper::escape('entities', $fh); - - $this->fail('::escape() throws an InvalidArgumentException if the value cannot be escaped'); - } catch (\InvalidArgumentException $e) { - } - fclose($fh); - } - - public function testUnescapeDoesNotUnescapeSpecialValues() - { - $this->assertNull(Escaper::unescape(null), '::unescape() returns null if the value to unescape is null'); - $this->assertFalse(Escaper::unescape(false), '::unescape() returns false if the value to unescape is false'); - $this->assertTrue(Escaper::unescape(true), '::unescape() returns true if the value to unescape is true'); - } - - public function testUnescapeUnescapesStrings() - { - $this->assertEquals('escaped!', Escaper::unescape('<strong>escaped!</strong>'), '::unescape() returns an unescaped string if the value to unescape is a string'); - $this->assertEquals('échappé', Escaper::unescape('<strong>échappé</strong>'), '::unescape() returns an unescaped string if the value to unescape is a string'); - } - - public function testUnescapeUnescapesArrays() - { - $input = Escaper::escape('entities', array( - 'foo' => 'escaped!', - 'bar' => array('foo' => 'escaped!'), - )); - $output = Escaper::unescape($input); - $this->assertType('array', $output, '::unescape() returns an array if the input is a ArrayDecorator object'); - $this->assertEquals('escaped!', $output['foo'], '::unescape() unescapes all elements of the original array'); - $this->assertEquals('escaped!', $output['bar']['foo'], '::unescape() is recursive'); - } - - public function testUnescapeUnescapesObjects() - { - $object = new OutputEscaperTestClass(); - $input = Escaper::escape('entities', $object); - $output = Escaper::unescape($input); - $this->assertInstanceOf('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass', $output, '::unescape() returns the original object when a ObjectDecorator object is passed'); - $this->assertEquals('escaped!', $output->getTitle(), '::unescape() unescapes all methods of the original object'); - $this->assertEquals('escaped!', $output->title, '::unescape() unescapes all properties of the original object'); - $this->assertEquals('escaped!', $output->getTitleTitle(), '::unescape() is recursive'); - - $this->assertInstanceOf('\DirectoryIterator', Escaper::unescape(Escaper::escape('entities', new \DirectoryIterator('.'))), '::unescape() unescapes IteratorDecorator objects'); - } - - public function testUnescapeDoesNotUnescapeObjectMarkedAsBeingSafe() - { - $this->assertInstanceOf('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass', Escaper::unescape(Escaper::escape('entities', new SafeDecorator(new OutputEscaperTestClass()))), '::unescape() returns the original value if it is marked as being safe'); - - Escaper::markClassAsSafe('OutputEscaperTestClass'); - $this->assertInstanceOf('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass', Escaper::unescape(Escaper::escape('entities', new OutputEscaperTestClass())), '::unescape() returns the original value if the object class is marked as being safe'); - $this->assertInstanceOf('Symfony\Tests\Component\OutputEscaper\OutputEscaperTestClass', Escaper::unescape(Escaper::escape('entities', new OutputEscaperTestClassChild())), '::unescape() returns the original value if one of the object parent class is marked as being safe'); - } - - public function testUnescapeDoesNothingToResources() - { - $fh = fopen(__FILE__, 'r'); - $this->assertEquals($fh, Escaper::unescape($fh), '::unescape() do nothing to resources'); - } - - public function testUnescapeUnescapesMixedArrays() - { - $object = new OutputEscaperTestClass(); - $input = array( - 'foo' => 'bar', - 'bar' => Escaper::escape('entities', 'bar'), - 'foobar' => Escaper::escape('entities', $object), - ); - $output = array( - 'foo' => 'bar', - 'bar' => 'bar', - 'foobar' => $object, - ); - $this->assertEquals($output, Escaper::unescape($input), '::unescape() unescapes values with some escaped and unescaped values'); - } - - public function testEscaperRememberSafeDecoratedObjects() - { - $object = new \stdClass(); - $object->foo = '
'; - - $var = new SafeDecorator($object); - Escaper::escape('entities', $var); - - $escaped = Escaper::escape('entities', $object); - - $this->assertEquals('
', $escaped->foo); - } -} - -class OutputEscaperTestClass -{ - public $title = 'escaped!'; - - public function getTitle() - { - return $this->title; - } - - public function getTitleTitle() - { - $o = new self; - - return $o->getTitle(); - } -} - -class OutputEscaperTestClassChild extends OutputEscaperTestClass -{ -} diff --git a/tests/Symfony/Tests/Component/OutputEscaper/ObjectDecoratorTest.php b/tests/Symfony/Tests/Component/OutputEscaper/ObjectDecoratorTest.php deleted file mode 100644 index c9bdb1b91468..000000000000 --- a/tests/Symfony/Tests/Component/OutputEscaper/ObjectDecoratorTest.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Tests\Component\OutputEscaper; - -use Symfony\Component\OutputEscaper\Escaper; - -class ObjectDecoratorTest extends \PHPUnit_Framework_TestCase -{ - static protected $escaped; - - static public function setUpBeforeClass() - { - $object = new OutputEscaperTest(); - - self::$escaped = Escaper::escape('entities', $object); - } - - public function testGenericBehavior() - { - $this->assertEquals('<strong>escaped!</strong>', self::$escaped->getTitle(), 'The escaped object behaves like the real object'); - - $array = self::$escaped->getTitles(); - $this->assertEquals('<strong>escaped!</strong>', $array[2], 'The escaped object behaves like the real object'); - - $this->assertEquals('Hello <strong>Fabien</strong>', self::$escaped->sayHello('Fabien'), 'The escaped object behaves like the real object'); - $this->assertEquals('Hello Fabien', self::$escaped->sayHello('Fabien', 'esc_raw'), 'The escaped object behaves like the real object'); - } - - public function testMagicToString() - { - $this->assertEquals('<strong>escaped!</strong>', self::$escaped->__toString(), 'The escaped object behaves like the real object'); - } - - public function testMagicGet() - { - $this->assertEquals('<em>escape me</em>', self::$escaped->someMember, 'The escaped object behaves like the real object'); - } - - public function testMagicIsset() - { - $this->assertTrue(isset(self::$escaped->someMember), 'The escaped object behaves like the real object'); - $this->assertFalse(isset(self::$escaped->invalidMember), 'The escaped object behaves like the real object'); - } -} - -class OutputEscaperTest -{ - public $someMember = 'escape me'; - - public function __toString() - { - return $this->getTitle(); - } - - public function getTitle() - { - return 'escaped!'; - } - - public function sayHello($name) - { - return sprintf('Hello %s', $name); - } - - public function getTitles() - { - return array(1, 2, 'escaped!'); - } - - public function get($key) - { - return isset($this->{$key}) ? $this->{$key} : null; - } -} diff --git a/tests/Symfony/Tests/Component/OutputEscaper/SafeDecoratorTest.php b/tests/Symfony/Tests/Component/OutputEscaper/SafeDecoratorTest.php deleted file mode 100644 index 235702a6538e..000000000000 --- a/tests/Symfony/Tests/Component/OutputEscaper/SafeDecoratorTest.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Tests\Component\OutputEscaper; - -use Symfony\Component\OutputEscaper\SafeDecorator; - -class SafeDecoratorTest extends \PHPUnit_Framework_TestCase -{ - public function testGetRawValue() - { - $safe = new SafeDecorator('foo'); - $this->assertEquals('foo', $safe->getRawValue(), '->getValue() returns the embedded value'); - } -}