vendor/twig/twig/src/Extension/EscaperExtension.php line 139

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) Fabien Potencier
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Twig\Extension;
  11. use Twig\Environment;
  12. use Twig\FileExtensionEscapingStrategy;
  13. use Twig\Node\Expression\ConstantExpression;
  14. use Twig\Node\Expression\Filter\RawFilter;
  15. use Twig\Node\Node;
  16. use Twig\NodeVisitor\EscaperNodeVisitor;
  17. use Twig\Runtime\EscaperRuntime;
  18. use Twig\TokenParser\AutoEscapeTokenParser;
  19. use Twig\TwigFilter;
  20. final class EscaperExtension extends AbstractExtension
  21. {
  22. private $environment;
  23. private $escapers = [];
  24. private $escaper;
  25. private $defaultStrategy;
  26. /**
  27. * @param string|false|callable $defaultStrategy An escaping strategy
  28. *
  29. * @see setDefaultStrategy()
  30. */
  31. public function __construct($defaultStrategy = 'html')
  32. {
  33. $this->setDefaultStrategy($defaultStrategy);
  34. }
  35. public function getTokenParsers(): array
  36. {
  37. return [new AutoEscapeTokenParser()];
  38. }
  39. public function getNodeVisitors(): array
  40. {
  41. return [new EscaperNodeVisitor()];
  42. }
  43. public function getFilters(): array
  44. {
  45. return [
  46. new TwigFilter('escape', [EscaperRuntime::class, 'escape'], ['is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
  47. new TwigFilter('e', [EscaperRuntime::class, 'escape'], ['is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
  48. new TwigFilter('raw', null, ['is_safe' => ['all'], 'node_class' => RawFilter::class]),
  49. ];
  50. }
  51. public function getLastModified(): int
  52. {
  53. return max(
  54. parent::getLastModified(),
  55. filemtime((new \ReflectionClass(EscaperRuntime::class))->getFileName()),
  56. );
  57. }
  58. /**
  59. * @deprecated since Twig 3.10
  60. */
  61. public function setEnvironment(Environment $environment): void
  62. {
  63. $triggerDeprecation = \func_num_args() > 1 ? func_get_arg(1) : true;
  64. if ($triggerDeprecation) {
  65. trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated and not needed if you are using methods from "Twig\Runtime\EscaperRuntime".', __METHOD__);
  66. }
  67. $this->environment = $environment;
  68. $this->escaper = $environment->getRuntime(EscaperRuntime::class);
  69. }
  70. /**
  71. * @return void
  72. *
  73. * @deprecated since Twig 3.10
  74. */
  75. public function setEscaperRuntime(EscaperRuntime $escaper)
  76. {
  77. trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated and not needed if you are using methods from "Twig\Runtime\EscaperRuntime".', __METHOD__);
  78. $this->escaper = $escaper;
  79. }
  80. /**
  81. * Sets the default strategy to use when not defined by the user.
  82. *
  83. * The strategy can be a valid PHP callback that takes the template
  84. * name as an argument and returns the strategy to use.
  85. *
  86. * @param string|false|callable(string $templateName): string $defaultStrategy An escaping strategy
  87. */
  88. public function setDefaultStrategy($defaultStrategy): void
  89. {
  90. if ('name' === $defaultStrategy) {
  91. $defaultStrategy = [FileExtensionEscapingStrategy::class, 'guess'];
  92. }
  93. $this->defaultStrategy = $defaultStrategy;
  94. }
  95. /**
  96. * Gets the default strategy to use when not defined by the user.
  97. *
  98. * @param string $name The template name
  99. *
  100. * @return string|false The default strategy to use for the template
  101. */
  102. public function getDefaultStrategy(string $name)
  103. {
  104. // disable string callables to avoid calling a function named html or js,
  105. // or any other upcoming escaping strategy
  106. if (!\is_string($this->defaultStrategy) && false !== $this->defaultStrategy) {
  107. return \call_user_func($this->defaultStrategy, $name);
  108. }
  109. return $this->defaultStrategy;
  110. }
  111. /**
  112. * Defines a new escaper to be used via the escape filter.
  113. *
  114. * @param string $strategy The strategy name that should be used as a strategy in the escape call
  115. * @param callable(Environment, string, string): string $callable A valid PHP callable
  116. *
  117. * @return void
  118. *
  119. * @deprecated since Twig 3.10
  120. */
  121. public function setEscaper($strategy, callable $callable)
  122. {
  123. trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::setEscaper()" method instead (be warned that Environment is not passed anymore to the callable).', __METHOD__);
  124. if (!isset($this->environment)) {
  125. throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
  126. }
  127. $this->escapers[$strategy] = $callable;
  128. $callable = function ($string, $charset) use ($callable) {
  129. return $callable($this->environment, $string, $charset);
  130. };
  131. $this->escaper->setEscaper($strategy, $callable);
  132. }
  133. /**
  134. * Gets all defined escapers.
  135. *
  136. * @return array<string, callable(Environment, string, string): string> An array of escapers
  137. *
  138. * @deprecated since Twig 3.10
  139. */
  140. public function getEscapers()
  141. {
  142. trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::getEscaper()" method instead.', __METHOD__);
  143. return $this->escapers;
  144. }
  145. /**
  146. * @return void
  147. *
  148. * @deprecated since Twig 3.10
  149. */
  150. public function setSafeClasses(array $safeClasses = [])
  151. {
  152. trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::setSafeClasses()" method instead.', __METHOD__);
  153. if (!isset($this->escaper)) {
  154. throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
  155. }
  156. $this->escaper->setSafeClasses($safeClasses);
  157. }
  158. /**
  159. * @return void
  160. *
  161. * @deprecated since Twig 3.10
  162. */
  163. public function addSafeClass(string $class, array $strategies)
  164. {
  165. trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::addSafeClass()" method instead.', __METHOD__);
  166. if (!isset($this->escaper)) {
  167. throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
  168. }
  169. $this->escaper->addSafeClass($class, $strategies);
  170. }
  171. /**
  172. * @internal
  173. *
  174. * @return array<string>
  175. */
  176. public static function escapeFilterIsSafe(Node $filterArgs)
  177. {
  178. foreach ($filterArgs as $arg) {
  179. if ($arg instanceof ConstantExpression) {
  180. return [$arg->getAttribute('value')];
  181. }
  182. return [];
  183. }
  184. return ['html'];
  185. }
  186. }