Start working

Modified some paths to be more generic and not require rewrite.  Some
instances of phase names have been changed, others are still in process.
This commit is contained in:
mattbk
2015-10-28 22:04:20 -05:00
parent eda91ff492
commit abadd5bc38
192 changed files with 16085 additions and 7 deletions

View File

@ -0,0 +1,157 @@
<?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.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor
{
protected $statusStack = array();
protected $blocks = array();
protected $safeAnalysis;
protected $traverser;
protected $defaultStrategy = false;
protected $safeVars = array();
public function __construct()
{
$this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
}
/**
* {@inheritdoc}
*/
protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
$this->defaultStrategy = $defaultStrategy;
}
$this->safeVars = array();
} elseif ($node instanceof Twig_Node_AutoEscape) {
$this->statusStack[] = $node->getAttribute('value');
} elseif ($node instanceof Twig_Node_Block) {
$this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
} elseif ($node instanceof Twig_Node_Import) {
$this->safeVars[] = $node->getNode('var')->getAttribute('name');
}
return $node;
}
/**
* {@inheritdoc}
*/
protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
$this->defaultStrategy = false;
$this->safeVars = array();
} elseif ($node instanceof Twig_Node_Expression_Filter) {
return $this->preEscapeFilterNode($node, $env);
} elseif ($node instanceof Twig_Node_Print) {
return $this->escapePrintNode($node, $env, $this->needEscaping($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 escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
{
if (false === $type) {
return $node;
}
$expression = $node->getNode('expr');
if ($this->isSafeFor($type, $expression, $env)) {
return $node;
}
$class = get_class($node);
return new $class(
$this->getEscaperFilter($type, $expression),
$node->getLine()
);
}
protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
{
$name = $filter->getNode('filter')->getAttribute('value');
$type = $env->getFilter($name)->getPreEscape();
if (null === $type) {
return $filter;
}
$node = $filter->getNode('node');
if ($this->isSafeFor($type, $node, $env)) {
return $filter;
}
$filter->setNode('node', $this->getEscaperFilter($type, $node));
return $filter;
}
protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
{
$safe = $this->safeAnalysis->getSafe($expression);
if (null === $safe) {
if (null === $this->traverser) {
$this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
}
$this->safeAnalysis->setSafeVars($this->safeVars);
$this->traverser->traverse($expression);
$safe = $this->safeAnalysis->getSafe($expression);
}
return in_array($type, $safe) || in_array('all', $safe);
}
protected function needEscaping(Twig_Environment $env)
{
if (count($this->statusStack)) {
return $this->statusStack[count($this->statusStack) - 1];
}
return $this->defaultStrategy ? $this->defaultStrategy : 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), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
return new Twig_Node_Expression_Filter($node, $name, $args, $line);
}
/**
* {@inheritdoc}
*/
public function getPriority()
{
return 0;
}
}

View File

@ -0,0 +1,271 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig_NodeVisitor_Optimizer tries to optimizes the AST.
*
* This visitor is always the last registered one.
*
* You can configure which optimizations you want to activate via the
* optimizer mode.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor
{
const OPTIMIZE_ALL = -1;
const OPTIMIZE_NONE = 0;
const OPTIMIZE_FOR = 2;
const OPTIMIZE_RAW_FILTER = 4;
const OPTIMIZE_VAR_ACCESS = 8;
protected $loops = array();
protected $loopsTargets = array();
protected $optimizers;
protected $prependedNodes = array();
protected $inABody = false;
/**
* Constructor.
*
* @param int $optimizers The optimizer mode
*/
public function __construct($optimizers = -1)
{
if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
}
$this->optimizers = $optimizers;
}
/**
* {@inheritdoc}
*/
protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
{
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
$this->enterOptimizeFor($node, $env);
}
if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
if ($this->inABody) {
if (!$node instanceof Twig_Node_Expression) {
if (get_class($node) !== 'Twig_Node') {
array_unshift($this->prependedNodes, array());
}
} else {
$node = $this->optimizeVariables($node, $env);
}
} elseif ($node instanceof Twig_Node_Body) {
$this->inABody = true;
}
}
return $node;
}
/**
* {@inheritdoc}
*/
protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
{
$expression = $node instanceof Twig_Node_Expression;
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
$this->leaveOptimizeFor($node, $env);
}
if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
$node = $this->optimizeRawFilter($node, $env);
}
$node = $this->optimizePrintNode($node, $env);
if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
if ($node instanceof Twig_Node_Body) {
$this->inABody = false;
} elseif ($this->inABody) {
if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
$nodes = array();
foreach (array_unique($prependedNodes) as $name) {
$nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
}
$nodes[] = $node;
$node = new Twig_Node($nodes);
}
}
}
return $node;
}
protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env)
{
if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
$this->prependedNodes[0][] = $node->getAttribute('name');
return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
}
return $node;
}
/**
* Optimizes print nodes.
*
* It replaces:
*
* * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
*
* @param Twig_NodeInterface $node A Node
* @param Twig_Environment $env The current Twig environment
*
* @return Twig_NodeInterface
*/
protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if (!$node instanceof Twig_Node_Print) {
return $node;
}
if (
$node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
$node->getNode('expr') instanceof Twig_Node_Expression_Parent
) {
$node->getNode('expr')->setAttribute('output', true);
return $node->getNode('expr');
}
return $node;
}
/**
* Removes "raw" filters.
*
* @param Twig_NodeInterface $node A Node
* @param Twig_Environment $env The current Twig environment
*
* @return Twig_NodeInterface
*/
protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
return $node->getNode('node');
}
return $node;
}
/**
* Optimizes "for" tag by removing the "loop" variable creation whenever possible.
*
* @param Twig_NodeInterface $node A Node
* @param Twig_Environment $env The current Twig environment
*/
protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_For) {
// disable the loop variable by default
$node->setAttribute('with_loop', false);
array_unshift($this->loops, $node);
array_unshift($this->loopsTargets, $node->getNode('value_target')->getAttribute('name'));
array_unshift($this->loopsTargets, $node->getNode('key_target')->getAttribute('name'));
} elseif (!$this->loops) {
// we are outside a loop
return;
}
// when do we need to add the loop variable back?
// the loop variable is referenced for the current loop
elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
$node->setAttribute('always_defined', true);
$this->addLoopToCurrent();
}
// optimize access to loop targets
elseif ($node instanceof Twig_Node_Expression_Name && in_array($node->getAttribute('name'), $this->loopsTargets)) {
$node->setAttribute('always_defined', true);
}
// block reference
elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
$this->addLoopToCurrent();
}
// include without the only attribute
elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
$this->addLoopToAll();
}
// include function without the with_context=false parameter
elseif ($node instanceof Twig_Node_Expression_Function
&& 'include' === $node->getAttribute('name')
&& (!$node->getNode('arguments')->hasNode('with_context')
|| false !== $node->getNode('arguments')->getNode('with_context')->getAttribute('value')
)
) {
$this->addLoopToAll();
}
// the loop variable is referenced via an attribute
elseif ($node instanceof Twig_Node_Expression_GetAttr
&& (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
|| 'parent' === $node->getNode('attribute')->getAttribute('value')
)
&& (true === $this->loops[0]->getAttribute('with_loop')
|| ($node->getNode('node') instanceof Twig_Node_Expression_Name
&& 'loop' === $node->getNode('node')->getAttribute('name')
)
)
) {
$this->addLoopToAll();
}
}
/**
* Optimizes "for" tag by removing the "loop" variable creation whenever possible.
*
* @param Twig_NodeInterface $node A Node
* @param Twig_Environment $env The current Twig environment
*/
protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_For) {
array_shift($this->loops);
array_shift($this->loopsTargets);
array_shift($this->loopsTargets);
}
}
protected function addLoopToCurrent()
{
$this->loops[0]->setAttribute('with_loop', true);
}
protected function addLoopToAll()
{
foreach ($this->loops as $loop) {
$loop->setAttribute('with_loop', true);
}
}
/**
* {@inheritdoc}
*/
public function getPriority()
{
return 255;
}
}

View File

@ -0,0 +1,154 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor
{
protected $data = array();
protected $safeVars = array();
public function setSafeVars($safeVars)
{
$this->safeVars = $safeVars;
}
public function getSafe(Twig_NodeInterface $node)
{
$hash = spl_object_hash($node);
if (!isset($this->data[$hash])) {
return;
}
foreach ($this->data[$hash] as $bucket) {
if ($bucket['key'] !== $node) {
continue;
}
if (in_array('html_attr', $bucket['value'])) {
$bucket['value'][] = 'html';
}
return $bucket['value'];
}
}
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,
);
}
/**
* {@inheritdoc}
*/
protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
{
return $node;
}
/**
* {@inheritdoc}
*/
protected function doLeaveNode(Twig_Node $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_BlockReference) {
// blocks are safe by definition
$this->setSafe($node, array('all'));
} elseif ($node instanceof Twig_Node_Expression_Parent) {
// parent block is safe by definition
$this->setSafe($node, array('all'));
} elseif ($node instanceof Twig_Node_Expression_Conditional) {
// intersect 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
$name = $node->getNode('filter')->getAttribute('value');
$args = $node->getNode('arguments');
if (false !== $filter = $env->getFilter($name)) {
$safe = $filter->getSafe($args);
if (null === $safe) {
$safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
}
$this->setSafe($node, $safe);
} else {
$this->setSafe($node, array());
}
} elseif ($node instanceof Twig_Node_Expression_Function) {
// function expression is safe when the function is safe
$name = $node->getAttribute('name');
$args = $node->getNode('arguments');
$function = $env->getFunction($name);
if (false !== $function) {
$this->setSafe($node, $function->getSafe($args));
} else {
$this->setSafe($node, array());
}
} elseif ($node instanceof Twig_Node_Expression_MethodCall) {
if ($node->getAttribute('safe')) {
$this->setSafe($node, array('all'));
} else {
$this->setSafe($node, array());
}
} elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
$name = $node->getNode('node')->getAttribute('name');
// attributes on template instances are safe
if ('_self' == $name || in_array($name, $this->safeVars)) {
$this->setSafe($node, array('all'));
} 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);
}
/**
* {@inheritdoc}
*/
public function getPriority()
{
return 0;
}
}

View File

@ -0,0 +1,82 @@
<?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.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor
{
protected $inAModule = false;
protected $tags;
protected $filters;
protected $functions;
/**
* {@inheritdoc}
*/
protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
$this->inAModule = true;
$this->tags = array();
$this->filters = array();
$this->functions = array();
return $node;
} elseif ($this->inAModule) {
// look for tags
if ($node->getNodeTag() && !isset($this->tags[$node->getNodeTag()])) {
$this->tags[$node->getNodeTag()] = $node;
}
// look for filters
if ($node instanceof Twig_Node_Expression_Filter && !isset($this->filters[$node->getNode('filter')->getAttribute('value')])) {
$this->filters[$node->getNode('filter')->getAttribute('value')] = $node;
}
// look for functions
if ($node instanceof Twig_Node_Expression_Function && !isset($this->functions[$node->getAttribute('name')])) {
$this->functions[$node->getAttribute('name')] = $node;
}
// wrap print to check __toString() calls
if ($node instanceof Twig_Node_Print) {
return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
}
}
return $node;
}
/**
* {@inheritdoc}
*/
protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
$this->inAModule = false;
$node->setNode('display_start', new Twig_Node(array(new Twig_Node_CheckSecurity($this->filters, $this->tags, $this->functions), $node->getNode('display_start'))));
}
return $node;
}
/**
* {@inheritdoc}
*/
public function getPriority()
{
return 0;
}
}