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