Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
EscaperNodeVisitor.php
001 <?php
002
003 /*
004 * This file is part of Twig.
005 *
006 * (c) Fabien Potencier
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Twig\NodeVisitor;
013
014 use Twig\Environment;
015 use Twig\Extension\EscaperExtension;
016 use Twig\Node\AutoEscapeNode;
017 use Twig\Node\BlockNode;
018 use Twig\Node\BlockReferenceNode;
019 use Twig\Node\DoNode;
020 use Twig\Node\Expression\ConditionalExpression;
021 use Twig\Node\Expression\ConstantExpression;
022 use Twig\Node\Expression\FilterExpression;
023 use Twig\Node\Expression\InlinePrint;
024 use Twig\Node\ImportNode;
025 use Twig\Node\ModuleNode;
026 use Twig\Node\Node;
027 use Twig\Node\PrintNode;
028 use Twig\NodeTraverser;
029
030 /**
031 * @author Fabien Potencier <fabien@symfony.com>
032 */
033 final class EscaperNodeVisitor extends AbstractNodeVisitor
034 {
035 private $statusStack = [];
036 private $blocks = [];
037 private $safeAnalysis;
038 private $traverser;
039 private $defaultStrategy = false;
040 private $safeVars = [];
041
042 public function __construct()
043 {
044 $this->safeAnalysis = new SafeAnalysisNodeVisitor();
045 }
046
047 protected function doEnterNode(Node $node, Environment $env)
048 {
049 if ($node instanceof ModuleNode) {
050 if ($env->hasExtension(EscaperExtension::class) && $defaultStrategy = $env->getExtension(EscaperExtension::class)->getDefaultStrategy($node->getTemplateName())) {
051 $this->defaultStrategy = $defaultStrategy;
052 }
053 $this->safeVars = [];
054 $this->blocks = [];
055 } elseif ($node instanceof AutoEscapeNode) {
056 $this->statusStack[] = $node->getAttribute('value');
057 } elseif ($node instanceof BlockNode) {
058 $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
059 } elseif ($node instanceof ImportNode) {
060 $this->safeVars[] = $node->getNode('var')->getAttribute('name');
061 }
062
063 return $node;
064 }
065
066 protected function doLeaveNode(Node $node, Environment $env)
067 {
068 if ($node instanceof ModuleNode) {
069 $this->defaultStrategy = false;
070 $this->safeVars = [];
071 $this->blocks = [];
072 } elseif ($node instanceof FilterExpression) {
073 return $this->preEscapeFilterNode($node, $env);
074 } elseif ($node instanceof PrintNode && false !== $type = $this->needEscaping($env)) {
075 $expression = $node->getNode('expr');
076 if ($expression instanceof ConditionalExpression && $this->shouldUnwrapConditional($expression, $env, $type)) {
077 return new DoNode($this->unwrapConditional($expression, $env, $type), $expression->getTemplateLine());
078 }
079
080 return $this->escapePrintNode($node, $env, $type);
081 }
082
083 if ($node instanceof AutoEscapeNode || $node instanceof BlockNode) {
084 array_pop($this->statusStack);
085 } elseif ($node instanceof BlockReferenceNode) {
086 $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
087 }
088
089 return $node;
090 }
091
092 private function shouldUnwrapConditional(ConditionalExpression $expression, Environment $env, $type)
093 {
094 $expr2Safe = $this->isSafeFor($type, $expression->getNode('expr2'), $env);
095 $expr3Safe = $this->isSafeFor($type, $expression->getNode('expr3'), $env);
096
097 return $expr2Safe !== $expr3Safe;
098 }
099
100 private function unwrapConditional(ConditionalExpression $expression, Environment $env, $type)
101 {
102 // convert "echo a ? b : c" to "a ? echo b : echo c" recursively
103 $expr2 = $expression->getNode('expr2');
104 if ($expr2 instanceof ConditionalExpression && $this->shouldUnwrapConditional($expr2, $env, $type)) {
105 $expr2 = $this->unwrapConditional($expr2, $env, $type);
106 } else {
107 $expr2 = $this->escapeInlinePrintNode(new InlinePrint($expr2, $expr2->getTemplateLine()), $env, $type);
108 }
109 $expr3 = $expression->getNode('expr3');
110 if ($expr3 instanceof ConditionalExpression && $this->shouldUnwrapConditional($expr3, $env, $type)) {
111 $expr3 = $this->unwrapConditional($expr3, $env, $type);
112 } else {
113 $expr3 = $this->escapeInlinePrintNode(new InlinePrint($expr3, $expr3->getTemplateLine()), $env, $type);
114 }
115
116 return new ConditionalExpression($expression->getNode('expr1'), $expr2, $expr3, $expression->getTemplateLine());
117 }
118
119 private function escapeInlinePrintNode(InlinePrint $node, Environment $env, $type)
120 {
121 $expression = $node->getNode('node');
122
123 if ($this->isSafeFor($type, $expression, $env)) {
124 return $node;
125 }
126
127 return new InlinePrint($this->getEscaperFilter($type, $expression), $node->getTemplateLine());
128 }
129
130 private function escapePrintNode(PrintNode $node, Environment $env, $type)
131 {
132 if (false === $type) {
133 return $node;
134 }
135
136 $expression = $node->getNode('expr');
137
138 if ($this->isSafeFor($type, $expression, $env)) {
139 return $node;
140 }
141
142 $class = \get_class($node);
143
144 return new $class($this->getEscaperFilter($type, $expression), $node->getTemplateLine());
145 }
146
147 private function preEscapeFilterNode(FilterExpression $filter, Environment $env)
148 {
149 $name = $filter->getNode('filter')->getAttribute('value');
150
151 $type = $env->getFilter($name)->getPreEscape();
152 if (null === $type) {
153 return $filter;
154 }
155
156 $node = $filter->getNode('node');
157 if ($this->isSafeFor($type, $node, $env)) {
158 return $filter;
159 }
160
161 $filter->setNode('node', $this->getEscaperFilter($type, $node));
162
163 return $filter;
164 }
165
166 private function isSafeFor($type, Node $expression, $env)
167 {
168 $safe = $this->safeAnalysis->getSafe($expression);
169
170 if (null === $safe) {
171 if (null === $this->traverser) {
172 $this->traverser = new NodeTraverser($env, [$this->safeAnalysis]);
173 }
174
175 $this->safeAnalysis->setSafeVars($this->safeVars);
176
177 $this->traverser->traverse($expression);
178 $safe = $this->safeAnalysis->getSafe($expression);
179 }
180
181 return \in_array($type, $safe) || \in_array('all', $safe);
182 }
183
184 private function needEscaping(Environment $env)
185 {
186 if (\count($this->statusStack)) {
187 return $this->statusStack[\count($this->statusStack) - 1];
188 }
189
190 return $this->defaultStrategy ? $this->defaultStrategy : false;
191 }
192
193 private function getEscaperFilter(string $type, Node $node): FilterExpression
194 {
195 $line = $node->getTemplateLine();
196 $name = new ConstantExpression('escape', $line);
197 $args = new Node([new ConstantExpression((string) $type, $line), new ConstantExpression(null, $line), new ConstantExpression(true, $line)]);
198
199 return new FilterExpression($node, $name, $args, $line);
200 }
201
202 public function getPriority()
203 {
204 return 0;
205 }
206 }
207
208 class_alias('Twig\NodeVisitor\EscaperNodeVisitor', 'Twig_NodeVisitor_Escaper');
209