aboutsummaryrefslogtreecommitdiffhomepage
path: root/inc/Twig/NodeVisitor/SafeAnalysis.php
diff options
context:
space:
mode:
Diffstat (limited to 'inc/Twig/NodeVisitor/SafeAnalysis.php')
-rw-r--r--inc/Twig/NodeVisitor/SafeAnalysis.php131
1 files changed, 131 insertions, 0 deletions
diff --git a/inc/Twig/NodeVisitor/SafeAnalysis.php b/inc/Twig/NodeVisitor/SafeAnalysis.php
new file mode 100644
index 00000000..c4bbd812
--- /dev/null
+++ b/inc/Twig/NodeVisitor/SafeAnalysis.php
@@ -0,0 +1,131 @@
1<?php
2
3class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
4{
5 protected $data = array();
6 protected $safeVars = array();
7
8 public function setSafeVars($safeVars)
9 {
10 $this->safeVars = $safeVars;
11 }
12
13 public function getSafe(Twig_NodeInterface $node)
14 {
15 $hash = spl_object_hash($node);
16 if (isset($this->data[$hash])) {
17 foreach ($this->data[$hash] as $bucket) {
18 if ($bucket['key'] === $node) {
19 return $bucket['value'];
20 }
21 }
22 }
23 }
24
25 protected function setSafe(Twig_NodeInterface $node, array $safe)
26 {
27 $hash = spl_object_hash($node);
28 if (isset($this->data[$hash])) {
29 foreach ($this->data[$hash] as &$bucket) {
30 if ($bucket['key'] === $node) {
31 $bucket['value'] = $safe;
32
33 return;
34 }
35 }
36 }
37 $this->data[$hash][] = array(
38 'key' => $node,
39 'value' => $safe,
40 );
41 }
42
43 public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
44 {
45 return $node;
46 }
47
48 public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
49 {
50 if ($node instanceof Twig_Node_Expression_Constant) {
51 // constants are marked safe for all
52 $this->setSafe($node, array('all'));
53 } elseif ($node instanceof Twig_Node_Expression_BlockReference) {
54 // blocks are safe by definition
55 $this->setSafe($node, array('all'));
56 } elseif ($node instanceof Twig_Node_Expression_Parent) {
57 // parent block is safe by definition
58 $this->setSafe($node, array('all'));
59 } elseif ($node instanceof Twig_Node_Expression_Conditional) {
60 // intersect safeness of both operands
61 $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
62 $this->setSafe($node, $safe);
63 } elseif ($node instanceof Twig_Node_Expression_Filter) {
64 // filter expression is safe when the filter is safe
65 $name = $node->getNode('filter')->getAttribute('value');
66 $args = $node->getNode('arguments');
67 if (false !== $filter = $env->getFilter($name)) {
68 $safe = $filter->getSafe($args);
69 if (null === $safe) {
70 $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
71 }
72 $this->setSafe($node, $safe);
73 } else {
74 $this->setSafe($node, array());
75 }
76 } elseif ($node instanceof Twig_Node_Expression_Function) {
77 // function expression is safe when the function is safe
78 $name = $node->getAttribute('name');
79 $args = $node->getNode('arguments');
80 $function = $env->getFunction($name);
81 if (false !== $function) {
82 $this->setSafe($node, $function->getSafe($args));
83 } else {
84 $this->setSafe($node, array());
85 }
86 } elseif ($node instanceof Twig_Node_Expression_MethodCall) {
87 if ($node->getAttribute('safe')) {
88 $this->setSafe($node, array('all'));
89 } else {
90 $this->setSafe($node, array());
91 }
92 } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
93 $name = $node->getNode('node')->getAttribute('name');
94 // attributes on template instances are safe
95 if ('_self' == $name || in_array($name, $this->safeVars)) {
96 $this->setSafe($node, array('all'));
97 } else {
98 $this->setSafe($node, array());
99 }
100 } else {
101 $this->setSafe($node, array());
102 }
103
104 return $node;
105 }
106
107 protected function intersectSafe(array $a = null, array $b = null)
108 {
109 if (null === $a || null === $b) {
110 return array();
111 }
112
113 if (in_array('all', $a)) {
114 return $b;
115 }
116
117 if (in_array('all', $b)) {
118 return $a;
119 }
120
121 return array_intersect($a, $b);
122 }
123
124 /**
125 * {@inheritdoc}
126 */
127 public function getPriority()
128 {
129 return 0;
130 }
131}