update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit 47263617c5
139 changed files with 418860 additions and 226988 deletions

View file

@ -1,18 +0,0 @@
; top-most EditorConfig file
root = true
; Unix-style newlines
[*]
end_of_line = LF
[*.php]
indent_style = space
indent_size = 4
[*.test]
indent_style = space
indent_size = 4
[*.rst]
indent_style = space
indent_size = 4

View file

@ -1,2 +0,0 @@
/ext/twig/autom4te.cache/

View file

@ -1,21 +0,0 @@
language: php
php:
- 5.2
- 5.3
- 5.4
- 5.5
- hhvm
env:
- TWIG_EXT=no
- TWIG_EXT=yes
before_script:
- if [ "$TWIG_EXT" == "yes" ]; then sh -c "cd ext/twig && phpize && ./configure --enable-twig && make && sudo make install"; fi
- if [ "$TWIG_EXT" == "yes" ]; then echo "extension=twig.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi
matrix:
exclude:
- php: hhvm
env: TWIG_EXT=yes

View file

@ -1,4 +1,126 @@
* 1.15.1 (2013-02-13)
* 1.22.3 (2015-10-13)
* fixed regression when using null as a cache strategy
* improved performance when checking template freshness
* fixed warnings when loaded templates do not exist
* fixed template class name generation to prevent possible collisions
* fixed logic for custom escapers to call them even on integers and null values
* changed template cache names to take into account the Twig C extension
* 1.22.2 (2015-09-22)
* fixed a race condition in template loading
* 1.22.1 (2015-09-15)
* fixed regression in template_from_string
* 1.22.0 (2015-09-13)
* made Twig_Test_IntegrationTestCase more flexible
* added an option to force PHP bytecode invalidation when writing a compiled template into the cache
* fixed the profiler duration for the root node
* changed template cache names to take into account enabled extensions
* deprecated Twig_Environment::clearCacheFiles(), Twig_Environment::getCacheFilename(),
Twig_Environment::writeCacheFile(), and Twig_Environment::getTemplateClassPrefix()
* added a way to override the filesystem template cache system
* added a way to get the original template source from Twig_Template
* 1.21.2 (2015-09-09)
* fixed variable names for the deprecation triggering code
* fixed escaping strategy detection based on filename
* added Traversable support for replace, merge, and sort
* deprecated support for character by character replacement for the "replace" filter
* 1.21.1 (2015-08-26)
* fixed regression when using the deprecated Twig_Test_* classes
* 1.21.0 (2015-08-24)
* added deprecation notices for deprecated features
* added a deprecation "framework" for filters/functions/tests and test fixtures
* 1.20.0 (2015-08-12)
* forbid access to the Twig environment from templates and internal parts of Twig_Template
* fixed limited RCEs when in sandbox mode
* deprecated Twig_Template::getEnvironment()
* deprecated the _self variable for usage outside of the from and import tags
* added Twig_BaseNodeVisitor to ease the compatibility of node visitors
between 1.x and 2.x
* 1.19.0 (2015-07-31)
* fixed wrong error message when including an undefined template in a child template
* added support for variadic filters, functions, and tests
* added support for extra positional arguments in macros
* added ignore_missing flag to the source function
* fixed batch filter with zero items
* deprecated Twig_Environment::clearTemplateCache()
* fixed sandbox disabling when using the include function
* 1.18.2 (2015-06-06)
* fixed template/line guessing in exceptions for nested templates
* optimized the number of inodes and the size of realpath cache when using the cache
* 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)
* added Twig_Environment::createTemplate() to create a template from a string
* added a profiler
* fixed filesystem loader cache when different file paths are used for the same template
* 1.17.0 (2015-01-14)
* added a 'filename' autoescaping strategy, which dynamically chooses the
autoescaping strategy for a template based on template file extension.
* 1.16.3 (2014-12-25)
* fixed regression for dynamic parent templates
* fixed cache management with statcache
* fixed a regression in the slice filter
* 1.16.2 (2014-10-17)
* fixed timezone on dates as strings
* fixed 2-words test names when a custom node class is not used
* fixed macros when using an argument named like a PHP super global (like GET or POST)
* fixed date_modify when working with DateTimeImmutable
* optimized for loops
* fixed multi-byte characters handling in the split filter
* fixed a regression in the in operator
* fixed a regression in the slice filter
* 1.16.1 (2014-10-10)
* improved error reporting in a sandboxed template
* fixed missing error file/line information under certain circumstances
* fixed wrong error line number in some error messages
* fixed the in operator to use strict comparisons
* sped up the slice filter
* fixed for mb function overload mb_substr acting different
* fixed the attribute() function when passing a variable for the arguments
* 1.16.0 (2014-07-05)
* changed url_encode to always encode according to RFC 3986
* fixed inheritance in a 'use'-hierarchy
* removed the __toString policy check when the sandbox is disabled
* fixed recursively calling blocks in templates with inheritance
* 1.15.1 (2014-02-13)
* fixed the conversion of the special '0000-00-00 00:00' date
* added an error message when trying to import an undefined block from a trait

View file

@ -14,7 +14,7 @@
},
{
"name": "Twig Team",
"homepage": "https://github.com/fabpot/Twig/graphs/contributors",
"homepage": "http://twig.sensiolabs.org/contributors",
"role": "Contributors"
},
{
@ -27,7 +27,11 @@
"forum": "https://groups.google.com/forum/#!forum/twig-users"
},
"require": {
"php": ">=5.2.4"
"php": ">=5.2.7"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7",
"symfony/debug": "~2.7"
},
"autoload": {
"psr-0" : {
@ -36,7 +40,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
"dev-master": "1.22-dev"
}
}
}

View file

@ -1,30 +0,0 @@
*.sw*
.deps
Makefile
Makefile.fragments
Makefile.global
Makefile.objects
acinclude.m4
aclocal.m4
build/
config.cache
config.guess
config.h
config.h.in
config.log
config.nice
config.status
config.sub
configure
configure.in
install-sh
libtool
ltmain.sh
missing
mkinstalldirs
run-tests.php
twig.loT
.libs/
modules/
twig.la
twig.lo

View file

@ -1,31 +0,0 @@
Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -15,17 +15,21 @@
#ifndef PHP_TWIG_H
#define PHP_TWIG_H
#define PHP_TWIG_VERSION "1.15.1"
#define PHP_TWIG_VERSION "1.22.3"
#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

View file

@ -54,11 +54,22 @@ ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_
ZEND_ARG_INFO(0, isDefinedTest)
ZEND_END_ARG_INFO()
zend_function_entry twig_functions[] = {
#ifndef PHP_FE_END
#define PHP_FE_END { NULL, NULL, NULL}
#endif
static const zend_function_entry twig_functions[] = {
PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args)
{NULL, NULL, NULL}
PHP_FE_END
};
PHP_RSHUTDOWN_FUNCTION(twig)
{
#if ZEND_DEBUG
CG(unclean_shutdown) = 0; /* get rid of PHPUnit's exit() and report memleaks */
#endif
return SUCCESS;
}
zend_module_entry twig_module_entry = {
STANDARD_MODULE_HEADER,
@ -67,7 +78,7 @@ zend_module_entry twig_module_entry = {
NULL,
NULL,
NULL,
NULL,
PHP_RSHUTDOWN(twig),
NULL,
PHP_TWIG_VERSION,
STANDARD_MODULE_PROPERTIES
@ -78,7 +89,7 @@ zend_module_entry twig_module_entry = {
ZEND_GET_MODULE(twig)
#endif
int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
static int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
{
if (Z_TYPE_P(array) != IS_ARRAY) {
return 0;
@ -100,7 +111,7 @@ int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
}
}
int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
static int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
{
if (Z_TYPE_P(object) != IS_OBJECT) {
return 0;
@ -108,7 +119,7 @@ int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC);
}
int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
static int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
{
zend_class_entry **pce;
if (Z_TYPE_P(object) != IS_OBJECT) {
@ -120,7 +131,7 @@ int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC);
}
zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
static zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
{
zend_class_entry *ce = Z_OBJCE_P(object);
zval *retval;
@ -143,7 +154,7 @@ zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
return NULL;
}
int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
static int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
{
zend_class_entry *ce = Z_OBJCE_P(object);
zval *retval;
@ -166,7 +177,7 @@ int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
return 0;
}
char *TWIG_STRTOLOWER(const char *str, int str_len)
static char *TWIG_STRTOLOWER(const char *str, int str_len)
{
char *item_dup;
@ -175,7 +186,7 @@ char *TWIG_STRTOLOWER(const char *str, int str_len)
return item_dup;
}
zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
static zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
{
zend_fcall_info fci;
zval ***args = NULL;
@ -227,7 +238,7 @@ zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TS
return retval_ptr;
}
int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
static int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
{
zval *ret;
int res;
@ -238,7 +249,7 @@ int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
return res;
}
zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
static zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
{
zval **tmp_zval;
zend_class_entry *ce;
@ -256,7 +267,7 @@ zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
return *tmp_zval;
}
zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
static zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
{
zval **tmp_zval;
@ -288,7 +299,7 @@ zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
return NULL;
}
zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
static zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
{
zval **tmp_zval;
@ -314,7 +325,7 @@ zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length
return NULL;
}
zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
static zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
{
zval *tmp = NULL;
@ -331,7 +342,7 @@ zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
return tmp;
}
int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
static int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
{
if (Z_OBJ_HT_P(object)->has_property) {
#if PHP_VERSION_ID >= 50400
@ -343,7 +354,7 @@ int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
return 0;
}
int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
static int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
{
if (Z_OBJ_HT_P(object)->get_properties) {
return zend_hash_quick_exists(
@ -356,7 +367,7 @@ int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
return 0;
}
zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
static zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
{
zval *tmp_name_zval, *tmp;
@ -367,12 +378,7 @@ zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
return tmp;
}
int TWIG_CALL_B_0(zval *object, char *method)
{
return 0;
}
zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
static zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
{
zend_fcall_info fci;
zval **args[1];
@ -410,7 +416,7 @@ zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
return retval_ptr;
}
int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
static int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
{
zval *retval_ptr;
int success;
@ -425,51 +431,7 @@ int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
return success;
}
int TWIG_CALL_Z(zval *object, char *method, zval *arg1 TSRMLS_DC)
{
zend_fcall_info fci;
zval **args[1];
zval *zfunction;
zval *retval_ptr;
int success;
args[0] = &arg1;
MAKE_STD_ZVAL(zfunction);
ZVAL_STRING(zfunction, method, 1);
fci.size = sizeof(fci);
fci.function_table = EG(function_table);
fci.function_name = zfunction;
fci.symbol_table = NULL;
#if PHP_VERSION_ID >= 50300
fci.object_ptr = object;
#else
fci.object_pp = &object;
#endif
fci.retval_ptr_ptr = &retval_ptr;
fci.param_count = 1;
fci.params = args;
fci.no_separation = 0;
if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
FREE_DTOR(zfunction);
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
return 0;
}
FREE_DTOR(zfunction);
success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
return success;
}
int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
static int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
{
zend_fcall_info fci;
zval **args[2];
@ -516,7 +478,7 @@ int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
# define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
#endif
void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
static void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
{
zend_class_entry **pce;
@ -561,7 +523,7 @@ static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC, int num_arg
return 0;
}
char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
static char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
{
smart_str collector = { 0, 0, 0 };
@ -572,24 +534,6 @@ char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
return collector.c;
}
static void TWIG_THROW_EXCEPTION(char *exception_name TSRMLS_DC, char *message, ...)
{
char *buffer;
va_list args;
zend_class_entry **pce;
if (zend_lookup_class(exception_name, strlen(exception_name), &pce TSRMLS_CC) == FAILURE) {
return;
}
va_start(args, message);
vspprintf(&buffer, 0, message, args);
va_end(args);
zend_throw_exception_ex(*pce, 0 TSRMLS_CC, buffer);
efree(buffer);
}
static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...)
{
char *buffer;
@ -665,6 +609,7 @@ static char *TWIG_GET_CLASS_NAME(zval *object TSRMLS_DC)
static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
{
zend_class_entry *ce;
zval *retval;
char *item;
size_t item_len;
@ -675,12 +620,23 @@ static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, v
return 0;
}
ce = *va_arg(args, zend_class_entry**);
retval = va_arg(args, zval*);
item_len = strlen(mptr->common.function_name);
item = estrndup(mptr->common.function_name, item_len);
php_strtolower(item, item_len);
if (strcmp("getenvironment", item) == 0) {
zend_class_entry **twig_template_ce;
if (zend_lookup_class("Twig_Template", strlen("Twig_Template"), &twig_template_ce TSRMLS_CC) == FAILURE) {
return 0;
}
if (instanceof_function(ce, *twig_template_ce TSRMLS_CC)) {
return 0;
}
}
add_assoc_stringl_ex(retval, item, item_len+1, item, item_len, 0);
return 0;
@ -726,7 +682,7 @@ static void twig_add_class_to_cache(zval *cache, zval *object, char *class_name
array_init(class_methods);
array_init(class_properties);
// add all methods to self::cache[$class]['methods']
zend_hash_apply_with_arguments(&class_ce->function_table APPLY_TSRMLS_CC, twig_add_method_to_class, 1, class_methods);
zend_hash_apply_with_arguments(&class_ce->function_table APPLY_TSRMLS_CC, twig_add_method_to_class, 2, &class_ce, class_methods);
zend_hash_apply_with_arguments(&class_ce->properties_info APPLY_TSRMLS_CC, twig_add_property_to_class, 2, &class_ce, class_properties);
add_assoc_zval(class_info, "methods", class_methods);
@ -794,6 +750,7 @@ PHP_FUNCTION(twig_template_get_attributes)
) {
if (isDefinedTest) {
efree(item);
RETURN_TRUE;
}
@ -806,6 +763,7 @@ PHP_FUNCTION(twig_template_get_attributes)
if (free_ret) {
zval_ptr_dtor(&ret);
}
efree(item);
return;
}
/*
@ -819,9 +777,11 @@ PHP_FUNCTION(twig_template_get_attributes)
*/
if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
if (isDefinedTest) {
efree(item);
RETURN_FALSE;
}
if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
efree(item);
return;
}
/*
@ -830,9 +790,19 @@ PHP_FUNCTION(twig_template_get_attributes)
} elseif (is_object($object)) {
$message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
} elseif (is_array($object)) {
$message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
if (empty($object)) {
$message = sprintf('Key "%s" does not exist as the array is empty', $arrayItem);
} else {
$message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
}
} elseif (Twig_Template::ARRAY_CALL === $type) {
$message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
if (null === $object) {
$message = sprintf('Impossible to access a key ("%s") on a null variable', $item);
} else {
$message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
}
} elseif (null === $object) {
$message = sprintf('Impossible to access an attribute ("%s") on a null variable', $item);
} else {
$message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
}
@ -845,18 +815,34 @@ PHP_FUNCTION(twig_template_get_attributes)
} else if (Z_TYPE_P(object) == IS_OBJECT) {
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to access a key \"%s\" on an object of class \"%s\" that does not implement ArrayAccess interface", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
} else if (Z_TYPE_P(object) == IS_ARRAY) {
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
if (0 == zend_hash_num_elements(Z_ARRVAL_P(object))) {
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" does not exist as the array is empty", item);
} else {
char *array_keys = TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC);
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, array_keys);
efree(array_keys);
}
} else {
char *type_name = zend_zval_type_name(object);
Z_ADDREF_P(object);
convert_to_string(object);
TWIG_RUNTIME_ERROR(template TSRMLS_CC,
(strcmp("array", type) == 0)
? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")"
: "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")",
item, type_name, Z_STRVAL_P(object));
if (Z_TYPE_P(object) == IS_NULL) {
convert_to_string(object);
TWIG_RUNTIME_ERROR(template TSRMLS_CC,
(strcmp("array", type) == 0)
? "Impossible to access a key (\"%s\") on a %s variable"
: "Impossible to access an attribute (\"%s\") on a %s variable",
item, type_name);
} else {
convert_to_string(object);
TWIG_RUNTIME_ERROR(template TSRMLS_CC,
(strcmp("array", type) == 0)
? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")"
: "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")",
item, type_name, Z_STRVAL_P(object));
}
zval_ptr_dtor(&object);
}
efree(item);
return;
}
}
@ -870,27 +856,42 @@ PHP_FUNCTION(twig_template_get_attributes)
if (Z_TYPE_P(object) != IS_OBJECT) {
if (isDefinedTest) {
efree(item);
RETURN_FALSE;
}
/*
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
return null;
}
throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
if (null === $object) {
$message = sprintf('Impossible to invoke a method ("%s") on a null variable', $item);
} else {
$message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
}
throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
}
*/
if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
efree(item);
return;
}
type_name = zend_zval_type_name(object);
Z_ADDREF_P(object);
convert_to_string_ex(&object);
if (Z_TYPE_P(object) == IS_NULL) {
convert_to_string_ex(&object);
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable", item, type_name);
} else {
convert_to_string_ex(&object);
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
}
zval_ptr_dtor(&object);
efree(item);
return;
}
/*
@ -909,7 +910,7 @@ PHP_FUNCTION(twig_template_get_attributes)
/*
// object property
if (Twig_Template::METHOD_CALL !== $type) {
if (Twig_Template::METHOD_CALL !== $type && !$object instanceof Twig_Template) {
if (isset($object->$item) || array_key_exists((string) $item, $object)) {
if ($isDefinedTest) {
return true;
@ -923,7 +924,7 @@ PHP_FUNCTION(twig_template_get_attributes)
}
}
*/
if (strcmp("method", type) != 0) {
if (strcmp("method", type) != 0 && !TWIG_INSTANCE_OF_USERLAND(object, "Twig_Template" TSRMLS_CC)) {
zval *tmp_properties, *tmp_item;
tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC);
@ -931,23 +932,42 @@ PHP_FUNCTION(twig_template_get_attributes)
if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
if (isDefinedTest) {
efree(item);
RETURN_TRUE;
}
if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
}
if (EG(exception)) {
efree(item);
return;
}
ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
efree(item);
RETURN_ZVAL(ret, 1, 0);
}
}
/*
// object method
if (!isset(self::$cache[$class]['methods'])) {
self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
if ($object instanceof self) {
$ref = new ReflectionClass($class);
$methods = array();
foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $refMethod) {
$methodName = strtolower($refMethod->name);
// Accessing the environment from templates is forbidden to prevent untrusted changes to the environment
if ('getenvironment' !== $methodName) {
$methods[$methodName] = true;
}
}
self::$cache[$class]['methods'] = $methods;
} else {
self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
}
}
$call = false;
@ -1013,19 +1033,22 @@ PHP_FUNCTION(twig_template_get_attributes)
efree(lcItem);
if (isDefinedTest) {
efree(item);
RETURN_FALSE;
}
if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
efree(item);
return;
}
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Method \"%s\" for object \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
efree(item);
return;
}
if (isDefinedTest) {
efree(tmp_method_name_get);
efree(tmp_method_name_is);
efree(lcItem);
efree(lcItem);efree(item);
RETURN_TRUE;
}
/*
@ -1038,11 +1061,11 @@ PHP_FUNCTION(twig_template_get_attributes)
if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zmethod TSRMLS_CC);
}
zval_ptr_dtor(&zmethod);
if (EG(exception)) {
efree(tmp_method_name_get);
efree(tmp_method_name_is);
efree(lcItem);
zval_ptr_dtor(&zmethod);
efree(lcItem);efree(item);
return;
}
/*
@ -1060,6 +1083,9 @@ PHP_FUNCTION(twig_template_get_attributes)
ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
if (EG(exception) && TWIG_INSTANCE_OF(EG(exception), spl_ce_BadMethodCallException TSRMLS_CC)) {
if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
efree(tmp_method_name_get);
efree(tmp_method_name_is);
efree(lcItem);efree(item);
zend_clear_exception(TSRMLS_C);
return;
}
@ -1068,7 +1094,6 @@ PHP_FUNCTION(twig_template_get_attributes)
efree(tmp_method_name_get);
efree(tmp_method_name_is);
efree(lcItem);
zval_ptr_dtor(&zmethod);
}
/*
// useful when calling a template method from a template
@ -1079,6 +1104,7 @@ PHP_FUNCTION(twig_template_get_attributes)
return $ret;
*/
efree(item);
// ret can be null, if e.g. the called method throws an exception
if (ret) {
if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {

View file

@ -9,24 +9,30 @@
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Autoloader class is deprecated and will be removed in 2.0. Use Composer instead.', E_USER_DEPRECATED);
/**
* Autoloads Twig classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated Use Composer instead. Will be removed in Twig 2.0.
*/
class Twig_Autoloader
{
/**
* Registers Twig_Autoloader as an SPL autoloader.
*
* @param Boolean $prepend Whether to prepend the autoloader or not.
* @param bool $prepend Whether to prepend the autoloader or not.
*/
public static function register($prepend = false)
{
if (version_compare(phpversion(), '5.3.0', '>=')) {
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
} else {
@trigger_error('Using Twig_Autoloader is deprecated. Use Composer instead.', E_USER_DEPRECATED);
if (PHP_VERSION_ID < 50300) {
spl_autoload_register(array(__CLASS__, 'autoload'));
} else {
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
}
}

View file

@ -0,0 +1,62 @@
<?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.
*/
/**
* Twig_BaseNodeVisitor can be used to make node visitors compatible with Twig 1.x and 2.x.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface
{
/**
* {@inheritdoc}
*/
final public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if (!$node instanceof Twig_Node) {
throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.');
}
return $this->doEnterNode($node, $env);
}
/**
* {@inheritdoc}
*/
final public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if (!$node instanceof Twig_Node) {
throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.');
}
return $this->doLeaveNode($node, $env);
}
/**
* Called before child nodes are visited.
*
* @param Twig_Node $node The node to visit
* @param Twig_Environment $env The Twig environment instance
*
* @return Twig_Node The modified node
*/
abstract protected function doEnterNode(Twig_Node $node, Twig_Environment $env);
/**
* Called after child nodes are visited.
*
* @param Twig_Node $node The node to visit
* @param Twig_Environment $env The Twig environment instance
*
* @return Twig_Node|false The modified node or false if the node must be removed
*/
abstract protected function doLeaveNode(Twig_Node $node, Twig_Environment $env);
}

View file

@ -0,0 +1,96 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2015 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Implements a cache on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
class Twig_Cache_Filesystem implements Twig_CacheInterface
{
const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
/**
* @param $directory string The root cache directory
* @param $options int A set of options
*/
public function __construct($directory, $options = 0)
{
$this->directory = $directory;
$this->options = $options;
}
/**
* {@inheritdoc}
*/
public function generateKey($name, $className)
{
$hash = hash('sha256', $className);
return $this->directory.'/'.$hash[0].$hash[1].'/'.$hash.'.php';
}
/**
* {@inheritdoc}
*/
public function load($key)
{
@include_once $key;
}
/**
* {@inheritdoc}
*/
public function write($key, $content)
{
$dir = dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
}
} elseif (!is_writable($dir)) {
throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (function_exists('opcache_invalidate')) {
opcache_invalidate($key, true);
} elseif (function_exists('apc_compile_file')) {
apc_compile_file($key);
}
}
return;
}
throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key));
}
/**
* {@inheritdoc}
*/
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}

View file

@ -0,0 +1,48 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2015 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Implements a no-cache strategy.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Cache_Null implements Twig_CacheInterface
{
/**
* {@inheritdoc}
*/
public function generateKey($name, $className)
{
return '';
}
/**
* {@inheritdoc}
*/
public function write($key, $content)
{
}
/**
* {@inheritdoc}
*/
public function load($key)
{
}
/**
* {@inheritdoc}
*/
public function getTimestamp($key)
{
return 0;
}
}

View file

@ -0,0 +1,56 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2015 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by cache classes.
*
* It is highly recommended to always store templates on the filesystem to
* benefit from the PHP opcode cache. This interface is mostly useful if you
* need to implement a custom strategy for storing templates on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
interface Twig_CacheInterface
{
/**
* Generates a cache key for the given template class name.
*
* @param string $name The template name
* @param string $className The template class name
*
* @return string
*/
public function generateKey($name, $className);
/**
* Writes the compiled template to cache.
*
* @param string $key The cache key
* @param string $content The template representation as a PHP class
*/
public function write($key, $content);
/**
* Loads a template from the cache.
*
* @param string $key The cache key
*/
public function load($key);
/**
* Returns the modification timestamp of a key.
*
* @param string $key The cache key
*
* @return int
*/
public function getTimestamp($key);
}

View file

@ -21,7 +21,7 @@ class Twig_Compiler implements Twig_CompilerInterface
protected $source;
protected $indentation;
protected $env;
protected $debugInfo;
protected $debugInfo = array();
protected $sourceOffset;
protected $sourceLine;
protected $filename;
@ -34,7 +34,6 @@ class Twig_Compiler implements Twig_CompilerInterface
public function __construct(Twig_Environment $env)
{
$this->env = $env;
$this->debugInfo = array();
}
public function getFilename()
@ -66,7 +65,7 @@ class Twig_Compiler implements Twig_CompilerInterface
* Compiles a node.
*
* @param Twig_NodeInterface $node The node to compile
* @param integer $indentation The current indentation
* @param int $indentation The current indentation
*
* @return Twig_Compiler The current compiler instance
*/
@ -74,6 +73,7 @@ class Twig_Compiler implements Twig_CompilerInterface
{
$this->lastLine = null;
$this->source = '';
$this->debugInfo = array();
$this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we encounter new lines)
$this->sourceLine = 1;
@ -181,14 +181,14 @@ class Twig_Compiler implements Twig_CompilerInterface
} elseif (is_array($value)) {
$this->raw('array(');
$first = true;
foreach ($value as $key => $value) {
foreach ($value as $key => $v) {
if (!$first) {
$this->raw(', ');
}
$first = false;
$this->repr($key);
$this->raw(' => ');
$this->repr($value);
$this->repr($v);
}
$this->raw(')');
} else {
@ -230,13 +230,15 @@ class Twig_Compiler implements Twig_CompilerInterface
public function getDebugInfo()
{
ksort($this->debugInfo);
return $this->debugInfo;
}
/**
* Indents the generated code.
*
* @param integer $step The number of indentation to add
* @param int $step The number of indentation to add
*
* @return Twig_Compiler The current compiler instance
*/
@ -250,7 +252,7 @@ class Twig_Compiler implements Twig_CompilerInterface
/**
* Outdents the generated code.
*
* @param integer $step The number of indentation to remove
* @param int $step The number of indentation to remove
*
* @return Twig_Compiler The current compiler instance
*
@ -267,4 +269,9 @@ class Twig_Compiler implements Twig_CompilerInterface
return $this;
}
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
}
}

View file

@ -13,7 +13,8 @@
* Interface implemented by compiler classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_CompilerInterface
{

View file

@ -16,7 +16,7 @@
*/
class Twig_Environment
{
const VERSION = '1.15.1';
const VERSION = '1.22.3';
protected $charset;
protected $loader;
@ -34,17 +34,22 @@ class Twig_Environment
protected $tests;
protected $functions;
protected $globals;
protected $runtimeInitialized;
protected $extensionInitialized;
protected $runtimeInitialized = false;
protected $extensionInitialized = false;
protected $loadedTemplates;
protected $strictVariables;
protected $unaryOperators;
protected $binaryOperators;
protected $templateClassPrefix = '__TwigTemplate_';
protected $functionCallbacks;
protected $filterCallbacks;
protected $functionCallbacks = array();
protected $filterCallbacks = array();
protected $staging;
private $originalCache;
private $bcWriteCacheFile = false;
private $bcGetCacheFilename = false;
private $lastModifiedExtension = 0;
/**
* Constructor.
*
@ -58,8 +63,9 @@ class Twig_Environment
* * base_template_class: The base template class to use for generated
* templates (default to Twig_Template).
*
* * cache: An absolute path where to store the compiled templates, or
* false to disable compilation cache (default).
* * cache: An absolute path where to store the compiled templates,
* a Twig_Cache_Interface implementation,
* or false to disable compilation cache (default).
*
* * auto_reload: Whether to reload the template if the original source changed.
* If you don't provide the auto_reload option, it will be
@ -72,6 +78,7 @@ class Twig_Environment
* * false: disable auto-escaping
* * true: equivalent to html
* * html, js: set the autoescaping to one of the supported strategies
* * filename: set the autoescaping strategy based on the template filename extension
* * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
*
* * optimizations: A flag that indicates which optimizations to apply
@ -85,34 +92,49 @@ class Twig_Environment
{
if (null !== $loader) {
$this->setLoader($loader);
} else {
@trigger_error('Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated.', E_USER_DEPRECATED);
}
$options = array_merge(array(
'debug' => false,
'charset' => 'UTF-8',
'debug' => false,
'charset' => 'UTF-8',
'base_template_class' => 'Twig_Template',
'strict_variables' => false,
'autoescape' => 'html',
'cache' => false,
'auto_reload' => null,
'optimizations' => -1,
'strict_variables' => false,
'autoescape' => 'html',
'cache' => false,
'auto_reload' => null,
'optimizations' => -1,
), $options);
$this->debug = (bool) $options['debug'];
$this->charset = strtoupper($options['charset']);
$this->baseTemplateClass = $options['base_template_class'];
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
$this->strictVariables = (bool) $options['strict_variables'];
$this->runtimeInitialized = false;
$this->debug = (bool) $options['debug'];
$this->charset = strtoupper($options['charset']);
$this->baseTemplateClass = $options['base_template_class'];
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
$this->strictVariables = (bool) $options['strict_variables'];
$this->setCache($options['cache']);
$this->functionCallbacks = array();
$this->filterCallbacks = array();
$this->addExtension(new Twig_Extension_Core());
$this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
$this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
$this->extensionInitialized = false;
$this->staging = new Twig_Extension_Staging();
// For BC
if (is_string($this->originalCache)) {
$r = new ReflectionMethod($this, 'writeCacheFile');
if ($r->getDeclaringClass()->getName() !== __CLASS__) {
@trigger_error('The Twig_Environment::writeCacheFile method is deprecated and will be removed in Twig 2.0.', E_USER_DEPRECATED);
$this->bcWriteCacheFile = true;
}
$r = new ReflectionMethod($this, 'getCacheFilename');
if ($r->getDeclaringClass()->getName() !== __CLASS__) {
@trigger_error('The Twig_Environment::getCacheFilename method is deprecated and will be removed in Twig 2.0.', E_USER_DEPRECATED);
$this->bcGetCacheFilename = true;
}
}
}
/**
@ -154,7 +176,7 @@ class Twig_Environment
/**
* Checks if debug mode is enabled.
*
* @return Boolean true if debug mode is enabled, false otherwise
* @return bool true if debug mode is enabled, false otherwise
*/
public function isDebug()
{
@ -180,7 +202,7 @@ class Twig_Environment
/**
* Checks if the auto_reload option is enabled.
*
* @return Boolean true if auto_reload is enabled, false otherwise
* @return bool true if auto_reload is enabled, false otherwise
*/
public function isAutoReload()
{
@ -206,7 +228,7 @@ class Twig_Environment
/**
* Checks if the strict_variables option is enabled.
*
* @return Boolean true if strict_variables is enabled, false otherwise
* @return bool true if strict_variables is enabled, false otherwise
*/
public function isStrictVariables()
{
@ -214,24 +236,43 @@ class Twig_Environment
}
/**
* Gets the cache directory or false if cache is disabled.
* Gets the current cache implementation.
*
* @return string|false
* @param bool $original Whether to return the original cache option or the real cache instance
*
* @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function getCache()
public function getCache($original = true)
{
return $this->cache;
return $original ? $this->originalCache : $this->cache;
}
/**
* Sets the cache directory or false if cache is disabled.
*
* @param string|false $cache The absolute path to the compiled templates,
* or false to disable cache
*/
/**
* Sets the current cache implementation.
*
* @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function setCache($cache)
{
$this->cache = $cache ? $cache : false;
if (is_string($cache)) {
$this->originalCache = $cache;
$this->cache = new Twig_Cache_Filesystem($cache);
} elseif (false === $cache) {
$this->originalCache = $cache;
$this->cache = new Twig_Cache_Null();
} elseif (null === $cache) {
@trigger_error('Using "null" as the cache strategy is deprecated and will be removed in Twig 2.0.', E_USER_DEPRECATED);
$this->originalCache = false;
$this->cache = new Twig_Cache_Null();
} elseif ($cache instanceof Twig_CacheInterface) {
$this->originalCache = $this->cache = $cache;
} else {
throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.'));
}
}
/**
@ -240,38 +281,52 @@ class Twig_Environment
* @param string $name The template name
*
* @return string|false The cache file name or false when caching is disabled
*
* @deprecated since 1.22 (to be removed in 2.0)
*/
public function getCacheFilename($name)
{
if (false === $this->cache) {
return false;
}
@trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
$class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
$key = $this->cache->generateKey($name, $this->getTemplateClass($name));
return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
return !$key ? false : $key;
}
/**
* Gets the template class associated with the given string.
*
* @param string $name The name for which to calculate the template class name
* @param integer $index The index if it is an embedded template
* The generated template class is based on the following parameters:
*
* * The cache key for the given template;
* * The currently enabled extensions;
* * Whether the Twig C extension is available or not.
*
* @param string $name The name for which to calculate the template class name
* @param int|null $index The index if it is an embedded template
*
* @return string The template class name
*/
public function getTemplateClass($name, $index = null)
{
return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
$key = $this->getLoader()->getCacheKey($name);
$key .= json_encode(array_keys($this->extensions));
$key .= function_exists('twig_template_get_attributes');
return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index);
}
/**
* Gets the template class prefix.
*
* @return string The template class prefix
*
* @deprecated since 1.22 (to be removed in 2.0)
*/
public function getTemplateClassPrefix()
{
@trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
return $this->templateClassPrefix;
}
@ -310,8 +365,8 @@ class Twig_Environment
/**
* Loads a template by name.
*
* @param string $name The template name
* @param integer $index The index if it is an embedded template
* @param string $name The template name
* @param int $index The index if it is an embedded template
*
* @return Twig_TemplateInterface A template instance representing the given template name
*
@ -327,14 +382,25 @@ class Twig_Environment
}
if (!class_exists($cls, false)) {
if (false === $cache = $this->getCacheFilename($name)) {
eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
if ($this->bcGetCacheFilename) {
$key = $this->getCacheFilename($name);
} else {
if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
$this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
$key = $this->cache->generateKey($name, $cls);
}
if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
$this->cache->load($key);
}
if (!class_exists($cls, false)) {
$content = $this->compileSource($this->getLoader()->getSource($name), $name);
if ($this->bcWriteCacheFile) {
$this->writeCacheFile($key, $content);
} else {
$this->cache->write($key, $content);
}
require_once $cache;
eval('?>'.$content);
}
}
@ -345,6 +411,40 @@ class Twig_Environment
return $this->loadedTemplates[$cls] = new $cls($this);
}
/**
* Creates a template from source.
*
* This method should not be used as a generic way to load templates.
*
* @param string $template The template name
*
* @return Twig_Template A template instance representing the given template name
*
* @throws Twig_Error_Loader When the template cannot be found
* @throws Twig_Error_Syntax When an error occurred during compilation
*/
public function createTemplate($template)
{
$name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
$loader = new Twig_Loader_Chain(array(
new Twig_Loader_Array(array($name => $template)),
$current = $this->getLoader(),
));
$this->setLoader($loader);
try {
$template = $this->loadTemplate($name);
} catch (Exception $e) {
$this->setLoader($current);
throw $e;
}
$this->setLoader($current);
return $template;
}
/**
* Returns true if the template is still fresh.
*
@ -352,21 +452,14 @@ class Twig_Environment
* this method also checks if the enabled extensions have
* not changed.
*
* @param string $name The template name
* @param timestamp $time The last modification time of the cached template
* @param string $name The template name
* @param int $time The last modification time of the cached template
*
* @return Boolean true if the template is fresh, false otherwise
* @return bool true if the template is fresh, false otherwise
*/
public function isTemplateFresh($name, $time)
{
foreach ($this->extensions as $extension) {
$r = new ReflectionObject($extension);
if (filemtime($r->getFileName()) > $time) {
return false;
}
}
return $this->getLoader()->isFresh($name, $time);
return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time);
}
/**
@ -408,24 +501,30 @@ class Twig_Environment
/**
* Clears the internal template cache.
*
* @deprecated since 1.18.3 (to be removed in 2.0)
*/
public function clearTemplateCache()
{
@trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
$this->loadedTemplates = array();
}
/**
* Clears the template cache files on the filesystem.
*
* @deprecated since 1.22 (to be removed in 2.0)
*/
public function clearCacheFiles()
{
if (false === $this->cache) {
return;
}
@trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if ($file->isFile()) {
@unlink($file->getPathname());
if (is_string($this->originalCache)) {
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if ($file->isFile()) {
@unlink($file->getPathname());
}
}
}
}
@ -447,7 +546,7 @@ class Twig_Environment
/**
* Sets the Lexer instance.
*
* @param Twig_LexerInterface A Twig_LexerInterface instance
* @param Twig_LexerInterface $lexer A Twig_LexerInterface instance
*/
public function setLexer(Twig_LexerInterface $lexer)
{
@ -486,7 +585,7 @@ class Twig_Environment
/**
* Sets the Parser instance.
*
* @param Twig_ParserInterface A Twig_ParserInterface instance
* @param Twig_ParserInterface $parser A Twig_ParserInterface instance
*/
public function setParser(Twig_ParserInterface $parser)
{
@ -556,7 +655,13 @@ class Twig_Environment
public function compileSource($source, $name = null)
{
try {
return $this->compile($this->parse($this->tokenize($source, $name)));
$compiled = $this->compile($this->parse($this->tokenize($source, $name)), $source);
if (isset($source[0])) {
$compiled .= '/* '.str_replace(array('*/', "\r\n", "\r", "\n"), array('*//* ', "\n", "\n", "*/\n/* "), $source)."*/\n";
}
return $compiled;
} catch (Twig_Error $e) {
$e->setTemplateFile($name);
throw $e;
@ -626,7 +731,7 @@ class Twig_Environment
*
* @param string $name The extension name
*
* @return Boolean Whether the extension is registered or not
* @return bool Whether the extension is registered or not
*/
public function hasExtension($name)
{
@ -660,6 +765,11 @@ class Twig_Environment
throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
}
$r = new ReflectionObject($extension);
if (($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) {
$this->lastModifiedExtension = $extensionTime;
}
$this->extensions[$extension->getName()] = $extension;
}
@ -674,6 +784,8 @@ class Twig_Environment
*/
public function removeExtension($name)
{
@trigger_error(sprintf('The %s method is deprecated and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
if ($this->extensionInitialized) {
throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
}
@ -793,6 +905,8 @@ class Twig_Environment
if ($name instanceof Twig_SimpleFilter) {
$filter = $name;
$name = $filter->getName();
} else {
@trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated. Pass an instance of "Twig_SimpleFilter" instead when defining filter "%s".', __METHOD__, $name), E_USER_DEPRECATED);
}
if ($this->extensionInitialized) {
@ -882,6 +996,8 @@ class Twig_Environment
if ($name instanceof Twig_SimpleTest) {
$test = $name;
$name = $test->getName();
} else {
@trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated. Pass an instance of "Twig_SimpleTest" instead when defining test "%s".', __METHOD__, $name), E_USER_DEPRECATED);
}
if ($this->extensionInitialized) {
@ -940,6 +1056,8 @@ class Twig_Environment
if ($name instanceof Twig_SimpleFunction) {
$function = $name;
$name = $function->getName();
} else {
@trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated. Pass an instance of "Twig_SimpleFunction" instead when defining function "%s".', __METHOD__, $name), E_USER_DEPRECATED);
}
if ($this->extensionInitialized) {
@ -1030,11 +1148,11 @@ class Twig_Environment
$this->globals = $this->initGlobals();
}
/* This condition must be uncommented in Twig 2.0
if (!array_key_exists($name, $this->globals)) {
throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
// The deprecation notice must be turned into the following exception in Twig 2.0
@trigger_error(sprintf('Registering global variable "%s" at runtime or when the extensions have already been initialized is deprecated.', $name), E_USER_DEPRECATED);
//throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
}
*/
}
if ($this->extensionInitialized || $this->runtimeInitialized) {
@ -1149,7 +1267,7 @@ class Twig_Environment
}
$this->extensionInitialized = true;
$this->parsers = new Twig_TokenParserBroker();
$this->parsers = new Twig_TokenParserBroker(array(), array(), false);
$this->filters = array();
$this->functions = array();
$this->tests = array();
@ -1167,11 +1285,10 @@ class Twig_Environment
{
// filters
foreach ($extension->getFilters() as $name => $filter) {
if ($name instanceof Twig_SimpleFilter) {
$filter = $name;
$name = $filter->getName();
} elseif ($filter instanceof Twig_SimpleFilter) {
if ($filter instanceof Twig_SimpleFilter) {
$name = $filter->getName();
} else {
@trigger_error(sprintf('Using an instance of "%s" for filter "%s" is deprecated. Use Twig_SimpleFilter instead.', get_class($filter), $name), E_USER_DEPRECATED);
}
$this->filters[$name] = $filter;
@ -1179,11 +1296,10 @@ class Twig_Environment
// functions
foreach ($extension->getFunctions() as $name => $function) {
if ($name instanceof Twig_SimpleFunction) {
$function = $name;
$name = $function->getName();
} elseif ($function instanceof Twig_SimpleFunction) {
if ($function instanceof Twig_SimpleFunction) {
$name = $function->getName();
} else {
@trigger_error(sprintf('Using an instance of "%s" for function "%s" is deprecated. Use Twig_SimpleFunction instead.', get_class($function), $name), E_USER_DEPRECATED);
}
$this->functions[$name] = $function;
@ -1191,11 +1307,10 @@ class Twig_Environment
// tests
foreach ($extension->getTests() as $name => $test) {
if ($name instanceof Twig_SimpleTest) {
$test = $name;
$name = $test->getName();
} elseif ($test instanceof Twig_SimpleTest) {
if ($test instanceof Twig_SimpleTest) {
$name = $test->getName();
} else {
@trigger_error(sprintf('Using an instance of "%s" for test "%s" is deprecated. Use Twig_SimpleTest instead.', get_class($test), $name), E_USER_DEPRECATED);
}
$this->tests[$name] = $test;
@ -1206,6 +1321,8 @@ class Twig_Environment
if ($parser instanceof Twig_TokenParserInterface) {
$this->parsers->addTokenParser($parser);
} elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
@trigger_error('Registering a Twig_TokenParserBrokerInterface instance is deprecated.', E_USER_DEPRECATED);
$this->parsers->addTokenParserBroker($parser);
} else {
throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
@ -1228,27 +1345,11 @@ class Twig_Environment
}
}
/**
* @deprecated since 1.22 (to be removed in 2.0)
*/
protected function writeCacheFile($file, $content)
{
$dir = dirname($file);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
}
} elseif (!is_writable($dir)) {
throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
}
$tmpFile = tempnam($dir, basename($file));
if (false !== @file_put_contents($tmpFile, $content)) {
// rename does not work on Win32 before 5.2.6
if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
@chmod($file, 0666 & ~umask());
return;
}
}
throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
$this->cache->write($file, $content);
}
}

View file

@ -51,13 +51,13 @@ class Twig_Error extends Exception
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param integer $lineno The template line where the error occurred
* @param int $lineno The template line where the error occurred
* @param string $filename The template file name where the error occurred
* @param Exception $previous The previous 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 {
@ -111,7 +111,7 @@ class Twig_Error extends Exception
/**
* Gets the template line where the error occurred.
*
* @return integer The template line
* @return int The template line
*/
public function getTemplateLine()
{
@ -121,7 +121,7 @@ class Twig_Error extends Exception
/**
* Sets the template line where the error occurred.
*
* @param integer $lineno The template line
* @param int $lineno The template line
*/
public function setTemplateLine($lineno)
{
@ -188,7 +188,7 @@ class Twig_Error extends Exception
$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();
@ -229,6 +229,8 @@ class Twig_Error extends Exception
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
array_unshift($traces, array('file' => $e->getFile(), 'line' => $e->getLine()));
while ($trace = array_shift($traces)) {
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
continue;

View file

@ -13,7 +13,8 @@
* Adds an exists() method for loaders.
*
* @author Florin Patan <florinpatan@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_ExistsLoaderInterface
{
@ -22,7 +23,7 @@ interface Twig_ExistsLoaderInterface
*
* @param string $name The name of the template to check if we can load
*
* @return Boolean If the template source code is handled by this loader or not
* @return bool If the template source code is handled by this loader or not
*/
public function exists($name);
}

View file

@ -164,6 +164,21 @@ class Twig_ExpressionParser
$this->parser->getStream()->next();
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
break;
} elseif (isset($this->unaryOperators[$token->getValue()])) {
$class = $this->unaryOperators[$token->getValue()]['class'];
$ref = new ReflectionClass($class);
$negClass = 'Twig_Node_Expression_Unary_Neg';
$posClass = 'Twig_Node_Expression_Unary_Pos';
if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) {
throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
$this->parser->getStream()->next();
$expr = $this->parsePrimaryExpression();
$node = new $class($expr, $token->getLine());
break;
}
default:
@ -300,7 +315,7 @@ class Twig_ExpressionParser
{
switch ($name) {
case 'parent':
$args = $this->parseArguments();
$this->parseArguments();
if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
}
@ -318,7 +333,7 @@ class Twig_ExpressionParser
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
}
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
default:
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
$arguments = new Twig_Node_Expression_Array(array(), $line);
@ -372,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;
@ -451,8 +472,12 @@ class Twig_ExpressionParser
/**
* Parses arguments.
*
* @param Boolean $namedArguments Whether to allow named arguments or not
* @param Boolean $definition Whether we are parsing arguments for a function definition
* @param bool $namedArguments Whether to allow named arguments or not
* @param bool $definition Whether we are parsing arguments for a function definition
*
* @return Twig_Node
*
* @throws Twig_Error_Syntax
*/
public function parseArguments($namedArguments = false, $definition = false)
{
@ -553,6 +578,16 @@ class Twig_ExpressionParser
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
}
if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
}
$message .= sprintf(' in %s at line %d.', $this->parser->getFilename(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
if ($function instanceof Twig_SimpleFunction) {
return $function->getNodeClass();
}
@ -573,6 +608,16 @@ class Twig_ExpressionParser
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
}
if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
}
$message .= sprintf(' in %s at line %d.', $this->parser->getFilename(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
if ($filter instanceof Twig_SimpleFilter) {
return $filter->getNodeClass();
}
@ -583,7 +628,9 @@ class Twig_ExpressionParser
// checks that the node only contains "constant" elements
protected function checkConstantExpression(Twig_NodeInterface $node)
{
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array
|| $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos
)) {
return false;
}

Some files were not shown because too many files have changed in this diff Show more