Commit 517b44dd authored by webchick's avatar webchick

Issue #2462393 by stefan.r, joelpittet: Upgrade Twig to 1.18.1 from 1.18.0

parent 873c5aab
......@@ -4,7 +4,7 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "8f0a2765121612251cd2967473bb66e0",
"hash": "304089b3fa329c66764fdc353c5e0e83",
"packages": [
{
"name": "behat/mink",
......@@ -2850,20 +2850,20 @@
},
{
"name": "twig/twig",
"version": "v1.18.0",
"version": "v1.18.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf"
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/4cf7464348e7f9893a93f7096a90b73722be99cf",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9f70492f44398e276d1b81c1b43adfe6751c7b7f",
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
"php": ">=5.2.7"
},
"type": "library",
"extra": {
......@@ -2903,7 +2903,7 @@
"keywords": [
"templating"
],
"time": "2015-01-25 17:32:08"
"time": "2015-04-19 08:30:27"
},
{
"name": "zendframework/zend-escaper",
......
......@@ -3100,23 +3100,23 @@
},
{
"name": "twig/twig",
"version": "v1.18.0",
"version_normalized": "1.18.0.0",
"version": "v1.18.1",
"version_normalized": "1.18.1.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf"
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/4cf7464348e7f9893a93f7096a90b73722be99cf",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9f70492f44398e276d1b81c1b43adfe6751c7b7f",
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
"php": ">=5.2.7"
},
"time": "2015-01-25 17:32:08",
"time": "2015-04-19 08:30:27",
"type": "library",
"extra": {
"branch-alias": {
......
......@@ -7,6 +7,12 @@ php:
- 5.5
- 5.6
- hhvm
- nightly
- hhvm-nightly
allow_failures:
- php: nightly
- php: hhvm-nightly
env:
- TWIG_EXT=no
......@@ -20,3 +26,7 @@ matrix:
exclude:
- php: hhvm
env: TWIG_EXT=yes
- php: hhvm-nightly
env: TWIG_EXT=yes
- php: nightly
env: TWIG_EXT=yes
* 1.18.0 (2015-XX-XX)
* 1.18.1 (2015-04-19)
* fixed memory leaks in the C extension
* deprecated Twig_Loader_String
* fixed the slice filter when used with a SimpleXMLElement object
* fixed filesystem loader when trying to load non-files (like directories)
* 1.18.0 (2015-01-25)
* fixed some error messages where the line was wrong (unknown variables or argument names)
* added a new way to customize the main Module node (via empty nodes)
......
......@@ -27,7 +27,7 @@
"forum": "https://groups.google.com/forum/#!forum/twig-users"
},
"require": {
"php": ">=5.2.4"
"php": ">=5.2.7"
},
"autoload": {
"psr-0" : {
......
......@@ -106,7 +106,9 @@ The following options are available:
to avoid collision with built-in escaping strategies).
As of Twig 1.17, the ``filename`` escaping strategy determines the escaping
strategy to use for a template based on the template filename extension.
strategy to use for a template based on the template filename extension (this
strategy does not incur any overhead at runtime as auto-escaping is done at
compilation time.)
* ``optimizations``: A flag that indicates which optimizations to apply
(default to ``-1`` -- all optimizations are enabled; set it to ``0`` to
......
......@@ -101,6 +101,12 @@ Interfaces
those constants Twig_Template::ANY_CALL, Twig_Template::ARRAY_CALL,
Twig_Template::METHOD_CALL)
Loaders
-------
* As of Twig 1.x, ``Twig_Loader_String`` is deprecated and will be removed in
2.0.
Globals
-------
......
......@@ -50,8 +50,11 @@ Installing the C extension
The C extension was added in Twig 1.4.
.. note::
The C extension is **optional** but as it brings some nice performance
improvements, you might want to install it in your production environment.
The C extension is **optional** but it brings some nice performance
improvements. Note that the extension is not a replacement for the PHP
code; it only implements a small part of the PHP code to improve the
performance at runtime; you must still install the regular PHP code.
Twig comes with a C extension that enhances the performance of the Twig
runtime engine; install it like any other PHP extensions:
......
......@@ -316,56 +316,6 @@ This can be easily achieved with the following code::
return $node;
}
Using the Template name to set the default Escaping Strategy
------------------------------------------------------------
.. versionadded:: 1.8
This recipe requires Twig 1.8 or later.
The ``autoescape`` option determines the default escaping strategy to use when
no escaping is applied on a variable. When Twig is used to mostly generate
HTML files, you can set it to ``html`` and explicitly change it to ``js`` when
you have some dynamic JavaScript files thanks to the ``autoescape`` tag:
.. code-block:: jinja
{% autoescape 'js' %}
... some JS ...
{% endautoescape %}
But if you have many HTML and JS files, and if your template names follow some
conventions, you can instead determine the default escaping strategy to use
based on the template name. Let's say that your template names always end
with ``.html`` for HTML files, ``.js`` for JavaScript ones, and ``.css`` for
stylesheets, here is how you can configure Twig::
class TwigEscapingGuesser
{
function guess($filename)
{
// get the format
$format = substr($filename, strrpos($filename, '.') + 1);
switch ($format) {
case 'js':
return 'js';
case 'css':
return 'css';
case 'html':
default:
return 'html';
}
}
}
$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
'autoescape' => array(new TwigEscapingGuesser(), 'guess'),
));
This dynamic strategy does not incur any overhead at runtime as auto-escaping
is done at compilation time.
Using a Database to store Templates
-----------------------------------
......
......@@ -15,17 +15,21 @@
#ifndef PHP_TWIG_H
#define PHP_TWIG_H
#define PHP_TWIG_VERSION "1.18.0"
#define PHP_TWIG_VERSION "1.18.1"
#include "php.h"
extern zend_module_entry twig_module_entry;
#define phpext_twig_ptr &twig_module_entry
#ifndef PHP_WIN32
zend_module_entry *get_module(void);
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_FUNCTION(twig_template_get_attributes);
PHP_RSHUTDOWN_FUNCTION(twig);
#endif
This diff is collapsed.
......@@ -23,10 +23,10 @@ class Twig_Autoloader
*/
public static function register($prepend = false)
{
if (version_compare(phpversion(), '5.3.0', '>=')) {
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
} else {
if (PHP_VERSION_ID < 50300) {
spl_autoload_register(array(__CLASS__, 'autoload'));
} else {
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
}
}
......
......@@ -16,7 +16,7 @@
*/
class Twig_Environment
{
const VERSION = '1.18.0';
const VERSION = '1.18.1';
protected $charset;
protected $loader;
......
......@@ -57,7 +57,7 @@ class Twig_Error extends Exception
*/
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
if (PHP_VERSION_ID < 50300) {
$this->previous = $previous;
parent::__construct('');
} else {
......@@ -188,7 +188,7 @@ protected function guessTemplateInfo()
$template = null;
$templateClass = null;
if (version_compare(phpversion(), '5.3.6', '>=')) {
if (PHP_VERSION_ID >= 50306) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
} else {
$backtrace = debug_backtrace();
......
......@@ -617,7 +617,7 @@ function twig_urlencode_filter($url)
return rawurlencode($url);
}
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
if (PHP_VERSION_ID < 50300) {
/**
* JSON encodes a variable.
*
......@@ -707,7 +707,7 @@ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $prese
$item = $item->getIterator();
}
if ($start >= 0 && $length >= 0) {
if ($start >= 0 && $length >= 0 && $item instanceof Iterator) {
try {
return iterator_to_array(new LimitIterator($item, $start, $length === null ? -1 : $length), $preserveKeys);
} catch (OutOfBoundsException $exception) {
......@@ -1073,9 +1073,7 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
return $string;
case 'url':
// hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
// at that point however PHP 5.2.* support can be removed
if (PHP_VERSION < '5.3.0') {
if (PHP_VERSION_ID < 50300) {
return str_replace('%7E', '~', rawurlencode($string));
}
......
......@@ -183,10 +183,11 @@ protected function findTemplate($name)
}
foreach ($this->paths[$namespace] as $path) {
if (false !== $realpath = realpath($path.'/'.$shortname)) {
return $this->cache[$name] = $realpath;
}
if (is_file($path.'/'.$shortname)) {
if (false !== $realpath = realpath($path.'/'.$shortname)) {
return $this->cache[$name] = $realpath;
}
return $this->cache[$name] = $path.'/'.$shortname;
}
}
......
......@@ -19,6 +19,8 @@
* source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself.
*
* @deprecated since 1.18.1 (to be removed in 2.0)
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
......
......@@ -28,9 +28,13 @@ public function __construct($filename, $index, Twig_Node_Expression $variables =
protected function addGetTemplate(Twig_Compiler $compiler)
{
$compiler
->write("\$this->env->loadTemplate(")
->write("\$this->loadTemplate(")
->string($this->getAttribute('filename'))
->raw(', ')
->repr($compiler->getFilename())
->raw(', ')
->repr($this->getLine())
->raw(', ')
->string($this->getAttribute('index'))
->raw(")")
;
......
......@@ -120,6 +120,8 @@ protected function getArguments($callable, $arguments)
} elseif (is_object($callable) && !$callable instanceof Closure) {
$r = new ReflectionObject($callable);
$r = $r->getMethod('__invoke');
} elseif (is_string($callable) && false !== strpos($callable, '::')) {
$r = new ReflectionMethod($callable);
} else {
$r = new ReflectionFunction($callable);
}
......
......@@ -46,7 +46,7 @@ public function compile(Twig_Compiler $compiler)
// remove the non-PHP 5.4 version when PHP 5.3 support is dropped
// as the non-optimized version is just a workaround for slow ternary operator
// when the context has a lot of variables
if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
if (PHP_VERSION_ID >= 50400) {
// PHP 5.4 ternary operator performance was optimized
$compiler
->raw('(isset($context[')
......
......@@ -39,8 +39,12 @@ public function compile(Twig_Compiler $compiler)
$compiler->raw("\$this");
} else {
$compiler
->raw('$this->env->loadTemplate(')
->raw('$this->loadTemplate(')
->subcompile($this->getNode('expr'))
->raw(', ')
->repr($compiler->getFilename())
->raw(', ')
->repr($this->getLine())
->raw(")")
;
}
......
......@@ -60,12 +60,15 @@ public function compile(Twig_Compiler $compiler)
protected function addGetTemplate(Twig_Compiler $compiler)
{
$method = $this->getNode('expr') instanceof Twig_Node_Expression_Constant ? 'loadTemplate' : 'resolveTemplate';
$compiler
->write(sprintf('$this->env->%s(', $method))
->subcompile($this->getNode('expr'))
->raw(')')
;
->write("\$this->loadTemplate(")
->subcompile($this->getNode('expr'))
->raw(', ')
->repr($compiler->getFilename())
->raw(', ')
->repr($this->getLine())
->raw(")")
;
}
protected function addTemplateArguments(Twig_Compiler $compiler)
......
......@@ -114,8 +114,12 @@ protected function compileGetParent(Twig_Compiler $compiler)
$compiler->subcompile($parent);
} else {
$compiler
->raw("\$this->env->resolveTemplate(")
->raw("\$this->loadTemplate(")
->subcompile($parent)
->raw(', ')
->repr($compiler->getFilename())
->raw(', ')
->repr($this->getNode('parent')->getLine())
->raw(")")
;
}
......@@ -155,19 +159,13 @@ protected function compileConstructor(Twig_Compiler $compiler)
} elseif ($parent instanceof Twig_Node_Expression_Constant) {
$compiler
->addDebugInfo($parent)
->write("try {\n")
->indent()
->write("\$this->parent = \$this->env->loadTemplate(")
->write("\$this->parent = \$this->loadTemplate(")
->subcompile($parent)
->raw(', ')
->repr($compiler->getFilename())
->raw(', ')
->repr($this->getNode('parent')->getLine())
->raw(");\n")
->outdent()
->write("} catch (Twig_Error_Loader \$e) {\n")
->indent()
->write("\$e->setTemplateFile(\$this->getTemplateName());\n")
->write(sprintf("\$e->setTemplateLine(%d);\n\n", $parent->getLine()))
->write("throw \$e;\n")
->outdent()
->write("}\n\n")
;
}
......@@ -395,8 +393,12 @@ protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
{
if ($node instanceof Twig_Node_Expression_Constant) {
$compiler
->write(sprintf("%s = \$this->env->loadTemplate(", $var))
->write(sprintf("%s = \$this->loadTemplate(", $var))
->subcompile($node)
->raw(', ')
->repr($compiler->getFilename())
->raw(', ')
->repr($node->getLine())
->raw(");\n")
;
} else {
......@@ -407,7 +409,12 @@ protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
->write(sprintf("if (!%s", $var))
->raw(" instanceof Twig_Template) {\n")
->indent()
->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
->write(sprintf("%s = \$this->loadTemplate(%s")
->raw(', ')
->repr($compiler->getFilename())
->raw(', ')
->repr($node->getLine())
->raw(");\n", $var, $var))
->outdent()
->write("}\n")
;
......
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a module node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_SandboxedModule extends Twig_Node_Module
{
protected $usedFilters;
protected $usedTags;
protected $usedFunctions;
public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
{
parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'));
$this->setAttribute('index', $node->getAttribute('index'));
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
$this->usedFunctions = $usedFunctions;
}
protected function compileDisplayBody(Twig_Compiler $compiler)
{
$compiler->write("\$this->checkSecurity();\n");
parent::compileDisplayBody($compiler);
}
protected function compileDisplayFooter(Twig_Compiler $compiler)
{
parent::compileDisplayFooter($compiler);
$tags = $filters = $functions = array();
foreach (array('tags', 'filters', 'functions') as $type) {
foreach ($this->{'used'.ucfirst($type)} as $name => $node) {
if ($node instanceof Twig_Node) {
${$type}[$name] = $node->getLine();
} else {
${$type}[$node] = null;
}
}
}
$compiler
->write("protected function checkSecurity()\n", "{\n")
->indent()
->write("\$tags = ")->repr(array_filter($tags))->raw(";\n")
->write("\$filters = ")->repr(array_filter($filters))->raw(";\n")
->write("\$functions = ")->repr(array_filter($functions))->raw(";\n\n")
->write("try {\n")
->indent()
->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
->indent()
->write(!$tags ? "array(),\n" : "array('".implode("', '", array_keys($tags))."'),\n")
->write(!$filters ? "array(),\n" : "array('".implode("', '", array_keys($filters))."'),\n")
->write(!$functions ? "array()\n" : "array('".implode("', '", array_keys($functions))."')\n")
->outdent()
->write(");\n")
->outdent()
->write("} catch (Twig_Sandbox_SecurityError \$e) {\n")
->indent()
->write("\$e->setTemplateFile(\$this->getTemplateName());\n\n")
->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
->outdent()
->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFilterError && isset(\$filters[\$e->getFilterName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n")
->outdent()
->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFunctionError && isset(\$functions[\$e->getFunctionName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$functions[\$e->getFunctionName()]);\n")
->outdent()
->write("}\n\n")
->write("throw \$e;\n")
->outdent()
->write("}\n")
->outdent()
->write("}\n\n")
;
}
}
......@@ -56,7 +56,7 @@ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
$this->enterOptimizeFor($node, $env);
}
if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
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') {
......
......@@ -78,7 +78,7 @@ public function getParent(array $context)
}
if (!isset($this->parents[$parent])) {
$this->parents[$parent] = $this->env->loadTemplate($parent);
$this->parents[$parent] = $this->loadTemplate($parent);
}
} catch (Twig_Error_Loader $e) {
$e->setTemplateFile(null);
......@@ -240,6 +240,30 @@ public function getBlockNames()
return array_keys($this->blocks);
}
protected function loadTemplate($template, $templateName = null, $line = null, $index = null)
{
try {
if (is_array($template)) {
return $this->env->resolveTemplate($template);
}
if ($template instanceof Twig_Template) {
return $template;
}
return $this->env->loadTemplate($template, $index);
} catch (Twig_Error $e) {
$e->setTemplateFile($templateName ? $templateName : $this->getTemplateName());
if (!$line) {