Dotclear

source: inc/libs/twig/NodeVisitor/Escaper.php @ 1101:7273894e61b8

Revision 1101:7273894e61b8, 5.3 KB checked in by Dsls <dsls@…>, 13 years ago (diff)

Twig 1.12.2

Line 
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2009 Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12/**
13 * Twig_NodeVisitor_Escaper implements output escaping.
14 *
15 * @package    twig
16 * @author     Fabien Potencier <fabien@symfony.com>
17 */
18class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
19{
20    protected $statusStack = array();
21    protected $blocks = array();
22    protected $safeAnalysis;
23    protected $traverser;
24    protected $defaultStrategy = false;
25    protected $safeVars = array();
26
27    public function __construct()
28    {
29        $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
30    }
31
32    /**
33     * Called before child nodes are visited.
34     *
35     * @param Twig_NodeInterface $node The node to visit
36     * @param Twig_Environment   $env  The Twig environment instance
37     *
38     * @return Twig_NodeInterface The modified node
39     */
40    public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
41    {
42        if ($node instanceof Twig_Node_Module) {
43            if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
44                $this->defaultStrategy = $defaultStrategy;
45            }
46            $this->safeVars = array();
47        } elseif ($node instanceof Twig_Node_AutoEscape) {
48            $this->statusStack[] = $node->getAttribute('value');
49        } elseif ($node instanceof Twig_Node_Block) {
50            $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
51        } elseif ($node instanceof Twig_Node_Import) {
52            $this->safeVars[] = $node->getNode('var')->getAttribute('name');
53        }
54
55        return $node;
56    }
57
58    /**
59     * Called after child nodes are visited.
60     *
61     * @param Twig_NodeInterface $node The node to visit
62     * @param Twig_Environment   $env  The Twig environment instance
63     *
64     * @return Twig_NodeInterface The modified node
65     */
66    public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
67    {
68        if ($node instanceof Twig_Node_Module) {
69            $this->defaultStrategy = false;
70            $this->safeVars = array();
71        } elseif ($node instanceof Twig_Node_Expression_Filter) {
72            return $this->preEscapeFilterNode($node, $env);
73        } elseif ($node instanceof Twig_Node_Print) {
74            return $this->escapePrintNode($node, $env, $this->needEscaping($env));
75        }
76
77        if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
78            array_pop($this->statusStack);
79        } elseif ($node instanceof Twig_Node_BlockReference) {
80            $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
81        }
82
83        return $node;
84    }
85
86    protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
87    {
88        if (false === $type) {
89            return $node;
90        }
91
92        $expression = $node->getNode('expr');
93
94        if ($this->isSafeFor($type, $expression, $env)) {
95            return $node;
96        }
97
98        $class = get_class($node);
99
100        return new $class(
101            $this->getEscaperFilter($type, $expression),
102            $node->getLine()
103        );
104    }
105
106    protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
107    {
108        $name = $filter->getNode('filter')->getAttribute('value');
109
110        $type = $env->getFilter($name)->getPreEscape();
111        if (null === $type) {
112            return $filter;
113        }
114
115        $node = $filter->getNode('node');
116        if ($this->isSafeFor($type, $node, $env)) {
117            return $filter;
118        }
119
120        $filter->setNode('node', $this->getEscaperFilter($type, $node));
121
122        return $filter;
123    }
124
125    protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
126    {
127        $safe = $this->safeAnalysis->getSafe($expression);
128
129        if (null === $safe) {
130            if (null === $this->traverser) {
131                $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
132            }
133
134            $this->safeAnalysis->setSafeVars($this->safeVars);
135
136            $this->traverser->traverse($expression);
137            $safe = $this->safeAnalysis->getSafe($expression);
138        }
139
140        return in_array($type, $safe) || in_array('all', $safe);
141    }
142
143    protected function needEscaping(Twig_Environment $env)
144    {
145        if (count($this->statusStack)) {
146            return $this->statusStack[count($this->statusStack) - 1];
147        }
148
149        return $this->defaultStrategy ? $this->defaultStrategy : false;
150    }
151
152    protected function getEscaperFilter($type, Twig_NodeInterface $node)
153    {
154        $line = $node->getLine();
155        $name = new Twig_Node_Expression_Constant('escape', $line);
156        $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
157
158        return new Twig_Node_Expression_Filter($node, $name, $args, $line);
159    }
160
161    /**
162     * {@inheritdoc}
163     */
164    public function getPriority()
165    {
166        return 0;
167    }
168}
Note: See TracBrowser for help on using the repository browser.

Sites map