1. sfOutputEscaper.class.php
  2. /** * Abstract class that provides an interface for escaping of output. * * @package symfony * @subpackage view * @author Mike Squire * @version SVN: $Id: sfOutputEscaper.class.php 21908 2009-09-11 12:06:21Z fabien $ */
  3. abstract class sfOutputEscaper
  4. {
  5. /**
  6. * The value that is to be escaped.
  7. *
  8. * @var mixed
  9. */
  10. protected $value;
  11. /**
  12. * The escaping method that is going to be applied to the value and its
  13. * children. This is actually the name of a PHP callable.
  14. *
  15. * @var string
  16. */
  17. protected $escapingMethod;
  18. static protected $safeClasses = array();
  19. /**
  20. * Constructor stores the escaping method and value.
  21. *
  22. * Since sfOutputEscaper is an abstract class, instances cannot be created
  23. * directly but the constructor will be inherited by sub-classes.
  24. *
  25. * @param string $escapingMethod Escaping method
  26. * @param string $value Escaping value
  27. */
  28. public function __construct($escapingMethod, $value)
  29. {
  30. $this->value = $value;
  31. $this->escapingMethod = $escapingMethod;
  32. }
  33. /**
  34. * Decorates a PHP variable with something that will escape any data obtained
  35. * from it.
  36. *
  37. * The following cases are dealt with:
  38. *
  39. * - The value is null or false: null or false is returned.
  40. * - The value is scalar: the result of applying the escaping method is
  41. * returned.
  42. * - The value is an array or an object that implements the ArrayAccess
  43. * interface: the array is decorated such that accesses to elements yield
  44. * an escaped value.
  45. * - The value implements the Traversable interface (either an Iterator, an
  46. * IteratorAggregate or an internal PHP class that implements
  47. * Traversable): decorated much like the array.
  48. * - The value is another type of object: decorated such that the result of
  49. * method calls is escaped.
  50. *
  51. * The escaping method is actually the name of a PHP callable. There are a set
  52. * of standard escaping methods listed in the escaping helper
  53. * (EscapingHelper.php).
  54. *
  55. * @param string $escapingMethod The escaping method (a PHP callable) to apply to the value
  56. * @param mixed $value The value to escape
  57. *
  58. * @return mixed Escaping value
  59. *
  60. * @throws InvalidArgumentException If the escaping fails
  61. */
  62. public static function escape($escapingMethod, $value)
  63. {
  64. if (null === $value)
  65. {
  66. return $value;
  67. }
  68. // Scalars are anything other than arrays, objects and resources.
  69. if (is_scalar($value))
  70. {
  71. return call_user_func($escapingMethod, $value);
  72. }
  73. if (is_array($value))
  74. {
  75. return new sfOutputEscaperArrayDecorator($escapingMethod, $value);
  76. }
  77. if (is_object($value))
  78. {
  79. if ($value instanceof sfOutputEscaper)
  80. {
  81. // avoid double decoration
  82. $copy = clone $value;
  83. $copy->escapingMethod = $escapingMethod;
  84. return $copy;
  85. }
  86. else if (self::isClassMarkedAsSafe(get_class($value)))
  87. {
  88. // the class or one of its children is marked as safe
  89. // return the unescaped object
  90. return $value;
  91. }
  92. else if ($value instanceof sfOutputEscaperSafe)
  93. {
  94. // do not escape objects marked as safe
  95. // return the original object
  96. return $value->getValue();
  97. }
  98. else if ($value instanceof Traversable)
  99. {
  100. return new sfOutputEscaperIteratorDecorator($escapingMethod, $value);
  101. }
  102. else
  103. {
  104. return new sfOutputEscaperObjectDecorator($escapingMethod, $value);
  105. }
  106. }
  107. // it must be a resource; cannot escape that.
  108. throw new InvalidArgumentException(sprintf('Unable to escape value "%s".', var_export($value, true)));
  109. }
  110. /**
  111. * Unescapes a value that has been escaped previously with the escape() method.
  112. *
  113. * @param mixed $value The value to unescape
  114. *
  115. * @return mixed Unescaped value
  116. *
  117. * @throws InvalidArgumentException If the escaping fails
  118. */
  119. static public function unescape($value)
  120. {
  121. if (null === $value || is_bool($value))
  122. {
  123. return $value;
  124. }
  125. if (is_scalar($value))
  126. {
  127. return html_entity_decode($value, ENT_QUOTES, sfConfig::get('sf_charset'));
  128. }
  129. elseif (is_array($value))
  130. {
  131. foreach ($value as $name => $v)
  132. {
  133. $value[$name] = self::unescape($v);
  134. }
  135. return $value;
  136. }
  137. elseif (is_object($value))
  138. {
  139. return $value instanceof sfOutputEscaper ? $value->getRawValue() : $value;
  140. }
  141. return $value;
  142. }
  143. /**
  144. * Returns true if the class if marked as safe.
  145. *
  146. * @param string $class A class name
  147. *
  148. * @return bool true if the class if safe, false otherwise
  149. */
  150. static public function isClassMarkedAsSafe($class)
  151. {
  152. if (in_array($class, self::$safeClasses))
  153. {
  154. return true;
  155. }
  156. foreach (self::$safeClasses as $safeClass)
  157. {
  158. if (is_subclass_of($class, $safeClass))
  159. {
  160. return true;
  161. }
  162. }
  163. return false;
  164. }
  165. /**
  166. * Marks an array of classes (and all its children) as being safe for output.
  167. *
  168. * @param array $classes An array of class names
  169. */
  170. static public function markClassesAsSafe(array $classes)
  171. {
  172. self::$safeClasses = array_unique(array_merge(self::$safeClasses, $classes));
  173. }
  174. /**
  175. * Marks a class (and all its children) as being safe for output.
  176. *
  177. * @param string $class A class name
  178. */
  179. static public function markClassAsSafe($class)
  180. {
  181. self::markClassesAsSafe(array($class));
  182. }
  183. /**
  184. * Returns the raw value associated with this instance.
  185. *
  186. * Concrete instances of sfOutputEscaper classes decorate a value which is
  187. * stored by the constructor. This returns that original, unescaped, value.
  188. *
  189. * @return mixed The original value used to construct the decorator
  190. */
  191. public function getRawValue()
  192. {
  193. return $this->value;
  194. }
  195. /**
  196. * Gets a value from the escaper.
  197. *
  198. * @param string $var Value to get
  199. *
  200. * @return mixed Value
  201. */
  202. public function __get($var)
  203. {
  204. return $this->escape($this->escapingMethod, $this->value->$var);
  205. }
  206. }

Debug toolbar