Prevent importing or calling reserved macro names

This also fixes the logic detecting reserved macro names to account for
the fact that they are compiled prefixed with get() since a very long
time and the logic preventing conflicts was broken.
This commit is contained in:
Christophe Coevoet
2015-08-12 12:06:21 +02:00
committed by Fabien Potencier
parent cfb0593028
commit 7b6c0e971f
7 changed files with 60 additions and 11 deletions
+7 -1
View File
@@ -387,7 +387,13 @@ class Twig_ExpressionParser
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
}
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
$name = $arg->getAttribute('value');
if ($this->parser->isReservedMacroName($name)) {
throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword', $name), $token->getLine(), $this->parser->getFilename());
}
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
+18 -9
View File
@@ -254,21 +254,30 @@ class Twig_Parser implements Twig_ParserInterface
public function setMacro($name, Twig_Node_Macro $node)
{
if (null === $this->reservedMacroNames) {
$this->reservedMacroNames = array();
$r = new ReflectionClass($this->env->getBaseTemplateClass());
foreach ($r->getMethods() as $method) {
$this->reservedMacroNames[] = $method->getName();
}
}
if (in_array($name, $this->reservedMacroNames)) {
if ($this->isReservedMacroName($name)) {
throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
}
$this->macros[$name] = $node;
}
public function isReservedMacroName($name)
{
if (null === $this->reservedMacroNames) {
$this->reservedMacroNames = array();
$r = new ReflectionClass($this->env->getBaseTemplateClass());
foreach ($r->getMethods() as $method) {
$methodName = strtolower($method->getName());
if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) {
$this->reservedMacroNames[] = substr($methodName, 3);
}
}
}
return in_array(strtolower($name), $this->reservedMacroNames);
}
public function addTrait($trait)
{
$this->traits[] = $trait;
+4
View File
@@ -52,6 +52,10 @@ class Twig_TokenParser_From extends Twig_TokenParser
$node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
foreach ($targets as $name => $alias) {
if ($this->parser->isReservedMacroName($name)) {
throw new Twig_Error_Syntax(sprintf('"%s" cannot be an imported macro as it is a reserved keyword', $name), $token->getLine(), $stream->getFilename());
}
$this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
}
@@ -0,0 +1,9 @@
--TEST--
"from" tag with reserved name
--TEMPLATE--
{% from 'forms.twig' import templateName %}
--TEMPLATE(forms.twig)--
--DATA--
return array()
--EXCEPTION--
Twig_Error_Syntax: "templateName" cannot be an imported macro as it is a reserved keyword in "index.twig" at line 2
@@ -0,0 +1,11 @@
--TEST--
"from" tag with reserved name
--TEMPLATE--
{% import 'forms.twig' as macros %}
{{ macros.parent() }}
--TEMPLATE(forms.twig)--
--DATA--
return array()
--EXCEPTION--
Twig_Error_Syntax: "parent" cannot be called as macro as it is a reserved keyword in "index.twig" at line 4
@@ -0,0 +1,10 @@
--TEST--
"macro" tag with reserved name
--TEMPLATE--
{% macro parent(arg1, arg2) %}
parent
{% endmacro %}
--DATA--
return array()
--EXCEPTION--
Twig_Error_Syntax: "parent" cannot be used as a macro name as it is a reserved keyword in "index.twig" at line 2
+1 -1
View File
@@ -16,7 +16,7 @@ class Twig_Tests_ParserTest extends PHPUnit_Framework_TestCase
public function testSetMacroThrowsExceptionOnReservedMethods()
{
$parser = $this->getParser();
$parser->setMacro('display', $this->getMock('Twig_Node_Macro', array(), array(), '', null));
$parser->setMacro('parent', $this->getMock('Twig_Node_Macro', array(), array(), '', null));
}
/**