vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php line 137

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\NodeVisitor;
  11. use Twig\Environment;
  12. use Twig\Node\Expression\BlockReferenceExpression;
  13. use Twig\Node\Expression\ConditionalExpression;
  14. use Twig\Node\Expression\ConstantExpression;
  15. use Twig\Node\Expression\FilterExpression;
  16. use Twig\Node\Expression\FunctionExpression;
  17. use Twig\Node\Expression\GetAttrExpression;
  18. use Twig\Node\Expression\MethodCallExpression;
  19. use Twig\Node\Expression\NameExpression;
  20. use Twig\Node\Expression\ParentExpression;
  21. use Twig\Node\Node;
  22. final class SafeAnalysisNodeVisitor extends AbstractNodeVisitor
  23. {
  24. private $data = [];
  25. private $safeVars = [];
  26. public function setSafeVars($safeVars)
  27. {
  28. $this->safeVars = $safeVars;
  29. }
  30. public function getSafe(Node $node)
  31. {
  32. $hash = spl_object_hash($node);
  33. if (!isset($this->data[$hash])) {
  34. return;
  35. }
  36. foreach ($this->data[$hash] as $bucket) {
  37. if ($bucket['key'] !== $node) {
  38. continue;
  39. }
  40. if (\in_array('html_attr', $bucket['value'])) {
  41. $bucket['value'][] = 'html';
  42. }
  43. return $bucket['value'];
  44. }
  45. }
  46. private function setSafe(Node $node, array $safe)
  47. {
  48. $hash = spl_object_hash($node);
  49. if (isset($this->data[$hash])) {
  50. foreach ($this->data[$hash] as &$bucket) {
  51. if ($bucket['key'] === $node) {
  52. $bucket['value'] = $safe;
  53. return;
  54. }
  55. }
  56. }
  57. $this->data[$hash][] = [
  58. 'key' => $node,
  59. 'value' => $safe,
  60. ];
  61. }
  62. protected function doEnterNode(Node $node, Environment $env)
  63. {
  64. return $node;
  65. }
  66. protected function doLeaveNode(Node $node, Environment $env)
  67. {
  68. if ($node instanceof ConstantExpression) {
  69. // constants are marked safe for all
  70. $this->setSafe($node, ['all']);
  71. } elseif ($node instanceof BlockReferenceExpression) {
  72. // blocks are safe by definition
  73. $this->setSafe($node, ['all']);
  74. } elseif ($node instanceof ParentExpression) {
  75. // parent block is safe by definition
  76. $this->setSafe($node, ['all']);
  77. } elseif ($node instanceof ConditionalExpression) {
  78. // intersect safeness of both operands
  79. $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
  80. $this->setSafe($node, $safe);
  81. } elseif ($node instanceof FilterExpression) {
  82. // filter expression is safe when the filter is safe
  83. $name = $node->getNode('filter')->getAttribute('value');
  84. $args = $node->getNode('arguments');
  85. if (false !== $filter = $env->getFilter($name)) {
  86. $safe = $filter->getSafe($args);
  87. if (null === $safe) {
  88. $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
  89. }
  90. $this->setSafe($node, $safe);
  91. } else {
  92. $this->setSafe($node, []);
  93. }
  94. } elseif ($node instanceof FunctionExpression) {
  95. // function expression is safe when the function is safe
  96. $name = $node->getAttribute('name');
  97. $args = $node->getNode('arguments');
  98. $function = $env->getFunction($name);
  99. if (false !== $function) {
  100. $this->setSafe($node, $function->getSafe($args));
  101. } else {
  102. $this->setSafe($node, []);
  103. }
  104. } elseif ($node instanceof MethodCallExpression) {
  105. if ($node->getAttribute('safe')) {
  106. $this->setSafe($node, ['all']);
  107. } else {
  108. $this->setSafe($node, []);
  109. }
  110. } elseif ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression) {
  111. $name = $node->getNode('node')->getAttribute('name');
  112. if (\in_array($name, $this->safeVars)) {
  113. $this->setSafe($node, ['all']);
  114. } else {
  115. $this->setSafe($node, []);
  116. }
  117. } else {
  118. $this->setSafe($node, []);
  119. }
  120. return $node;
  121. }
  122. private function intersectSafe(array $a = null, array $b = null): array
  123. {
  124. if (null === $a || null === $b) {
  125. return [];
  126. }
  127. if (\in_array('all', $a)) {
  128. return $b;
  129. }
  130. if (\in_array('all', $b)) {
  131. return $a;
  132. }
  133. return array_intersect($a, $b);
  134. }
  135. public function getPriority()
  136. {
  137. return 0;
  138. }
  139. }
  140. class_alias('Twig\NodeVisitor\SafeAnalysisNodeVisitor', 'Twig_NodeVisitor_SafeAnalysis');