initial import

This commit is contained in:
Alchemy
2011-02-16 16:09:48 +01:00
parent 399a584b6f
commit 339d23c06d
5539 changed files with 2028637 additions and 1 deletions

View File

@@ -0,0 +1,123 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig_NodeVisitor_Escaper implements output escaping.
*
* @package twig
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
{
protected $statusStack = array();
protected $blocks = array();
protected $safeAnalysis;
protected $traverser;
function __construct()
{
$this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
}
/**
* Called before child nodes are visited.
*
* @param Twig_NodeInterface $node The node to visit
* @param Twig_Environment $env The Twig environment instance
*
* @param Twig_NodeInterface The modified node
*/
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_AutoEscape) {
$this->statusStack[] = $node->getAttribute('value');
} elseif ($node instanceof Twig_Node_Print) {
return $this->escapeNode($node, $env, $this->needEscaping($env));
} elseif ($node instanceof Twig_Node_Block) {
$this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
}
return $node;
}
/**
* Called after child nodes are visited.
*
* @param Twig_NodeInterface $node The node to visit
* @param Twig_Environment $env The Twig environment instance
*
* @param Twig_NodeInterface The modified node
*/
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
array_pop($this->statusStack);
} elseif ($node instanceof Twig_Node_BlockReference) {
$this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
}
return $node;
}
protected function escapeNode(Twig_NodeInterface $node, Twig_Environment $env, $type)
{
if (false === $type) {
return $node;
}
$expression = $node instanceof Twig_Node_Print ? $node->getNode('expr') : $node;
$safe = $this->safeAnalysis->getSafe($expression);
if (null === $safe) {
if (null === $this->traverser) {
$this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
}
$this->traverser->traverse($expression);
$safe = $this->safeAnalysis->getSafe($expression);
}
if (false !== in_array($type, $safe) || false !== in_array('all', $safe)) {
return $node;
}
if ($node instanceof Twig_Node_Print) {
return new Twig_Node_Print(
$this->getEscaperFilter($type, $expression),
$node->getLine()
);
}
return $this->getEscaperFilter($type, $node);
}
protected function needEscaping(Twig_Environment $env)
{
if (count($this->statusStack)) {
return $this->statusStack[count($this->statusStack) - 1];
}
if ($env->hasExtension('escaper') && $env->getExtension('escaper')->isGlobal()) {
return 'html';
}
return false;
}
protected function getEscaperFilter($type, Twig_NodeInterface $node)
{
$line = $node->getLine();
$name = new Twig_Node_Expression_Constant('escape', $line);
$args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line)));
return new Twig_Node_Expression_Filter($node, $name, $args, $line);
}
}

View File

@@ -0,0 +1,84 @@
<?php
class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
{
protected $data = array();
public function getSafe(Twig_NodeInterface $node)
{
$hash = spl_object_hash($node);
if (isset($this->data[$hash])) {
foreach($this->data[$hash] as $bucket) {
if ($bucket['key'] === $node) {
return $bucket['value'];
}
}
}
return null;
}
protected function setSafe(Twig_NodeInterface $node, array $safe)
{
$hash = spl_object_hash($node);
if (isset($this->data[$hash])) {
foreach($this->data[$hash] as &$bucket) {
if ($bucket['key'] === $node) {
$bucket['value'] = $safe;
return;
}
}
}
$this->data[$hash][] = array(
'key' => $node,
'value' => $safe,
);
}
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
return $node;
}
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Expression_Constant) {
// constants are marked safe for all
$this->setSafe($node, array('all'));
} elseif ($node instanceof Twig_Node_Expression_Conditional) {
// instersect safeness of both operands
$safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
$this->setSafe($node, $safe);
} elseif ($node instanceof Twig_Node_Expression_Filter) {
// filter expression is safe when the filter is safe
$filterMap = $env->getFilters();
$name = $node->getNode('filter')->getAttribute('value');
$args = $node->getNode('arguments');
if (isset($filterMap[$name])) {
$this->setSafe($node, $filterMap[$name]->getSafe($args));
} else {
$this->setSafe($node, array());
}
} else {
$this->setSafe($node, array());
}
return $node;
}
protected function intersectSafe(array $a = null, array $b = null)
{
if (null === $a || null === $b) {
return array();
}
if (in_array('all', $a)) {
return $b;
}
if (in_array('all', $b)) {
return $a;
}
return array_intersect($a, $b);
}
}

View File

@@ -0,0 +1,78 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig_NodeVisitor_Sandbox implements sandboxing.
*
* @package twig
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
{
protected $inAModule = false;
protected $tags;
protected $filters;
/**
* Called before child nodes are visited.
*
* @param Twig_NodeInterface $node The node to visit
* @param Twig_Environment $env The Twig environment instance
*
* @param Twig_NodeInterface The modified node
*/
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
$this->inAModule = true;
$this->tags = array();
$this->filters = array();
return $node;
} elseif ($this->inAModule) {
// look for tags
if ($node->getNodeTag()) {
$this->tags[] = $node->getNodeTag();
}
// look for filters
if ($node instanceof Twig_Node_Expression_Filter) {
$this->filters[] = $node->getNode('filter')->getAttribute('value');
}
// look for simple print statements ({{ article }})
if ($node instanceof Twig_Node_Print && $node->getNode('expr') instanceof Twig_Node_Expression_Name) {
return new Twig_Node_SandboxedPrint($node);
}
}
return $node;
}
/**
* Called after child nodes are visited.
*
* @param Twig_NodeInterface $node The node to visit
* @param Twig_Environment $env The Twig environment instance
*
* @param Twig_NodeInterface The modified node
*/
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
$this->inAModule = false;
return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags));
}
return $node;
}
}