1
0
mirror of https://github.com/vichan-devel/vichan.git synced 2024-11-27 17:00:52 +01:00

Merge pull request #401 from vichan-devel/composer

use composer
This commit is contained in:
Łiźnier Hełam Łabej 2021-02-13 19:52:00 +01:00 committed by GitHub
commit d5e8747a19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
261 changed files with 439 additions and 31440 deletions

5
.gitignore vendored
View File

@ -11,9 +11,6 @@
!/templates/*.html !/templates/*.html
!/inc/config.php !/inc/config.php
# minify
/inc/lib/minify
# instance-config # instance-config
/inc/instance-config.php /inc/instance-config.php
@ -47,3 +44,5 @@ Thumbs.db
#vichan custom #vichan custom
favicon.ico favicon.ico
/static/spoiler.png /static/spoiler.png
/vendor/

View File

@ -61,10 +61,11 @@ Installation
development version with: development version with:
git clone git://github.com/vichan-devel/vichan.git git clone git://github.com/vichan-devel/vichan.git
2. Navigate to ```install.php``` in your web browser and follow the 2. run ```composer install``` inside the directory
3. Navigate to ```install.php``` in your web browser and follow the
prompts. prompts.
3. vichan should now be installed. Log in to ```mod.php``` with the 4. vichan should now be installed. Log in to ```mod.php``` with the
default username and password combination: **admin / password**. default username and password combination: **admin / password**.
Please remember to change the administrator account password. Please remember to change the administrator account password.

View File

@ -1,6 +1,5 @@
<?php <?php
require_once 'inc/functions.php'; require_once 'inc/bootstrap.php';
require_once 'inc/bans.php';
checkBan(); checkBan();
print "<!doctype html><html><head><meta charset='utf-8'><title>"._("Banned?")."</title></head><body>"; print "<!doctype html><html><head><meta charset='utf-8'><title>"._("Banned?")."</title></head><body>";
print "<h1>"._("You are not banned.")."</h1>"; print "<h1>"._("You are not banned.")."</h1>";

38
composer.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "vichan-devel/vichan",
"description": "vichan imageboard",
"type": "project",
"require": {
"ext-mbstring": ">=5.4",
"ext-gd": ">=5.4",
"ext-pdo": ">=5.4",
"twig/twig": "^1.44.2",
"lifo/ip": "^1.0",
"gettext/gettext": "^1.0",
"mrclay/minify": "^2.1.6",
"geoip/geoip": "^1.17"
},
"autoload": {
"classmap": ["inc/"],
"files": [
"inc/bootstrap.php",
"inc/display.php",
"inc/template.php",
"inc/database.php",
"inc/events.php",
"inc/api.php",
"inc/mod/auth.php",
"inc/lock.php",
"inc/queue.php",
"inc/polyfill.php",
"inc/functions.php"
]
},
"license": "Tinyboard + vichan",
"authors": [
{
"name": "h00j",
"email": "admin@vichan.net"
}
]
}

384
composer.lock generated Normal file
View File

@ -0,0 +1,384 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e78104dfc51d725ae15a17e7a70e7ca3",
"packages": [
{
"name": "geoip/geoip",
"version": "v1.17",
"source": {
"type": "git",
"url": "https://github.com/maxmind/geoip-api-php.git",
"reference": "2053a85c2ed3e7adcbaf0117e26832f57366e370"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maxmind/geoip-api-php/zipball/2053a85c2ed3e7adcbaf0117e26832f57366e370",
"reference": "2053a85c2ed3e7adcbaf0117e26832f57366e370",
"shasum": ""
},
"conflict": {
"ext-geoip": "*"
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"satooshi/php-coveralls": "1.0.*"
},
"type": "library",
"autoload": {
"files": [
"src/geoip.inc",
"src/geoipcity.inc",
"src/timezone.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL 2.1+"
],
"authors": [
{
"name": "MaxMind, Inc.",
"email": "support@maxmind.com",
"homepage": "http://www.maxmind.com/"
}
],
"description": "MaxMind GeoIP PHP API",
"homepage": "http://dev.maxmind.com/geoip/legacy/downloadable",
"keywords": [
"geoip",
"geolocation",
"maxmind"
],
"support": {
"issues": "https://github.com/maxmind/geoip-api-php/issues",
"source": "https://github.com/maxmind/geoip-api-php/tree/master"
},
"time": "2016-05-16T19:06:50+00:00"
},
{
"name": "gettext/gettext",
"version": "v1.1.5",
"source": {
"type": "git",
"url": "https://github.com/php-gettext/Gettext.git",
"reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-gettext/Gettext/zipball/1bdf755a1b49f0614d6fc29f446df567eb62cd5c",
"reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Gettext": ""
},
"files": [
"Gettext/translator_functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"AGPL-3.0"
],
"authors": [
{
"name": "Oscar Otero",
"email": "oom@oscarotero.com",
"homepage": "http://oscarotero.com",
"role": "Developer"
}
],
"description": "PHP - JS gettext conversor",
"homepage": "https://github.com/oscarotero/Gettext",
"keywords": [
"JS",
"gettext",
"i18n",
"translation"
],
"support": {
"email": "oom@oscarotero.com",
"issues": "https://github.com/oscarotero/Gettext/issues",
"source": "https://github.com/php-gettext/Gettext/tree/v1.1.5"
},
"time": "2014-10-22T15:53:45+00:00"
},
{
"name": "lifo/ip",
"version": "v1.1",
"source": {
"type": "git",
"url": "https://github.com/lifo101/ip.git",
"reference": "b6a36dab288d7aea155698808bfc6649799fe413"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lifo101/ip/zipball/b6a36dab288d7aea155698808bfc6649799fe413",
"reference": "b6a36dab288d7aea155698808bfc6649799fe413",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Lifo\\IP\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jason Morriss",
"email": "lifo2013@gmail.com"
}
],
"description": "IP address helper PHP library for working with IPv4 and IPv6 addresses",
"keywords": [
"IP",
"ip address",
"ipv4",
"ipv6"
],
"support": {
"issues": "https://github.com/lifo101/ip/issues",
"source": "https://github.com/lifo101/ip/tree/master"
},
"time": "2020-04-02T11:09:10+00:00"
},
{
"name": "mrclay/minify",
"version": "2.3.3",
"source": {
"type": "git",
"url": "https://github.com/mrclay/minify.git",
"reference": "1928e89208d28e91427b2f13b67acdbd8cd01ac9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mrclay/minify/zipball/1928e89208d28e91427b2f13b67acdbd8cd01ac9",
"reference": "1928e89208d28e91427b2f13b67acdbd8cd01ac9",
"shasum": ""
},
"require": {
"ext-pcre": "*",
"php": ">=5.2.1"
},
"require-dev": {
"tubalmartin/cssmin": "~2.4.8"
},
"suggest": {
"tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)"
},
"type": "library",
"autoload": {
"classmap": [
"min/lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Stephen Clay",
"email": "steve@mrclay.org",
"role": "Developer"
}
],
"description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers",
"homepage": "http://code.google.com/p/minify/",
"support": {
"email": "minify@googlegroups.com",
"issues": "http://code.google.com/p/minify/issues/list",
"source": "https://github.com/mrclay/minify/tree/2.x",
"wiki": "http://code.google.com/p/minify/w/list"
},
"time": "2017-11-03T21:04:01+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.22.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-01-07T16:49:33+00:00"
},
{
"name": "twig/twig",
"version": "v1.44.2",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "138c493c5b8ee7cff3821f80b8896d371366b5fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/138c493c5b8ee7cff3821f80b8896d371366b5fe",
"reference": "138c493c5b8ee7cff3821f80b8896d371366b5fe",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"psr/container": "^1.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.44-dev"
}
},
"autoload": {
"psr-0": {
"Twig_": "lib/"
},
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v1.44.2"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2021-01-05T10:10:05+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"ext-mbstring": ">=5.4",
"ext-gd": ">=5.4",
"ext-pdo": ">=5.4"
},
"platform-dev": [],
"plugin-api-version": "2.0.0"
}

View File

@ -1,9 +1,5 @@
<?php <?php
require 'inc/lib/IP/Lifo/IP/IP.php';
require 'inc/lib/IP/Lifo/IP/BC.php';
require 'inc/lib/IP/Lifo/IP/CIDR.php';
use Lifo\IP\CIDR; use Lifo\IP\CIDR;
class Bans { class Bans {

3
inc/bootstrap.php Normal file
View File

@ -0,0 +1,3 @@
<?php
define('TINYBOARD', 'xD');
require_once('vendor/autoload.php');

View File

@ -10,25 +10,8 @@ if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
exit; exit;
} }
define('TINYBOARD', null);
$microtime_start = microtime(true); $microtime_start = microtime(true);
require_once 'inc/display.php';
require_once 'inc/template.php';
require_once 'inc/database.php';
require_once 'inc/events.php';
require_once 'inc/api.php';
require_once 'inc/mod/auth.php';
require_once 'inc/lock.php';
require_once 'inc/queue.php';
require_once 'inc/polyfill.php';
@include_once 'inc/lib/parsedown/Parsedown.php'; // fail silently, this isn't a critical piece of code
if (!extension_loaded('gettext')) {
require_once 'inc/lib/gettext/gettext.inc';
}
// the user is not currently logged in as a moderator // the user is not currently logged in as a moderator
$mod = false; $mod = false;
@ -1785,7 +1768,6 @@ function buildJavascript() {
} }
if ($config['minify_js']) { if ($config['minify_js']) {
require_once 'inc/lib/minify/JSMin.php';
$script = JSMin::minify($script); $script = JSMin::minify($script);
} }

View File

@ -1,20 +0,0 @@
Copyright (c) 2013 Jason Morriss
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,293 +0,0 @@
<?php
/**
* This file is part of the Lifo\IP PHP Library.
*
* (c) Jason Morriss <lifo2013@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Lifo\IP;
/**
* BCMath helper class.
*
* Provides a handful of BCMath routines that are not included in the native
* PHP library.
*
* Note: The Bitwise functions operate on fixed byte boundaries. For example,
* comparing the following numbers uses X number of bits:
* 0xFFFF and 0xFF will result in comparison of 16 bits.
* 0xFFFFFFFF and 0xF will result in comparison of 32 bits.
* etc...
*
*/
abstract class BC
{
// Some common (maybe useless) constants
const MAX_INT_32 = '2147483647'; // 7FFFFFFF
const MAX_UINT_32 = '4294967295'; // FFFFFFFF
const MAX_INT_64 = '9223372036854775807'; // 7FFFFFFFFFFFFFFF
const MAX_UINT_64 = '18446744073709551615'; // FFFFFFFFFFFFFFFF
const MAX_INT_96 = '39614081257132168796771975167'; // 7FFFFFFFFFFFFFFFFFFFFFFF
const MAX_UINT_96 = '79228162514264337593543950335'; // FFFFFFFFFFFFFFFFFFFFFFFF
const MAX_INT_128 = '170141183460469231731687303715884105727'; // 7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
const MAX_UINT_128 = '340282366920938463463374607431768211455'; // FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
/**
* BC Math function to convert a HEX string into a DECIMAL
*/
public static function bchexdec($hex)
{
if (strlen($hex) == 1) {
return hexdec($hex);
}
$remain = substr($hex, 0, -1);
$last = substr($hex, -1);
return bcadd(bcmul(16, self::bchexdec($remain), 0), hexdec($last), 0);
}
/**
* BC Math function to convert a DECIMAL string into a BINARY string
*/
public static function bcdecbin($dec, $pad = null)
{
$bin = '';
while ($dec) {
$m = bcmod($dec, 2);
$dec = bcdiv($dec, 2, 0);
$bin = abs($m) . $bin;
}
return $pad ? sprintf("%0{$pad}s", $bin) : $bin;
}
/**
* BC Math function to convert a BINARY string into a DECIMAL string
*/
public static function bcbindec($bin)
{
$dec = '0';
for ($i=0, $j=strlen($bin); $i<$j; $i++) {
$dec = bcmul($dec, '2', 0);
$dec = bcadd($dec, $bin[$i], 0);
}
return $dec;
}
/**
* BC Math function to convert a BINARY string into a HEX string
*/
public static function bcbinhex($bin, $pad = 0)
{
return self::bcdechex(self::bcbindec($bin));
}
/**
* BC Math function to convert a DECIMAL into a HEX string
*/
public static function bcdechex($dec)
{
$last = bcmod($dec, 16);
$remain = bcdiv(bcsub($dec, $last, 0), 16, 0);
return $remain == 0 ? dechex($last) : self::bcdechex($remain) . dechex($last);
}
/**
* Bitwise AND two arbitrarily large numbers together.
*/
public static function bcand($left, $right)
{
$len = self::_bitwise($left, $right);
$value = '';
for ($i=0; $i<$len; $i++) {
$value .= (($left[$i] + 0) & ($right[$i] + 0)) ? '1' : '0';
}
return self::bcbindec($value != '' ? $value : '0');
}
/**
* Bitwise OR two arbitrarily large numbers together.
*/
public static function bcor($left, $right)
{
$len = self::_bitwise($left, $right);
$value = '';
for ($i=0; $i<$len; $i++) {
$value .= (($left[$i] + 0) | ($right[$i] + 0)) ? '1' : '0';
}
return self::bcbindec($value != '' ? $value : '0');
}
/**
* Bitwise XOR two arbitrarily large numbers together.
*/
public static function bcxor($left, $right)
{
$len = self::_bitwise($left, $right);
$value = '';
for ($i=0; $i<$len; $i++) {
$value .= (($left[$i] + 0) ^ ($right[$i] + 0)) ? '1' : '0';
}
return self::bcbindec($value != '' ? $value : '0');
}
/**
* Bitwise NOT two arbitrarily large numbers together.
*/
public static function bcnot($left, $bits = null)
{
$right = 0;
$len = self::_bitwise($left, $right, $bits);
$value = '';
for ($i=0; $i<$len; $i++) {
$value .= $left[$i] == '1' ? '0' : '1';
}
return self::bcbindec($value);
}
/**
* Shift number to the left
*
* @param integer $bits Total bits to shift
*/
public static function bcleft($num, $bits) {
return bcmul($num, bcpow('2', $bits));
}
/**
* Shift number to the right
*
* @param integer $bits Total bits to shift
*/
public static function bcright($num, $bits) {
return bcdiv($num, bcpow('2', $bits));
}
/**
* Determine how many bits are needed to store the number rounded to the
* nearest bit boundary.
*/
public static function bits_needed($num, $boundary = 4)
{
$bits = 0;
while ($num > 0) {
$num = bcdiv($num, '2', 0);
$bits++;
}
// round to nearest boundrary
return $boundary ? ceil($bits / $boundary) * $boundary : $bits;
}
/**
* BC Math function to return an arbitrarily large random number.
*/
public static function bcrand($min, $max = null)
{
if ($max === null) {
$max = $min;
$min = 0;
}
// swap values if $min > $max
if (bccomp($min, $max) == 1) {
list($min,$max) = array($max,$min);
}
return bcadd(
bcmul(
bcdiv(
mt_rand(0, mt_getrandmax()),
mt_getrandmax(),
strlen($max)
),
bcsub(
bcadd($max, '1'),
$min
)
),
$min
);
}
/**
* Computes the natural logarithm using a series.
* @author Thomas Oldbury.
* @license Public domain.
*/
public static function bclog($num, $iter = 10, $scale = 100)
{
$log = "0.0";
for($i = 0; $i < $iter; $i++) {
$pow = 1 + (2 * $i);
$mul = bcdiv("1.0", $pow, $scale);
$fraction = bcmul($mul, bcpow(bcsub($num, "1.0", $scale) / bcadd($num, "1.0", $scale), $pow, $scale), $scale);
$log = bcadd($fraction, $log, $scale);
}
return bcmul("2.0", $log, $scale);
}
/**
* Computes the base2 log using baseN log.
*/
public static function bclog2($num, $iter = 10, $scale = 100)
{
return bcdiv(self::bclog($num, $iter, $scale), self::bclog("2", $iter, $scale), $scale);
}
public static function bcfloor($num)
{
if (substr($num, 0, 1) == '-') {
return bcsub($num, 1, 0);
}
return bcadd($num, 0, 0);
}
public static function bcceil($num)
{
if (substr($num, 0, 1) == '-') {
return bcsub($num, 0, 0);
}
return bcadd($num, 1, 0);
}
/**
* Compare two numbers and return -1, 0, 1 depending if the LEFT number is
* < = > the RIGHT.
*
* @param string|integer $left Left side operand
* @param string|integer $right Right side operand
* @return integer Return -1,0,1 for <=> comparison
*/
public static function cmp($left, $right)
{
// @todo could an optimization be done to determine if a normal 32bit
// comparison could be done instead of using bccomp? But would
// the number verification cause too much overhead to be useful?
return bccomp($left, $right, 0);
}
/**
* Internal function to prepare for bitwise operations
*/
private static function _bitwise(&$left, &$right, $bits = null)
{
if ($bits === null) {
$bits = max(self::bits_needed($left), self::bits_needed($right));
}
$left = self::bcdecbin($left);
$right = self::bcdecbin($right);
$len = max(strlen($left), strlen($right), (int)$bits);
$left = sprintf("%0{$len}s", $left);
$right = sprintf("%0{$len}s", $right);
return $len;
}
}

View File

@ -1,706 +0,0 @@
<?php
/**
* This file is part of the Lifo\IP PHP Library.
*
* (c) Jason Morriss <lifo2013@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Lifo\IP;
/**
* CIDR Block helper class.
*
* Most routines can be used statically or by instantiating an object and
* calling its methods.
*
* Provides routines to do various calculations on IP addresses and ranges.
* Convert to/from CIDR to ranges, etc.
*/
class CIDR
{
const INTERSECT_NO = 0;
const INTERSECT_YES = 1;
const INTERSECT_LOW = 2;
const INTERSECT_HIGH = 3;
protected $start;
protected $end;
protected $prefix;
protected $version;
protected $istart;
protected $iend;
private $cache;
/**
* Create a new CIDR object.
*
* The IP range can be arbitrary and does not have to fall on a valid CIDR
* range. Some methods will return different values depending if you ignore
* the prefix or not. By default all prefix sensitive methods will assume
* the prefix is used.
*
* @param string $cidr An IP address (1.2.3.4), CIDR block (1.2.3.4/24),
* or range "1.2.3.4-1.2.3.10"
* @param string $end Ending IP in range if no cidr/prefix is given
*/
public function __construct($cidr, $end = null)
{
if ($end !== null) {
$this->setRange($cidr, $end);
} else {
$this->setCidr($cidr);
}
}
/**
* Returns the string representation of the CIDR block.
*/
public function __toString()
{
// do not include the prefix if its a single IP
try {
if ($this->isTrueCidr() && (
($this->version == 4 and $this->prefix != 32) ||
($this->version == 6 and $this->prefix != 128)
)
) {
return $this->start . '/' . $this->prefix;
}
} catch (\Exception $e) {
// isTrueCidr() calls getRange which can throw an exception
}
if (strcmp($this->start, $this->end) == 0) {
return $this->start;
}
return $this->start . ' - ' . $this->end;
}
public function __clone()
{
// do not clone the cache. No real reason why. I just want to keep the
// memory foot print as low as possible, even though this is trivial.
$this->cache = array();
}
/**
* Set an arbitrary IP range.
* The closest matching prefix will be calculated but the actual range
* stored in the object can be arbitrary.
* @param string $start Starting IP or combination "start-end" string.
* @param string $end Ending IP or null.
*/
public function setRange($ip, $end = null)
{
if (strpos($ip, '-') !== false) {
list($ip, $end) = array_map('trim', explode('-', $ip, 2));
}
if (false === filter_var($ip, FILTER_VALIDATE_IP) ||
false === filter_var($end, FILTER_VALIDATE_IP)) {
throw new \InvalidArgumentException("Invalid IP range \"$ip-$end\"");
}
// determine version (4 or 6)
$this->version = (false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ? 6 : 4;
$this->istart = IP::inet_ptod($ip);
$this->iend = IP::inet_ptod($end);
// fix order
if (bccomp($this->istart, $this->iend) == 1) {
list($this->istart, $this->iend) = array($this->iend, $this->istart);
list($ip, $end) = array($end, $ip);
}
$this->start = $ip;
$this->end = $end;
// calculate real prefix
$len = $this->version == 4 ? 32 : 128;
$this->prefix = $len - strlen(BC::bcdecbin(BC::bcxor($this->istart, $this->iend)));
}
/**
* Returns true if the current IP is a true cidr block
*/
public function isTrueCidr()
{
return $this->start == $this->getNetwork() && $this->end == $this->getBroadcast();
}
/**
* Set the CIDR block.
*
* The prefix length is optional and will default to 32 ot 128 depending on
* the version detected.
*
* @param string $cidr CIDR block string, eg: "192.168.0.0/24" or "2001::1/64"
* @throws \InvalidArgumentException If the CIDR block is invalid
*/
public function setCidr($cidr)
{
if (strpos($cidr, '-') !== false) {
return $this->setRange($cidr);
}
list($ip, $bits) = array_pad(array_map('trim', explode('/', $cidr, 2)), 2, null);
if (false === filter_var($ip, FILTER_VALIDATE_IP)) {
throw new \InvalidArgumentException("Invalid IP address \"$cidr\"");
}
// determine version (4 or 6)
$this->version = (false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ? 6 : 4;
$this->start = $ip;
$this->istart = IP::inet_ptod($ip);
if ($bits !== null and $bits !== '') {
$this->prefix = $bits;
} else {
$this->prefix = $this->version == 4 ? 32 : 128;
}
if (($this->prefix < 0)
|| ($this->prefix > 32 and $this->version == 4)
|| ($this->prefix > 128 and $this->version == 6)) {
throw new \InvalidArgumentException("Invalid IP address \"$cidr\"");
}
$this->end = $this->getBroadcast();
$this->iend = IP::inet_ptod($this->end);
$this->cache = array();
}
/**
* Get the IP version. 4 or 6.
*
* @return integer
*/
public function getVersion()
{
return $this->version;
}
/**
* Get the prefix.
*
* Always returns the "proper" prefix, even if the IP range is arbitrary.
*
* @return integer
*/
public function getPrefix()
{
return $this->prefix;
}
/**
* Return the starting presentational IP or Decimal value.
*
* Ignores prefix
*/
public function getStart($decimal = false)
{
return $decimal ? $this->istart : $this->start;
}
/**
* Return the ending presentational IP or Decimal value.
*
* Ignores prefix
*/
public function getEnd($decimal = false)
{
return $decimal ? $this->iend : $this->end;
}
/**
* Return the next presentational IP or Decimal value (following the
* broadcast address of the current CIDR block).
*/
public function getNext($decimal = false)
{
$next = bcadd($this->getEnd(true), '1');
return $decimal ? $next : new self(IP::inet_dtop($next));
}
/**
* Returns true if the IP is an IPv4
*
* @return boolean
*/
public function isIPv4()
{
return $this->version == 4;
}
/**
* Returns true if the IP is an IPv6
*
* @return boolean
*/
public function isIPv6()
{
return $this->version == 6;
}
/**
* Get the cidr notation for the subnet block.
*
* This is useful for when you want a string representation of the IP/prefix
* and the starting IP is not on a valid network boundrary (eg: Displaying
* an IP from an interface).
*
* @return string IP in CIDR notation "ipaddr/prefix"
*/
public function getCidr()
{
return $this->start . '/' . $this->prefix;
}
/**
* Get the [low,high] range of the CIDR block
*
* Prefix sensitive.
*
* @param boolean $ignorePrefix If true the arbitrary start-end range is
* returned. default=false.
*/
public function getRange($ignorePrefix = false)
{
$range = $ignorePrefix
? array($this->start, $this->end)
: self::cidr_to_range($this->start, $this->prefix);
// watch out for IP '0' being converted to IPv6 '::'
if ($range[0] == '::' and strpos($range[1], ':') == false) {
$range[0] = '0.0.0.0';
}
return $range;
}
/**
* Return the IP in its fully expanded form.
*
* For example: 2001::1 == 2007:0000:0000:0000:0000:0000:0000:0001
*
* @see IP::inet_expand
*/
public function getExpanded()
{
return IP::inet_expand($this->start);
}
/**
* Get network IP of the CIDR block
*
* Prefix sensitive.
*
* @param boolean $ignorePrefix If true the arbitrary start-end range is
* returned. default=false.
*/
public function getNetwork($ignorePrefix = false)
{
// micro-optimization to prevent calling getRange repeatedly
$k = $ignorePrefix ? 1 : 0;
if (!isset($this->cache['range'][$k])) {
$this->cache['range'][$k] = $this->getRange($ignorePrefix);
}
return $this->cache['range'][$k][0];
}
/**
* Get broadcast IP of the CIDR block
*
* Prefix sensitive.
*
* @param boolean $ignorePrefix If true the arbitrary start-end range is
* returned. default=false.
*/
public function getBroadcast($ignorePrefix = false)
{
// micro-optimization to prevent calling getRange repeatedly
$k = $ignorePrefix ? 1 : 0;
if (!isset($this->cache['range'][$k])) {
$this->cache['range'][$k] = $this->getRange($ignorePrefix);
}
return $this->cache['range'][$k][1];
}
/**
* Get the network mask based on the prefix.
*
*/
public function getMask()
{
return self::prefix_to_mask($this->prefix, $this->version);
}
/**
* Get total hosts within CIDR range
*
* Prefix sensitive.
*
* @param boolean $ignorePrefix If true the arbitrary start-end range is
* returned. default=false.
*/
public function getTotal($ignorePrefix = false)
{
// micro-optimization to prevent calling getRange repeatedly
$k = $ignorePrefix ? 1 : 0;
if (!isset($this->cache['range'][$k])) {
$this->cache['range'][$k] = $this->getRange($ignorePrefix);
}
return bcadd(bcsub(IP::inet_ptod($this->cache['range'][$k][1]),
IP::inet_ptod($this->cache['range'][$k][0])), '1');
}
public function intersects($cidr)
{
return self::cidr_intersect((string)$this, $cidr);
}
/**
* Determines the intersection between an IP (with optional prefix) and a
* CIDR block.
*
* The IP will be checked against the CIDR block given and will either be
* inside or outside the CIDR completely, or partially.
*
* NOTE: The caller should explicitly check against the INTERSECT_*
* constants because this method will return a value > 1 even for partial
* matches.
*
* @param mixed $ip The IP/cidr to match
* @param mixed $cidr The CIDR block to match within
* @return integer Returns an INTERSECT_* constant
* @throws \InvalidArgumentException if either $ip or $cidr is invalid
*/
public static function cidr_intersect($ip, $cidr)
{
// use fixed length HEX strings so we can easily do STRING comparisons
// instead of using slower bccomp() math.
list($lo,$hi) = array_map(function($v){ return sprintf("%032s", IP::inet_ptoh($v)); }, CIDR::cidr_to_range($ip));
list($min,$max) = array_map(function($v){ return sprintf("%032s", IP::inet_ptoh($v)); }, CIDR::cidr_to_range($cidr));
/** visualization of logic used below
lo-hi = $ip to check
min-max = $cidr block being checked against
--- --- --- lo --- --- hi --- --- --- --- --- IP/prefix to check
--- min --- --- max --- --- --- --- --- --- --- Partial "LOW" match
--- --- --- --- --- min --- --- max --- --- --- Partial "HIGH" match
--- --- --- --- min max --- --- --- --- --- --- No match "NO"
--- --- --- --- --- --- --- --- min --- max --- No match "NO"
min --- max --- --- --- --- --- --- --- --- --- No match "NO"
--- --- min --- --- --- --- max --- --- --- --- Full match "YES"
*/
// IP is exact match or completely inside the CIDR block
if ($lo >= $min and $hi <= $max) {
return self::INTERSECT_YES;
}
// IP is completely outside the CIDR block
if ($max < $lo or $min > $hi) {
return self::INTERSECT_NO;
}
// @todo is it useful to return LOW/HIGH partial matches?
// IP matches the lower end
if ($max <= $hi and $min <= $lo) {
return self::INTERSECT_LOW;
}
// IP matches the higher end
if ($min >= $lo and $max >= $hi) {
return self::INTERSECT_HIGH;
}
return self::INTERSECT_NO;
}
/**
* Converts an IPv4 or IPv6 CIDR block into its range.
*
* @todo May not be the fastest way to do this.
*
* @static
* @param string $cidr CIDR block or IP address string.
* @param integer|null $bits If /bits is not specified on string they can be
* passed via this parameter instead.
* @return array A 2 element array with the low, high range
*/
public static function cidr_to_range($cidr, $bits = null)
{
if (strpos($cidr, '/') !== false) {
list($ip, $_bits) = array_pad(explode('/', $cidr, 2), 2, null);
} else {
$ip = $cidr;
$_bits = $bits;
}
if (false === filter_var($ip, FILTER_VALIDATE_IP)) {
throw new \InvalidArgumentException("IP address \"$cidr\" is invalid");
}
// force bit length to 32 or 128 depending on type of IP
$bitlen = (false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ? 128 : 32;
if ($bits === null) {
// if no prefix is given use the length of the binary string which
// will give us 32 or 128 and result in a single IP being returned.
$bits = $_bits !== null ? $_bits : $bitlen;
}
if ($bits > $bitlen) {
throw new \InvalidArgumentException("IP address \"$cidr\" is invalid");
}
$ipdec = IP::inet_ptod($ip);
$ipbin = BC::bcdecbin($ipdec, $bitlen);
// calculate network
$netmask = BC::bcbindec(str_pad(str_repeat('1',$bits), $bitlen, '0'));
$ip1 = BC::bcand($ipdec, $netmask);
// calculate "broadcast" (not technically a broadcast in IPv6)
$ip2 = BC::bcor($ip1, BC::bcnot($netmask));
return array(IP::inet_dtop($ip1), IP::inet_dtop($ip2));
}
/**
* Return the CIDR string from the range given
*/
public static function range_to_cidr($start, $end)
{
$cidr = new CIDR($start, $end);
return (string)$cidr;
}
/**
* Return the maximum prefix length that would fit the IP address given.
*
* This is useful to determine how my bit would be needed to store the IP
* address when you don't already have a prefix for the IP.
*
* @example 216.240.32.0 would return 27
*
* @param string $ip IP address without prefix
* @param integer $bits Maximum bits to check; defaults to 32 for IPv4 and 128 for IPv6
*/
public static function max_prefix($ip, $bits = null)
{
static $mask = array();
$ver = (false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ? 6 : 4;
$max = $ver == 6 ? 128 : 32;
if ($bits === null) {
$bits = $max;
}
$int = IP::inet_ptod($ip);
while ($bits > 0) {
// micro-optimization; calculate mask once ...
if (!isset($mask[$ver][$bits-1])) {
// 2^$max - 2^($max - $bits);
if ($ver == 4) {
$mask[$ver][$bits-1] = pow(2, $max) - pow(2, $max - ($bits-1));
} else {
$mask[$ver][$bits-1] = bcsub(bcpow(2, $max), bcpow(2, $max - ($bits-1)));
}
}
$m = $mask[$ver][$bits-1];
//printf("%s/%d: %s & %s == %s\n", $ip, $bits-1, BC::bcdecbin($m, 32), BC::bcdecbin($int, 32), BC::bcdecbin(BC::bcand($int, $m)));
//echo "$ip/", $bits-1, ": ", IP::inet_dtop($m), " ($m) & $int == ", BC::bcand($int, $m), "\n";
if (bccomp(BC::bcand($int, $m), $int) != 0) {
return $bits;
}
$bits--;
}
return $bits;
}
/**
* Return a contiguous list of true CIDR blocks that span the range given.
*
* Note: It's not a good idea to call this with IPv6 addresses. While it may
* work for certain ranges this can be very slow. Also an IPv6 list won't be
* as accurate as an IPv4 list.
*
* @example
* range_to_cidrlist(192.168.0.0, 192.168.0.15) ==
* 192.168.0.0/28
* range_to_cidrlist(192.168.0.0, 192.168.0.20) ==
* 192.168.0.0/28
* 192.168.0.16/30
* 192.168.0.20/32
*/
public static function range_to_cidrlist($start, $end)
{
$ver = (false === filter_var($start, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) ? 6 : 4;
$start = IP::inet_ptod($start);
$end = IP::inet_ptod($end);
$len = $ver == 4 ? 32 : 128;
$log2 = $ver == 4 ? log(2) : BC::bclog(2);
$list = array();
while (BC::cmp($end, $start) >= 0) { // $end >= $start
$prefix = self::max_prefix(IP::inet_dtop($start), $len);
if ($ver == 4) {
$diff = $len - floor( log($end - $start + 1) / $log2 );
} else {
// this is not as accurate due to the bclog function
$diff = bcsub($len, BC::bcfloor(bcdiv(BC::bclog(bcadd(bcsub($end, $start), '1')), $log2)));
}
if ($prefix < $diff) {
$prefix = $diff;
}
$list[] = IP::inet_dtop($start) . "/" . $prefix;
if ($ver == 4) {
$start += pow(2, $len - $prefix);
} else {
$start = bcadd($start, bcpow(2, $len - $prefix));
}
}
return $list;
}
/**
* Return an list of optimized CIDR blocks by collapsing adjacent CIDR
* blocks into larger blocks.
*
* @param array $cidrs List of CIDR block strings or objects
* @param integer $maxPrefix Maximum prefix to allow
* @return array Optimized list of CIDR objects
*/
public static function optimize_cidrlist($cidrs, $maxPrefix = 32)
{
// all indexes must be a CIDR object
$cidrs = array_map(function($o){ return $o instanceof CIDR ? $o : new CIDR($o); }, $cidrs);
// sort CIDR blocks in proper order so we can easily loop over them
$cidrs = self::cidr_sort($cidrs);
$list = array();
while ($cidrs) {
$c = array_shift($cidrs);
$start = $c->getStart();
$max = bcadd($c->getStart(true), $c->getTotal());
// loop through each cidr block until its ending range is more than
// the current maximum.
while (!empty($cidrs) and $cidrs[0]->getStart(true) <= $max) {
$b = array_shift($cidrs);
$newmax = bcadd($b->getStart(true), $b->getTotal());
if ($newmax > $max) {
$max = $newmax;
}
}
// add the new cidr range to the optimized list
$list = array_merge($list, self::range_to_cidrlist($start, IP::inet_dtop(bcsub($max, '1'))));
}
return $list;
}
/**
* Sort the list of CIDR blocks, optionally with a custom callback function.
*
* @param array $cidrs A list of CIDR blocks (strings or objects)
* @param Closure $callback Optional callback to perform the sorting.
* See PHP usort documentation for more details.
*/
public static function cidr_sort($cidrs, $callback = null)
{
// all indexes must be a CIDR object
$cidrs = array_map(function($o){ return $o instanceof CIDR ? $o : new CIDR($o); }, $cidrs);
if ($callback === null) {
$callback = function($a, $b) {
if (0 != ($o = BC::cmp($a->getStart(true), $b->getStart(true)))) {
return $o; // < or >
}
if ($a->getPrefix() == $b->getPrefix()) {
return 0;
}
return $a->getPrefix() < $b->getPrefix() ? -1 : 1;
};
} elseif (!($callback instanceof \Closure) or !is_callable($callback)) {
throw new \InvalidArgumentException("Invalid callback in CIDR::cidr_sort, expected Closure, got " . gettype($callback));
}
usort($cidrs, $callback);
return $cidrs;
}
/**
* Return the Prefix bits from the IPv4 mask given.
*
* This is only valid for IPv4 addresses since IPv6 addressing does not
* have a concept of network masks.
*
* Example: 255.255.255.0 == 24
*
* @param string $mask IPv4 network mask.
*/
public static function mask_to_prefix($mask)
{
if (false === filter_var($mask, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
throw new \InvalidArgumentException("Invalid IP netmask \"$mask\"");
}
return strrpos(IP::inet_ptob($mask, 32), '1') + 1;
}
/**
* Return the network mask for the prefix given.
*
* Normally this is only useful for IPv4 addresses but you can generate a
* mask for IPv6 addresses as well, only because its mathematically
* possible.
*
* @param integer $prefix CIDR prefix bits (0-128)
* @param integer $version IP version. If null the version will be detected
* based on the prefix length given.
*/
public static function prefix_to_mask($prefix, $version = null)
{
if ($version === null) {
$version = $prefix > 32 ? 6 : 4;
}
if ($prefix < 0 or $prefix > 128) {
throw new \InvalidArgumentException("Invalid prefix length \"$prefix\"");
}
if ($version != 4 and $version != 6) {
throw new \InvalidArgumentException("Invalid version \"$version\". Must be 4 or 6");
}
if ($version == 4) {
return long2ip($prefix == 0 ? 0 : (0xFFFFFFFF >> (32 - $prefix)) << (32 - $prefix));
} else {
return IP::inet_dtop($prefix == 0 ? 0 : BC::bcleft(BC::bcright(BC::MAX_UINT_128, 128-$prefix), 128-$prefix));
}
}
/**
* Return true if the $ip given is a true CIDR block.
*
* A true CIDR block is one where the $ip given is the actual Network
* address and broadcast matches the prefix appropriately.
*/
public static function cidr_is_true($ip)
{
$ip = new CIDR($ip);
return $ip->isTrueCidr();
}
}

View File

@ -1,207 +0,0 @@
<?php
/**
* This file is part of the Lifo\IP PHP Library.
*
* (c) Jason Morriss <lifo2013@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Lifo\IP;
/**
* IP Address helper class.
*
* Provides routines to translate IPv4 and IPv6 addresses between human readable
* strings, decimal, hexidecimal and binary.
*
* Requires BCmath extension and IPv6 PHP support
*/
abstract class IP
{
/**
* Convert a human readable (presentational) IP address string into a decimal string.
*/
public static function inet_ptod($ip)
{
// shortcut for IPv4 addresses
if (strpos($ip, ':') === false && strpos($ip, '.') !== false) {
return sprintf('%u', ip2long($ip));
}
// remove any cidr block notation
if (($o = strpos($ip, '/')) !== false) {
$ip = substr($ip, 0, $o);
}
// unpack into 4 32bit integers
$parts = unpack('N*', inet_pton($ip));
foreach ($parts as &$part) {
if ($part < 0) {
// convert signed int into unsigned
$part = sprintf('%u', $part);
//$part = bcadd($part, '4294967296');
}
}
// add each 32bit integer to the proper bit location in our big decimal
$decimal = $parts[4]; // << 0
$decimal = bcadd($decimal, bcmul($parts[3], '4294967296')); // << 32
$decimal = bcadd($decimal, bcmul($parts[2], '18446744073709551616')); // << 64
$decimal = bcadd($decimal, bcmul($parts[1], '79228162514264337593543950336')); // << 96
return $decimal;
}
/**
* Convert a decimal string into a human readable IP address.
*/
public static function inet_dtop($decimal, $expand = false)
{
$parts = array();
$parts[1] = bcdiv($decimal, '79228162514264337593543950336', 0); // >> 96
$decimal = bcsub($decimal, bcmul($parts[1], '79228162514264337593543950336'));
$parts[2] = bcdiv($decimal, '18446744073709551616', 0); // >> 64
$decimal = bcsub($decimal, bcmul($parts[2], '18446744073709551616'));
$parts[3] = bcdiv($decimal, '4294967296', 0); // >> 32
$decimal = bcsub($decimal, bcmul($parts[3], '4294967296'));
$parts[4] = $decimal; // >> 0
foreach ($parts as &$part) {
if (bccomp($part, '2147483647') == 1) {
$part = bcsub($part, '4294967296');
}
$part = (int) $part;
}
// if the first 96bits is all zeros then we can safely assume we
// actually have an IPv4 address. Even though it's technically possible
// you're not really ever going to see an IPv6 address in the range:
// ::0 - ::ffff
// It's feasible to see an IPv6 address of "::", in which case the
// caller is going to have to account for that on their own.
if (($parts[1] | $parts[2] | $parts[3]) == 0) {
$ip = long2ip($parts[4]);
} else {
$packed = pack('N4', $parts[1], $parts[2], $parts[3], $parts[4]);
$ip = inet_ntop($packed);
}
// Turn IPv6 to IPv4 if it's IPv4
if (preg_match('/^::\d+\./', $ip)) {
return substr($ip, 2);
}
return $expand ? self::inet_expand($ip) : $ip;
}
/**
* Convert a human readable (presentational) IP address into a HEX string.
*/
public static function inet_ptoh($ip)
{
return bin2hex(inet_pton($ip));
//return BC::bcdechex(self::inet_ptod($ip));
}
/**
* Convert a human readable (presentational) IP address into a BINARY string.
*/
public static function inet_ptob($ip, $bits = 128)
{
return BC::bcdecbin(self::inet_ptod($ip), $bits);
}
/**
* Convert a binary string into an IP address (presentational) string.
*/
public static function inet_btop($bin)
{
return self::inet_dtop(BC::bcbindec($bin));
}
/**
* Convert a HEX string into a human readable (presentational) IP address
*/
public static function inet_htop($hex)
{
return self::inet_dtop(BC::bchexdec($hex));
}
/**
* Expand an IP address. IPv4 addresses are returned as-is.
*
* Example:
* 2001::1 expands to 2001:0000:0000:0000:0000:0000:0000:0001
* ::127.0.0.1 expands to 0000:0000:0000:0000:0000:0000:7f00:0001
* 127.0.0.1 expands to 127.0.0.1
*/
public static function inet_expand($ip)
{
// strip possible cidr notation off
if (($pos = strpos($ip, '/')) !== false) {
$ip = substr($ip, 0, $pos);
}
$bytes = unpack('n*', inet_pton($ip));
if (count($bytes) > 2) {
return implode(':', array_map(function ($b) {
return sprintf("%04x", $b);
}, $bytes));
}
return $ip;
}
/**
* Convert an IPv4 address into an IPv6 address.
*
* One use-case for this is IP 6to4 tunnels used in networking.
*
* @example
* to_ipv4("10.10.10.10") == a0a:a0a
*
* @param string $ip IPv4 address.
* @param boolean $mapped If true a Full IPv6 address is returned within the
* official ipv4to6 mapped space "0:0:0:0:0:ffff:x:x"
*/
public static function to_ipv6($ip, $mapped = false)
{
if (!self::isIPv4($ip)) {
throw new \InvalidArgumentException("Invalid IPv4 address \"$ip\"");
}
$num = IP::inet_ptod($ip);
$o1 = dechex($num >> 16);
$o2 = dechex($num & 0x0000FFFF);
return $mapped ? "0:0:0:0:0:ffff:$o1:$o2" : "$o1:$o2";
}
/**
* Returns true if the IP address is a valid IPv4 address
*/
public static function isIPv4($ip)
{
return $ip === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
}
/**
* Returns true if the IP address is a valid IPv6 address
*/
public static function isIPv6($ip)
{
return $ip === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
}
/**
* Compare two IP's (v4 or v6) and return -1, 0, 1 if the first is < = >
* the second.
*
* @param string $ip1 IP address
* @param string $ip2 IP address to compare against
* @return integer Return -1,0,1 depending if $ip1 is <=> $ip2
*/
public static function cmp($ip1, $ip2)
{
return bccomp(self::inet_ptod($ip1), self::inet_ptod($ip2), 0);
}
}

View File

@ -1,54 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Autoloader class is deprecated since version 1.21 and will be removed in 2.0. Use Composer instead.', E_USER_DEPRECATED);
/**
* Autoloads Twig classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.21 and will be removed in 2.0. Use Composer instead. 2.0.
*/
class Twig_Autoloader
{
/**
* Registers Twig_Autoloader as an SPL autoloader.
*
* @param bool $prepend whether to prepend the autoloader or not
*/
public static function register($prepend = false)
{
@trigger_error('Using Twig_Autoloader is deprecated since version 1.21. 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);
}
}
/**
* Handles autoloading of classes.
*
* @param string $class a class name
*/
public static function autoload($class)
{
if (0 !== strpos($class, 'Twig')) {
return;
}
if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
require $file;
}
}
}

View File

@ -1,54 +0,0 @@
<?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
{
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);
}
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.
*
* @return Twig_Node The modified node
*/
abstract protected function doEnterNode(Twig_Node $node, Twig_Environment $env);
/**
* Called after child nodes are visited.
*
* @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);
}
class_alias('Twig_BaseNodeVisitor', 'Twig\NodeVisitor\AbstractNodeVisitor', false);
class_exists('Twig_Environment');
class_exists('Twig_Node');

View File

@ -1,93 +0,0 @@
<?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.
*/
/**
* 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 = rtrim($directory, '\/').'/';
$this->options = $options;
}
public function generateKey($name, $className)
{
$hash = hash('sha256', $className);
return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
public function load($key)
{
if (file_exists($key)) {
@include_once $key;
}
}
public function write($key, $content)
{
$dir = dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
if (PHP_VERSION_ID >= 50300) {
clearstatcache(true, $dir);
}
if (!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));
}
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}
class_alias('Twig_Cache_Filesystem', 'Twig\Cache\FilesystemCache', false);

View File

@ -1,40 +0,0 @@
<?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.
*/
/**
* Implements a no-cache strategy.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Cache_Null implements Twig_CacheInterface
{
public function generateKey($name, $className)
{
return '';
}
public function write($key, $content)
{
}
public function load($key)
{
}
public function getTimestamp($key)
{
return 0;
}
}
class_alias('Twig_Cache_Null', 'Twig\Cache\NullCache', false);

View File

@ -1,58 +0,0 @@
<?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.
*/
/**
* 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);
}
class_alias('Twig_CacheInterface', 'Twig\Cache\CacheInterface', false);

View File

@ -1,286 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Compiles a node to PHP code.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Compiler implements Twig_CompilerInterface
{
protected $lastLine;
protected $source;
protected $indentation;
protected $env;
protected $debugInfo = array();
protected $sourceOffset;
protected $sourceLine;
protected $filename;
private $varNameSalt = 0;
public function __construct(Twig_Environment $env)
{
$this->env = $env;
}
/**
* @deprecated since 1.25 (to be removed in 2.0)
*/
public function getFilename()
{
@trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
return $this->filename;
}
/**
* Returns the environment instance related to this compiler.
*
* @return Twig_Environment
*/
public function getEnvironment()
{
return $this->env;
}
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource()
{
return $this->source;
}
/**
* Compiles a node.
*
* @param Twig_NodeInterface $node The node to compile
* @param int $indentation The current indentation
*
* @return $this
*/
public function compile(Twig_NodeInterface $node, $indentation = 0)
{
$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;
$this->indentation = $indentation;
$this->varNameSalt = 0;
if ($node instanceof Twig_Node_Module) {
// to be removed in 2.0
$this->filename = $node->getTemplateName();
}
$node->compile($this);
return $this;
}
public function subcompile(Twig_NodeInterface $node, $raw = true)
{
if (false === $raw) {
$this->source .= str_repeat(' ', $this->indentation * 4);
}
$node->compile($this);
return $this;
}
/**
* Adds a raw string to the compiled code.
*
* @param string $string The string
*
* @return $this
*/
public function raw($string)
{
$this->source .= $string;
return $this;
}
/**
* Writes a string to the compiled code by adding indentation.
*
* @return $this
*/
public function write()
{
$strings = func_get_args();
foreach ($strings as $string) {
$this->source .= str_repeat(' ', $this->indentation * 4).$string;
}
return $this;
}
/**
* Appends an indentation to the current PHP code after compilation.
*
* @return $this
*
* @deprecated since 1.27 (to be removed in 2.0).
*/
public function addIndentation()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use write(\'\') instead.', E_USER_DEPRECATED);
$this->source .= str_repeat(' ', $this->indentation * 4);
return $this;
}
/**
* Adds a quoted string to the compiled code.
*
* @param string $value The string
*
* @return $this
*/
public function string($value)
{
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
return $this;
}
/**
* Returns a PHP representation of a given value.
*
* @param mixed $value The value to convert
*
* @return $this
*/
public function repr($value)
{
if (is_int($value) || is_float($value)) {
if (false !== $locale = setlocale(LC_NUMERIC, '0')) {
setlocale(LC_NUMERIC, 'C');
}
$this->raw($value);
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
} elseif (null === $value) {
$this->raw('null');
} elseif (is_bool($value)) {
$this->raw($value ? 'true' : 'false');
} elseif (is_array($value)) {
$this->raw('array(');
$first = true;
foreach ($value as $key => $v) {
if (!$first) {
$this->raw(', ');
}
$first = false;
$this->repr($key);
$this->raw(' => ');
$this->repr($v);
}
$this->raw(')');
} else {
$this->string($value);
}
return $this;
}
/**
* Adds debugging information.
*
* @return $this
*/
public function addDebugInfo(Twig_NodeInterface $node)
{
if ($node->getTemplateLine() != $this->lastLine) {
$this->write(sprintf("// line %d\n", $node->getTemplateLine()));
// when mbstring.func_overload is set to 2
// mb_substr_count() replaces substr_count()
// but they have different signatures!
if (((int) ini_get('mbstring.func_overload')) & 2) {
@trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
// this is much slower than the "right" version
$this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
} else {
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
}
$this->sourceOffset = strlen($this->source);
$this->debugInfo[$this->sourceLine] = $node->getTemplateLine();
$this->lastLine = $node->getTemplateLine();
}
return $this;
}
public function getDebugInfo()
{
ksort($this->debugInfo);
return $this->debugInfo;
}
/**
* Indents the generated code.
*
* @param int $step The number of indentation to add
*
* @return $this
*/
public function indent($step = 1)
{
$this->indentation += $step;
return $this;
}
/**
* Outdents the generated code.
*
* @param int $step The number of indentation to remove
*
* @return $this
*
* @throws LogicException When trying to outdent too much so the indentation would become negative
*/
public function outdent($step = 1)
{
// can't outdent by more steps than the current indentation level
if ($this->indentation < $step) {
throw new LogicException('Unable to call outdent() as the indentation would become negative.');
}
$this->indentation -= $step;
return $this;
}
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->varNameSalt++));
}
}
class_alias('Twig_Compiler', 'Twig\Compiler', false);
class_exists('Twig_Node');

View File

@ -1,34 +0,0 @@
<?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.
*/
/**
* Interface implemented by compiler classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_CompilerInterface
{
/**
* Compiles a node.
*
* @return $this
*/
public function compile(Twig_NodeInterface $node);
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource();
}

View File

@ -1,39 +0,0 @@
<?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.
*/
use Psr\Container\ContainerInterface;
/**
* Lazily loads Twig runtime implementations from a PSR-11 container.
*
* Note that the runtime services MUST use their class names as identifiers.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class Twig_ContainerRuntimeLoader implements Twig_RuntimeLoaderInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function load($class)
{
if ($this->container->has($class)) {
return $this->container->get($class);
}
}
}
class_alias('Twig_ContainerRuntimeLoader', 'Twig\RuntimeLoader\ContainerRuntimeLoader', false);

File diff suppressed because it is too large Load Diff

View File

@ -1,363 +0,0 @@
<?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 base exception.
*
* This exception class and its children must only be used when
* an error occurs during the loading of a template, when a syntax error
* is detected in a template, or when rendering a template. Other
* errors must use regular PHP exception classes (like when the template
* cache directory is not writable for instance).
*
* To help debugging template issues, this class tracks the original template
* name and line where the error occurred.
*
* Whenever possible, you must set these information (original template name
* and line number) yourself by passing them to the constructor. If some or all
* these information are not available from where you throw the exception, then
* this class will guess them automatically (when the line number is set to -1
* and/or the name is set to null). As this is a costly operation, this
* can be disabled by passing false for both the name and the line number
* when creating a new instance of this class.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error extends Exception
{
protected $lineno;
// to be renamed to name in 2.0
protected $filename;
protected $rawMessage;
protected $previous;
private $sourcePath;
private $sourceCode;
/**
* Constructor.
*
* Set both the line number and the name to false to
* disable automatic guessing of the original template name
* and line number.
*
* Set the line number to -1 to enable its automatic guessing.
* Set the name to null to enable its automatic guessing.
*
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param int $lineno The template line where the error occurred
* @param Twig_Source|string|null $source The source context where the error occurred
* @param Exception $previous The previous exception
*/
public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
{
if (null === $source) {
$name = null;
} elseif (!$source instanceof Twig_Source) {
// for compat with the Twig C ext., passing the template name as string is accepted
$name = $source;
} else {
$name = $source->getName();
$this->sourceCode = $source->getCode();
$this->sourcePath = $source->getPath();
}
if (PHP_VERSION_ID < 50300) {
$this->previous = $previous;
parent::__construct('');
} else {
parent::__construct('', 0, $previous);
}
$this->lineno = $lineno;
$this->filename = $name;
if (-1 === $lineno || null === $name || null === $this->sourcePath) {
$this->guessTemplateInfo();
}
$this->rawMessage = $message;
$this->updateRepr();
}
/**
* Gets the raw message.
*
* @return string The raw message
*/
public function getRawMessage()
{
return $this->rawMessage;
}
/**
* Gets the logical name where the error occurred.
*
* @return string The name
*
* @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead.
*/
public function getTemplateFile()
{
@trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->filename;
}
/**
* Sets the logical name where the error occurred.
*
* @param string $name The name
*
* @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead.
*/
public function setTemplateFile($name)
{
@trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
$this->filename = $name;
$this->updateRepr();
}
/**
* Gets the logical name where the error occurred.
*
* @return string The name
*
* @deprecated since 1.29 (to be removed in 2.0). Use getSourceContext() instead.
*/
public function getTemplateName()
{
@trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->filename;
}
/**
* Sets the logical name where the error occurred.
*
* @param string $name The name
*
* @deprecated since 1.29 (to be removed in 2.0). Use setSourceContext() instead.
*/
public function setTemplateName($name)
{
@trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
$this->filename = $name;
$this->sourceCode = $this->sourcePath = null;
$this->updateRepr();
}
/**
* Gets the template line where the error occurred.
*
* @return int The template line
*/
public function getTemplateLine()
{
return $this->lineno;
}
/**
* Sets the template line where the error occurred.
*
* @param int $lineno The template line
*/
public function setTemplateLine($lineno)
{
$this->lineno = $lineno;
$this->updateRepr();
}
/**
* Gets the source context of the Twig template where the error occurred.
*
* @return Twig_Source|null
*/
public function getSourceContext()
{
return $this->filename ? new Twig_Source($this->sourceCode, $this->filename, $this->sourcePath) : null;
}
/**
* Sets the source context of the Twig template where the error occurred.
*/
public function setSourceContext(Twig_Source $source = null)
{
if (null === $source) {
$this->sourceCode = $this->filename = $this->sourcePath = null;
} else {
$this->sourceCode = $source->getCode();
$this->filename = $source->getName();
$this->sourcePath = $source->getPath();
}
$this->updateRepr();
}
public function guess()
{
$this->guessTemplateInfo();
$this->updateRepr();
}
/**
* For PHP < 5.3.0, provides access to the getPrevious() method.
*
* @param string $method The method name
* @param array $arguments The parameters to be passed to the method
*
* @return Exception The previous exception or null
*
* @throws BadMethodCallException
*/
public function __call($method, $arguments)
{
if ('getprevious' == strtolower($method)) {
return $this->previous;
}
throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
}
public function appendMessage($rawMessage)
{
$this->rawMessage .= $rawMessage;
$this->updateRepr();
}
/**
* @internal
*/
protected function updateRepr()
{
$this->message = $this->rawMessage;
if ($this->sourcePath && $this->lineno > 0) {
$this->file = $this->sourcePath;
$this->line = $this->lineno;
return;
}
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
$questionMark = false;
if ('?' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$questionMark = true;
}
if ($this->filename) {
if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
$name = sprintf('"%s"', $this->filename);
} else {
$name = json_encode($this->filename);
}
$this->message .= sprintf(' in %s', $name);
}
if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d', $this->lineno);
}
if ($dot) {
$this->message .= '.';
}
if ($questionMark) {
$this->message .= '?';
}
}
/**
* @internal
*/
protected function guessTemplateInfo()
{
$template = null;
$templateClass = null;
if (PHP_VERSION_ID >= 50306) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
} else {
$backtrace = debug_backtrace();
}
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
$currentClass = get_class($trace['object']);
$isEmbedContainer = 0 === strpos($templateClass, $currentClass);
if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
$template = $trace['object'];
$templateClass = get_class($trace['object']);
}
}
}
// update template name
if (null !== $template && null === $this->filename) {
$this->filename = $template->getTemplateName();
}
// update template path if any
if (null !== $template && null === $this->sourcePath) {
$src = $template->getSourceContext();
$this->sourceCode = $src->getCode();
$this->sourcePath = $src->getPath();
}
if (null === $template || $this->lineno > -1) {
return;
}
$r = new ReflectionObject($template);
$file = $r->getFileName();
$exceptions = array($e = $this);
while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
$exceptions[] = $e;
}
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;
}
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
if ($codeLine <= $trace['line']) {
// update template line
$this->lineno = $templateLine;
return;
}
}
}
}
}
}
class_alias('Twig_Error', 'Twig\Error\Error', false);
class_exists('Twig_Source');

View File

@ -1,40 +0,0 @@
<?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.
*/
/**
* Exception thrown when an error occurs during template loading.
*
* Automatic template information guessing is always turned off as
* if a template cannot be loaded, there is nothing to guess.
* However, when a template is loaded from another one, then, we need
* to find the current context and this is automatically done by
* Twig_Template::displayWithErrorHandling().
*
* This strategy makes Twig_Environment::resolveTemplate() much faster.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Loader extends Twig_Error
{
public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
{
if (PHP_VERSION_ID < 50300) {
$this->previous = $previous;
Exception::__construct('');
} else {
Exception::__construct('', 0, $previous);
}
$this->appendMessage($message);
$this->setTemplateLine(false);
}
}
class_alias('Twig_Error_Loader', 'Twig\Error\LoaderError', false);

View File

@ -1,22 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when an error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Runtime extends Twig_Error
{
}
class_alias('Twig_Error_Runtime', 'Twig\Error\RuntimeError', false);

View File

@ -1,55 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when a syntax error occurs during lexing or parsing of a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Syntax extends Twig_Error
{
/**
* Tweaks the error message to include suggestions.
*
* @param string $name The original name of the item that does not exist
* @param array $items An array of possible items
*/
public function addSuggestions($name, array $items)
{
if (!$alternatives = self::computeAlternatives($name, $items)) {
return;
}
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', $alternatives)));
}
/**
* @internal
*
* To be merged with the addSuggestions() method in 2.0.
*/
public static function computeAlternatives($name, $items)
{
$alternatives = array();
foreach ($items as $item) {
$lev = levenshtein($name, $item);
if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
$alternatives[$item] = $lev;
}
}
asort($alternatives);
return array_keys($alternatives);
}
}
class_alias('Twig_Error_Syntax', 'Twig\Error\SyntaxError', false);

View File

@ -1,31 +0,0 @@
<?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.
*/
/**
* Adds an exists() method for loaders.
*
* @author Florin Patan <florinpatan@gmail.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_ExistsLoaderInterface
{
/**
* Check if we have the source code of a template, given its name.
*
* @param string $name The name of the template to check if we can load
*
* @return bool If the template source code is handled by this loader or not
*/
public function exists($name);
}
class_alias('Twig_ExistsLoaderInterface', 'Twig\Loader\ExistsLoaderInterface', false);

View File

@ -1,744 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Parses expressions.
*
* This parser implements a "Precedence climbing" algorithm.
*
* @see https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
* @see https://en.wikipedia.org/wiki/Operator-precedence_parser
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
class Twig_ExpressionParser
{
const OPERATOR_LEFT = 1;
const OPERATOR_RIGHT = 2;
protected $parser;
protected $unaryOperators;
protected $binaryOperators;
private $env;
public function __construct(Twig_Parser $parser, $env = null)
{
$this->parser = $parser;
if ($env instanceof Twig_Environment) {
$this->env = $env;
$this->unaryOperators = $env->getUnaryOperators();
$this->binaryOperators = $env->getBinaryOperators();
} else {
@trigger_error('Passing the operators as constructor arguments to '.__METHOD__.' is deprecated since version 1.27. Pass the environment instead.', E_USER_DEPRECATED);
$this->env = $parser->getEnvironment();
$this->unaryOperators = func_get_arg(1);
$this->binaryOperators = func_get_arg(2);
}
}
public function parseExpression($precedence = 0)
{
$expr = $this->getPrimary();
$token = $this->parser->getCurrentToken();
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
$op = $this->binaryOperators[$token->getValue()];
$this->parser->getStream()->next();
if ('is not' === $token->getValue()) {
$expr = $this->parseNotTestExpression($expr);
} elseif ('is' === $token->getValue()) {
$expr = $this->parseTestExpression($expr);
} elseif (isset($op['callable'])) {
$expr = call_user_func($op['callable'], $this->parser, $expr);
} else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
$class = $op['class'];
$expr = new $class($expr, $expr1, $token->getLine());
}
$token = $this->parser->getCurrentToken();
}
if (0 === $precedence) {
return $this->parseConditionalExpression($expr);
}
return $expr;
}
protected function getPrimary()
{
$token = $this->parser->getCurrentToken();
if ($this->isUnary($token)) {
$operator = $this->unaryOperators[$token->getValue()];
$this->parser->getStream()->next();
$expr = $this->parseExpression($operator['precedence']);
$class = $operator['class'];
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$this->parser->getStream()->next();
$expr = $this->parseExpression();
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
return $this->parsePostfixExpression($expr);
}
return $this->parsePrimaryExpression();
}
protected function parseConditionalExpression($expr)
{
while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$expr2 = $this->parseExpression();
if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$expr3 = $this->parseExpression();
} else {
$expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
}
} else {
$expr2 = $expr;
$expr3 = $this->parseExpression();
}
$expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
}
return $expr;
}
protected function isUnary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
}
protected function isBinary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
}
public function parsePrimaryExpression()
{
$token = $this->parser->getCurrentToken();
switch ($token->getType()) {
case Twig_Token::NAME_TYPE:
$this->parser->getStream()->next();
switch ($token->getValue()) {
case 'true':
case 'TRUE':
$node = new Twig_Node_Expression_Constant(true, $token->getLine());
break;
case 'false':
case 'FALSE':
$node = new Twig_Node_Expression_Constant(false, $token->getLine());
break;
case 'none':
case 'NONE':
case 'null':
case 'NULL':
$node = new Twig_Node_Expression_Constant(null, $token->getLine());
break;
default:
if ('(' === $this->parser->getCurrentToken()->getValue()) {
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
} else {
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
}
}
break;
case Twig_Token::NUMBER_TYPE:
$this->parser->getStream()->next();
$node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
break;
case Twig_Token::STRING_TYPE:
case Twig_Token::INTERPOLATION_START_TYPE:
$node = $this->parseStringExpression();
break;
case Twig_Token::OPERATOR_TYPE:
if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
// in this context, string operators are variable names
$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->getStream()->getSourceContext());
}
$this->parser->getStream()->next();
$expr = $this->parsePrimaryExpression();
$node = new $class($expr, $token->getLine());
break;
}
// no break
default:
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
$node = $this->parseArrayExpression();
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
$node = $this->parseHashExpression();
} elseif ($token->test(Twig_Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
throw new Twig_Error_Syntax(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
} else {
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
}
return $this->parsePostfixExpression($node);
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = array();
// a string cannot be followed by another string in a single expression
$nextCanBeString = true;
while (true) {
if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
$nextCanBeString = false;
} elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
$nodes[] = $this->parseExpression();
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
$nextCanBeString = true;
} else {
break;
}
}
$expr = array_shift($nodes);
foreach ($nodes as $node) {
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getTemplateLine());
}
return $expr;
}
public function parseArrayExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
break;
}
}
$first = false;
$node->addElement($this->parseExpression());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
return $node;
}
public function parseHashExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
break;
}
}
$first = false;
// a hash key can be:
//
// * a number -- 12
// * a string -- 'a'
// * a name, which is equivalent to a string -- a
// * an expression, which must be enclosed in parentheses -- (1 + 2)
if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$key = $this->parseExpression();
} else {
$current = $stream->getCurrent();
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
return $node;
}
public function parsePostfixExpression($node)
{
while (true) {
$token = $this->parser->getCurrentToken();
if (Twig_Token::PUNCTUATION_TYPE == $token->getType()) {
if ('.' == $token->getValue() || '[' == $token->getValue()) {
$node = $this->parseSubscriptExpression($node);
} elseif ('|' == $token->getValue()) {
$node = $this->parseFilterExpression($node);
} else {
break;
}
} else {
break;
}
}
return $node;
}
public function getFunctionNode($name, $line)
{
switch ($name) {
case 'parent':
$this->parseArguments();
if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
case 'block':
$args = $this->parseArguments();
if (count($args) < 1) {
throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
}
return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line);
case 'attribute':
$args = $this->parseArguments();
if (count($args) < 2) {
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
}
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);
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
$node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
$node->setAttribute('safe', true);
return $node;
}
$args = $this->parseArguments(true);
$class = $this->getFunctionNodeClass($name, $line);
return new $class($name, $args, $line);
}
}
public function parseSubscriptExpression($node)
{
$stream = $this->parser->getStream();
$token = $stream->next();
$lineno = $token->getLine();
$arguments = new Twig_Node_Expression_Array(array(), $lineno);
$type = Twig_Template::ANY_CALL;
if ('.' == $token->getValue()) {
$token = $stream->next();
if (
Twig_Token::NAME_TYPE == $token->getType()
||
Twig_Token::NUMBER_TYPE == $token->getType()
||
(Twig_Token::OPERATOR_TYPE == $token->getType() && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$type = Twig_Template::METHOD_CALL;
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
}
} else {
throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext());
}
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof Twig_Node_Expression_Constant) {
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
}
$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(), $stream->getSourceContext());
}
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
}
} else {
$type = Twig_Template::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$arg = new Twig_Node_Expression_Constant(0, $token->getLine());
} else {
$arg = $this->parseExpression();
}
if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
}
if ($slice) {
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
$length = new Twig_Node_Expression_Constant(null, $token->getLine());
} else {
$length = $this->parseExpression();
}
$class = $this->getFilterNodeClass('slice', $token->getLine());
$arguments = new Twig_Node(array($arg, $length));
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
return $filter;
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
}
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
}
public function parseFilterExpression($node)
{
$this->parser->getStream()->next();
return $this->parseFilterExpressionRaw($node);
}
public function parseFilterExpressionRaw($node, $tag = null)
{
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
$name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = new Twig_Node();
} else {
$arguments = $this->parseArguments(true);
}
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
break;
}
$this->parser->getStream()->next();
}
return $node;
}
/**
* Parses arguments.
*
* @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)
{
$args = array();
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
if (!empty($args)) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
}
if ($definition) {
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
$value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression();
}
$name = null;
if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
if (!$value instanceof Twig_Node_Expression_Name) {
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext());
}
$name = $value->getAttribute('name');
if ($definition) {
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $stream->getSourceContext());
}
} else {
$value = $this->parseExpression();
}
}
if ($definition) {
if (null === $name) {
$name = $value->getAttribute('name');
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
}
$args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
}
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
return new Twig_Node($args);
}
public function parseAssignmentExpression()
{
$stream = $this->parser->getStream();
$targets = array();
while (true) {
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
$value = $token->getValue();
if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
}
$targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
}
return new Twig_Node($targets);
}
public function parseMultitargetExpression()
{
$targets = array();
while (true) {
$targets[] = $this->parseExpression();
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
}
return new Twig_Node($targets);
}
private function parseNotTestExpression(Twig_NodeInterface $node)
{
return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
}
private function parseTestExpression(Twig_NodeInterface $node)
{
$stream = $this->parser->getStream();
list($name, $test) = $this->getTest($node->getTemplateLine());
$class = $this->getTestNodeClass($test);
$arguments = null;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = $this->parser->getExpressionParser()->parseArguments(true);
}
return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
}
private function getTest($line)
{
$stream = $this->parser->getStream();
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
if ($test = $this->env->getTest($name)) {
return array($name, $test);
}
if ($stream->test(Twig_Token::NAME_TYPE)) {
// try 2-words tests
$name = $name.' '.$this->parser->getCurrentToken()->getValue();
if ($test = $this->env->getTest($name)) {
$stream->next();
return array($name, $test);
}
}
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getTests()));
throw $e;
}
private function getTestNodeClass($test)
{
if ($test instanceof Twig_SimpleTest && $test->isDeprecated()) {
$stream = $this->parser->getStream();
$message = sprintf('Twig Test "%s" is deprecated', $test->getName());
if (!is_bool($test->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $test->getDeprecatedVersion());
}
if ($test->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $test->getAlternative());
}
$src = $stream->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine());
@trigger_error($message, E_USER_DEPRECATED);
}
if ($test instanceof Twig_SimpleTest) {
return $test->getNodeClass();
}
return $test instanceof Twig_Test_Node ? $test->getClass() : 'Twig_Node_Expression_Test';
}
protected function getFunctionNodeClass($name, $line)
{
if (false === $function = $this->env->getFunction($name)) {
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFunctions()));
throw $e;
}
if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if (!is_bool($function->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $function->getDeprecatedVersion());
}
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
if ($function instanceof Twig_SimpleFunction) {
return $function->getNodeClass();
}
return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
}
protected function getFilterNodeClass($name, $line)
{
if (false === $filter = $this->env->getFilter($name)) {
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFilters()));
throw $e;
}
if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if (!is_bool($filter->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
}
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
if ($filter instanceof Twig_SimpleFilter) {
return $filter->getNodeClass();
}
return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
}
// 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
|| $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos
)) {
return false;
}
foreach ($node as $n) {
if (!$this->checkConstantExpression($n)) {
return false;
}
}
return true;
}
}
class_alias('Twig_ExpressionParser', 'Twig\ExpressionParser', false);

View File

@ -1,69 +0,0 @@
<?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.
*/
abstract class Twig_Extension implements Twig_ExtensionInterface
{
/**
* @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead
*/
public function initRuntime(Twig_Environment $environment)
{
}
public function getTokenParsers()
{
return array();
}
public function getNodeVisitors()
{
return array();
}
public function getFilters()
{
return array();
}
public function getTests()
{
return array();
}
public function getFunctions()
{
return array();
}
public function getOperators()
{
return array();
}
/**
* @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
*/
public function getGlobals()
{
return array();
}
/**
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
*/
public function getName()
{
return get_class($this);
}
}
class_alias('Twig_Extension', 'Twig\Extension\AbstractExtension', false);
class_exists('Twig_Environment');

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +0,0 @@
<?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.
*/
/**
* @final
*/
class Twig_Extension_Debug extends Twig_Extension
{
public function getFunctions()
{
// dump is safe if var_dump is overridden by xdebug
$isDumpOutputHtmlSafe = extension_loaded('xdebug')
// false means that it was not set (and the default is on) or it explicitly enabled
&& (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
// false means that it was not set (and the default is on) or it explicitly enabled
// xdebug.overload_var_dump produces HTML only when html_errors is also enabled
&& (false === ini_get('html_errors') || ini_get('html_errors'))
|| 'cli' === PHP_SAPI
;
return array(
new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
);
}
public function getName()
{
return 'debug';
}
}
function twig_var_dump(Twig_Environment $env, $context)
{
if (!$env->isDebug()) {
return;
}
ob_start();
$count = func_num_args();
if (2 === $count) {
$vars = array();
foreach ($context as $key => $value) {
if (!$value instanceof Twig_Template) {
$vars[$key] = $value;
}
}
var_dump($vars);
} else {
for ($i = 2; $i < $count; ++$i) {
var_dump(func_get_arg($i));
}
}
return ob_get_clean();
}
class_alias('Twig_Extension_Debug', 'Twig\Extension\DebugExtension', false);

View File

@ -1,112 +0,0 @@
<?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.
*/
/**
* @final
*/
class Twig_Extension_Escaper extends Twig_Extension
{
protected $defaultStrategy;
/**
* @param string|false|callable $defaultStrategy An escaping strategy
*
* @see setDefaultStrategy()
*/
public function __construct($defaultStrategy = 'html')
{
$this->setDefaultStrategy($defaultStrategy);
}
public function getTokenParsers()
{
return array(new Twig_TokenParser_AutoEscape());
}
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Escaper());
}
public function getFilters()
{
return array(
new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
);
}
/**
* Sets the default strategy to use when not defined by the user.
*
* The strategy can be a valid PHP callback that takes the template
* name as an argument and returns the strategy to use.
*
* @param string|false|callable $defaultStrategy An escaping strategy
*/
public function setDefaultStrategy($defaultStrategy)
{
// for BC
if (true === $defaultStrategy) {
@trigger_error('Using "true" as the default strategy is deprecated since version 1.21. Use "html" instead.', E_USER_DEPRECATED);
$defaultStrategy = 'html';
}
if ('filename' === $defaultStrategy) {
@trigger_error('Using "filename" as the default strategy is deprecated since version 1.27. Use "name" instead.', E_USER_DEPRECATED);
$defaultStrategy = 'name';
}
if ('name' === $defaultStrategy) {
$defaultStrategy = array('Twig_FileExtensionEscapingStrategy', 'guess');
}
$this->defaultStrategy = $defaultStrategy;
}
/**
* Gets the default strategy to use when not defined by the user.
*
* @param string $name The template name
*
* @return string|false The default strategy to use for the template
*/
public function getDefaultStrategy($name)
{
// disable string callables to avoid calling a function named html or js,
// or any other upcoming escaping strategy
if (!is_string($this->defaultStrategy) && false !== $this->defaultStrategy) {
return call_user_func($this->defaultStrategy, $name);
}
return $this->defaultStrategy;
}
public function getName()
{
return 'escaper';
}
}
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*
* @return string
*/
function twig_raw_filter($string)
{
return $string;
}
class_alias('Twig_Extension_Escaper', 'Twig\Extension\EscaperExtension', false);

View File

@ -1,24 +0,0 @@
<?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.
*/
/**
* Enables usage of the deprecated Twig_Extension::getGlobals() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated getGlobals() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_Extension_GlobalsInterface
{
}
class_alias('Twig_Extension_GlobalsInterface', 'Twig\Extension\GlobalsInterface', false);

View File

@ -1,24 +0,0 @@
<?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.
*/
/**
* Enables usage of the deprecated Twig_Extension::initRuntime() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated initRuntime() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_Extension_InitRuntimeInterface
{
}
class_alias('Twig_Extension_InitRuntimeInterface', 'Twig\Extension\InitRuntimeInterface', false);

View File

@ -1,35 +0,0 @@
<?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.
*/
/**
* @final
*/
class Twig_Extension_Optimizer extends Twig_Extension
{
protected $optimizers;
public function __construct($optimizers = -1)
{
$this->optimizers = $optimizers;
}
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
}
public function getName()
{
return 'optimizer';
}
}
class_alias('Twig_Extension_Optimizer', 'Twig\Extension\OptimizerExtension', false);

View File

@ -1,49 +0,0 @@
<?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_Extension_Profiler extends Twig_Extension
{
private $actives = array();
public function __construct(Twig_Profiler_Profile $profile)
{
$this->actives[] = $profile;
}
public function enter(Twig_Profiler_Profile $profile)
{
$this->actives[0]->addProfile($profile);
array_unshift($this->actives, $profile);
}
public function leave(Twig_Profiler_Profile $profile)
{
$profile->leave();
array_shift($this->actives);
if (1 === count($this->actives)) {
$this->actives[0]->leave();
}
}
public function getNodeVisitors()
{
return array(new Twig_Profiler_NodeVisitor_Profiler(get_class($this)));
}
public function getName()
{
return 'profiler';
}
}
class_alias('Twig_Extension_Profiler', 'Twig\Extension\ProfilerExtension', false);
class_exists('Twig_Profiler_Profile');

View File

@ -1,103 +0,0 @@
<?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.
*/
/**
* @final
*/
class Twig_Extension_Sandbox extends Twig_Extension
{
protected $sandboxedGlobally;
protected $sandboxed;
protected $policy;
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
{
$this->policy = $policy;
$this->sandboxedGlobally = $sandboxed;
}
public function getTokenParsers()
{
return array(new Twig_TokenParser_Sandbox());
}
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Sandbox());
}
public function enableSandbox()
{
$this->sandboxed = true;
}
public function disableSandbox()
{
$this->sandboxed = false;
}
public function isSandboxed()
{
return $this->sandboxedGlobally || $this->sandboxed;
}
public function isSandboxedGlobally()
{
return $this->sandboxedGlobally;
}
public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
{
$this->policy = $policy;
}
public function getSecurityPolicy()
{
return $this->policy;
}
public function checkSecurity($tags, $filters, $functions)
{
if ($this->isSandboxed()) {
$this->policy->checkSecurity($tags, $filters, $functions);
}
}
public function checkMethodAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkMethodAllowed($obj, $method);
}
}
public function checkPropertyAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkPropertyAllowed($obj, $method);
}
}
public function ensureToStringAllowed($obj)
{
if ($this->isSandboxed() && is_object($obj)) {
$this->policy->checkMethodAllowed($obj, '__toString');
}
return $obj;
}
public function getName()
{
return 'sandbox';
}
}
class_alias('Twig_Extension_Sandbox', 'Twig\Extension\SandboxExtension', false);

View File

@ -1,112 +0,0 @@
<?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.
*/
/**
* Internal class.
*
* This class is used by Twig_Environment as a staging area and must not be used directly.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
class Twig_Extension_Staging extends Twig_Extension
{
protected $functions = array();
protected $filters = array();
protected $visitors = array();
protected $tokenParsers = array();
protected $globals = array();
protected $tests = array();
public function addFunction($name, $function)
{
if (isset($this->functions[$name])) {
@trigger_error(sprintf('Overriding function "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->functions[$name] = $function;
}
public function getFunctions()
{
return $this->functions;
}
public function addFilter($name, $filter)
{
if (isset($this->filters[$name])) {
@trigger_error(sprintf('Overriding filter "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->filters[$name] = $filter;
}
public function getFilters()
{
return $this->filters;
}
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
{
$this->visitors[] = $visitor;
}
public function getNodeVisitors()
{
return $this->visitors;
}
public function addTokenParser(Twig_TokenParserInterface $parser)
{
if (isset($this->tokenParsers[$parser->getTag()])) {
@trigger_error(sprintf('Overriding tag "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED);
}
$this->tokenParsers[$parser->getTag()] = $parser;
}
public function getTokenParsers()
{
return $this->tokenParsers;
}
public function addGlobal($name, $value)
{
$this->globals[$name] = $value;
}
public function getGlobals()
{
return $this->globals;
}
public function addTest($name, $test)
{
if (isset($this->tests[$name])) {
@trigger_error(sprintf('Overriding test "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->tests[$name] = $test;
}
public function getTests()
{
return $this->tests;
}
public function getName()
{
return 'staging';
}
}
class_alias('Twig_Extension_Staging', 'Twig\Extension\StagingExtension', false);

View File

@ -1,47 +0,0 @@
<?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.
*/
/**
* @final
*/
class Twig_Extension_StringLoader extends Twig_Extension
{
public function getFunctions()
{
return array(
new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
);
}
public function getName()
{
return 'string_loader';
}
}
/**
* Loads a template from a string.
*
* <pre>
* {{ include(template_from_string("Hello {{ name }}")) }}
* </pre>
*
* @param Twig_Environment $env A Twig_Environment instance
* @param string $template A template as a string or object implementing __toString()
*
* @return Twig_Template
*/
function twig_template_from_string(Twig_Environment $env, $template)
{
return $env->createTemplate((string) $template);
}
class_alias('Twig_Extension_StringLoader', 'Twig\Extension\StringLoaderExtension', false);

View File

@ -1,90 +0,0 @@
<?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.
*/
/**
* Interface implemented by extension classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_ExtensionInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions for instance.
*
* @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead
*/
public function initRuntime(Twig_Environment $environment);
/**
* Returns the token parser instances to add to the existing list.
*
* @return Twig_TokenParserInterface[]
*/
public function getTokenParsers();
/**
* Returns the node visitor instances to add to the existing list.
*
* @return Twig_NodeVisitorInterface[]
*/
public function getNodeVisitors();
/**
* Returns a list of filters to add to the existing list.
*
* @return Twig_SimpleFilter[]
*/
public function getFilters();
/**
* Returns a list of tests to add to the existing list.
*
* @return Twig_SimpleTest[]
*/
public function getTests();
/**
* Returns a list of functions to add to the existing list.
*
* @return Twig_SimpleFunction[]
*/
public function getFunctions();
/**
* Returns a list of operators to add to the existing list.
*
* @return array<array> First array of unary operators, second array of binary operators
*/
public function getOperators();
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*
* @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
*/
public function getGlobals();
/**
* Returns the name of the extension.
*
* @return string The extension name
*
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
*/
public function getName();
}
class_alias('Twig_ExtensionInterface', 'Twig\Extension\ExtensionInterface', false);
class_exists('Twig_Environment');

View File

@ -1,39 +0,0 @@
<?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.
*/
/**
* Lazy loads the runtime implementations for a Twig element.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class Twig_FactoryRuntimeLoader implements Twig_RuntimeLoaderInterface
{
private $map;
/**
* @param array $map An array where keys are class names and values factory callables
*/
public function __construct($map = array())
{
$this->map = $map;
}
public function load($class)
{
if (isset($this->map[$class])) {
$runtimeFactory = $this->map[$class];
return $runtimeFactory();
}
}
}
class_alias('Twig_FactoryRuntimeLoader', 'Twig\RuntimeLoader\FactoryRuntimeLoader', false);

View File

@ -1,60 +0,0 @@
<?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.
*/
/**
* Default autoescaping strategy based on file names.
*
* This strategy sets the HTML as the default autoescaping strategy,
* but changes it based on the template name.
*
* Note that there is no runtime performance impact as the
* default autoescaping strategy is set at compilation time.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_FileExtensionEscapingStrategy
{
/**
* Guesses the best autoescaping strategy based on the file name.
*
* @param string $name The template name
*
* @return string|false The escaping strategy name to use or false to disable
*/
public static function guess($name)
{
if (in_array(substr($name, -1), array('/', '\\'))) {
return 'html'; // return html for directories
}
if ('.twig' === substr($name, -5)) {
$name = substr($name, 0, -5);
}
$extension = pathinfo($name, PATHINFO_EXTENSION);
switch ($extension) {
case 'js':
return 'js';
case 'css':
return 'css';
case 'txt':
return false;
default:
return 'html';
}
}
}
class_alias('Twig_FileExtensionEscapingStrategy', 'Twig\FileExtensionEscapingStrategy', false);

View File

@ -1,84 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Filter class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/**
* Represents a template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
{
protected $options;
protected $arguments = array();
public function __construct(array $options = array())
{
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'pre_escape' => null,
'preserves_safety' => null,
'callable' => null,
), $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $filterArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return call_user_func($this->options['is_safe_callback'], $filterArgs);
}
}
public function getPreservesSafety()
{
return $this->options['preserves_safety'];
}
public function getPreEscape()
{
return $this->options['pre_escape'];
}
public function getCallable()
{
return $this->options['callable'];
}
}

View File

@ -1,40 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Filter_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/**
* Represents a function template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Function extends Twig_Filter
{
protected $function;
public function __construct($function, array $options = array())
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}

View File

@ -1,42 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Filter_Method class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/**
* Represents a method template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Method extends Twig_Filter
{
protected $extension;
protected $method;
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
{
$options['callable'] = array($extension, $method);
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method);
}
}

View File

@ -1,42 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Filter_Node class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED);
/**
* Represents a template filter as a node.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Node extends Twig_Filter
{
protected $class;
public function __construct($class, array $options = array())
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}

View File

@ -1,24 +0,0 @@
<?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.
*/
/**
* Represents a callable template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterCallableInterface
{
public function getCallable();
}

View File

@ -1,43 +0,0 @@
<?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.
*/
/**
* Represents a template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterInterface
{
/**
* Compiles a filter.
*
* @return string The PHP code for the filter
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Twig_Node $filterArgs);
public function getPreservesSafety();
public function getPreEscape();
public function setArguments($arguments);
public function getArguments();
}

View File

@ -1,74 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/**
* Represents a template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
{
protected $options;
protected $arguments = array();
public function __construct(array $options = array())
{
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'callable' => null,
), $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $functionArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return call_user_func($this->options['is_safe_callback'], $functionArgs);
}
return array();
}
public function getCallable()
{
return $this->options['callable'];
}
}

View File

@ -1,41 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Function_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/**
* Represents a function template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Function extends Twig_Function
{
protected $function;
public function __construct($function, array $options = array())
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}

View File

@ -1,43 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Function_Method class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/**
* Represents a method template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Method extends Twig_Function
{
protected $extension;
protected $method;
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
{
$options['callable'] = array($extension, $method);
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method);
}
}

View File

@ -1,42 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Function_Node class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED);
/**
* Represents a template function as a node.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Node extends Twig_Function
{
protected $class;
public function __construct($class, array $options = array())
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}

View File

@ -1,24 +0,0 @@
<?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.
*/
/**
* Represents a callable template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionCallableInterface
{
public function getCallable();
}

View File

@ -1,40 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionInterface
{
/**
* Compiles a function.
*
* @return string The PHP code for the function
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Twig_Node $filterArgs);
public function setArguments($arguments);
public function getArguments();
}

View File

@ -1,427 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Lexes a template string.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Lexer implements Twig_LexerInterface
{
protected $tokens;
protected $code;
protected $cursor;
protected $lineno;
protected $end;
protected $state;
protected $states;
protected $brackets;
protected $env;
// to be renamed to $name in 2.0 (where it is private)
protected $filename;
protected $options;
protected $regexes;
protected $position;
protected $positions;
protected $currentVarBlockLine;
private $source;
const STATE_DATA = 0;
const STATE_BLOCK = 1;
const STATE_VAR = 2;
const STATE_STRING = 3;
const STATE_INTERPOLATION = 4;
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const REGEX_DQ_STRING_DELIM = '/"/A';
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
const PUNCTUATION = '()[]{}?:.,|';
public function __construct(Twig_Environment $env, array $options = array())
{
$this->env = $env;
$this->options = array_merge(array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('{{', '}}'),
'whitespace_trim' => '-',
'interpolation' => array('#{', '}'),
), $options);
$this->regexes = array(
'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
'operator' => $this->getOperatorRegex(),
'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
);
}
public function tokenize($code, $name = null)
{
if (!$code instanceof Twig_Source) {
@trigger_error(sprintf('Passing a string as the $code argument of %s() is deprecated since version 1.27 and will be removed in 2.0. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED);
$this->source = new Twig_Source($code, $name);
} else {
$this->source = $code;
}
if (((int) ini_get('mbstring.func_overload')) & 2) {
@trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
}
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
} else {
$mbEncoding = null;
}
$this->code = str_replace(array("\r\n", "\r"), "\n", $this->source->getCode());
$this->filename = $this->source->getName();
$this->cursor = 0;
$this->lineno = 1;
$this->end = strlen($this->code);
$this->tokens = array();
$this->state = self::STATE_DATA;
$this->states = array();
$this->brackets = array();
$this->position = -1;
// find all token starts in one go
preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
$this->positions = $matches;
while ($this->cursor < $this->end) {
// dispatch to the lexing functions depending
// on the current state
switch ($this->state) {
case self::STATE_DATA:
$this->lexData();
break;
case self::STATE_BLOCK:
$this->lexBlock();
break;
case self::STATE_VAR:
$this->lexVar();
break;
case self::STATE_STRING:
$this->lexString();
break;
case self::STATE_INTERPOLATION:
$this->lexInterpolation();
break;
}
}
$this->pushToken(Twig_Token::EOF_TYPE);
if (!empty($this->brackets)) {
list($expect, $lineno) = array_pop($this->brackets);
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
if ($mbEncoding) {
mb_internal_encoding($mbEncoding);
}
return new Twig_TokenStream($this->tokens, $this->source);
}
protected function lexData()
{
// if no matches are left we return the rest of the template as simple text token
if ($this->position == count($this->positions[0]) - 1) {
$this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
$this->cursor = $this->end;
return;
}
// Find the first token after the current cursor
$position = $this->positions[0][++$this->position];
while ($position[1] < $this->cursor) {
if ($this->position == count($this->positions[0]) - 1) {
return;
}
$position = $this->positions[0][++$this->position];
}
// push the template text first
$text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
if (isset($this->positions[2][$this->position][0])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
$this->moveCursor($textContent.$position[0]);
switch ($this->positions[1][$this->position][0]) {
case $this->options['tag_comment'][0]:
$this->lexComment();
break;
case $this->options['tag_block'][0]:
// raw data?
if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lexRawData($match[1]);
// {% line \d+ %}
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lineno = (int) $match[1];
} else {
$this->pushToken(Twig_Token::BLOCK_START_TYPE);
$this->pushState(self::STATE_BLOCK);
$this->currentVarBlockLine = $this->lineno;
}
break;
case $this->options['tag_variable'][0]:
$this->pushToken(Twig_Token::VAR_START_TYPE);
$this->pushState(self::STATE_VAR);
$this->currentVarBlockLine = $this->lineno;
break;
}
}
protected function lexBlock()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::BLOCK_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexVar()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::VAR_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexExpression()
{
// whitespace
if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
if ($this->cursor >= $this->end) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
}
}
// operators
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
$this->moveCursor($match[0]);
}
// names
elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
$this->moveCursor($match[0]);
}
// numbers
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
$number = (float) $match[0]; // floats
if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
$number = (int) $match[0]; // integers lower than the maximum
}
$this->pushToken(Twig_Token::NUMBER_TYPE, $number);
$this->moveCursor($match[0]);
}
// punctuation
elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
// opening bracket
if (false !== strpos('([{', $this->code[$this->cursor])) {
$this->brackets[] = array($this->code[$this->cursor], $this->lineno);
}
// closing bracket
elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
if (empty($this->brackets)) {
throw new Twig_Error_Syntax(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
}
$this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
++$this->cursor;
}
// strings
elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
$this->moveCursor($match[0]);
}
// opening double quoted string
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array('"', $this->lineno);
$this->pushState(self::STATE_STRING);
$this->moveCursor($match[0]);
}
// unlexable
else {
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
}
protected function lexRawData($tag)
{
if ('raw' === $tag) {
@trigger_error(sprintf('Twig Tag "raw" is deprecated since version 1.21. Use "verbatim" instead in %s at line %d.', $this->filename, $this->lineno), E_USER_DEPRECATED);
}
if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->source);
}
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
$this->moveCursor($text.$match[0][0]);
if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
}
protected function lexComment()
{
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax('Unclosed comment.', $this->lineno, $this->source);
}
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
}
protected function lexString()
{
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
$this->moveCursor($match[0]);
$this->pushState(self::STATE_INTERPOLATION);
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
$this->moveCursor($match[0]);
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
list($expect, $lineno) = array_pop($this->brackets);
if ('"' != $this->code[$this->cursor]) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
$this->popState();
++$this->cursor;
} else {
// unlexable
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
}
protected function lexInterpolation()
{
$bracket = end($this->brackets);
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
array_pop($this->brackets);
$this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function pushToken($type, $value = '')
{
// do not push empty text tokens
if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
return;
}
$this->tokens[] = new Twig_Token($type, $value, $this->lineno);
}
protected function moveCursor($text)
{
$this->cursor += strlen($text);
$this->lineno += substr_count($text, "\n");
}
protected function getOperatorRegex()
{
$operators = array_merge(
array('='),
array_keys($this->env->getUnaryOperators()),
array_keys($this->env->getBinaryOperators())
);
$operators = array_combine($operators, array_map('strlen', $operators));
arsort($operators);
$regex = array();
foreach ($operators as $operator => $length) {
// an operator that ends with a character must be followed by
// a whitespace or a parenthesis
if (ctype_alpha($operator[$length - 1])) {
$r = preg_quote($operator, '/').'(?=[\s()])';
} else {
$r = preg_quote($operator, '/');
}
// an operator with a space can be any amount of whitespaces
$r = preg_replace('/\s+/', '\s+', $r);
$regex[] = $r;
}
return '/'.implode('|', $regex).'/A';
}
protected function pushState($state)
{
$this->states[] = $this->state;
$this->state = $state;
}
protected function popState()
{
if (0 === count($this->states)) {
throw new Exception('Cannot pop state without a previous state.');
}
$this->state = array_pop($this->states);
}
}
class_alias('Twig_Lexer', 'Twig\Lexer', false);

View File

@ -1,32 +0,0 @@
<?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.
*/
/**
* Interface implemented by lexer classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_LexerInterface
{
/**
* Tokenizes a source code.
*
* @param string|Twig_Source $code The source code
* @param string $name A unique identifier for the source code
*
* @return Twig_TokenStream
*
* @throws Twig_Error_Syntax When the code is syntactically wrong
*/
public function tokenize($code, $name = null);
}

View File

@ -1,97 +0,0 @@
<?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.
*/
/**
* Loads a template from an array.
*
* When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the
* 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.
*
* This loader should only be used for unit testing.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{
protected $templates = array();
/**
* @param array $templates An array of templates (keys are the names, and values are the source code)
*/
public function __construct(array $templates = array())
{
$this->templates = $templates;
}
/**
* Adds or overrides a template.
*
* @param string $name The template name
* @param string $template The template source
*/
public function setTemplate($name, $template)
{
$this->templates[(string) $name] = $template;
}
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return $this->templates[$name];
}
public function getSourceContext($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return new Twig_Source($this->templates[$name], $name);
}
public function exists($name)
{
return isset($this->templates[(string) $name]);
}
public function getCacheKey($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return $name.':'.$this->templates[$name];
}
public function isFresh($name, $time)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return true;
}
}
class_alias('Twig_Loader_Array', 'Twig\Loader\ArrayLoader', false);

View File

@ -1,151 +0,0 @@
<?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.
*/
/**
* Loads templates from other loaders.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{
private $hasSourceCache = array();
protected $loaders = array();
/**
* @param Twig_LoaderInterface[] $loaders
*/
public function __construct(array $loaders = array())
{
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
public function addLoader(Twig_LoaderInterface $loader)
{
$this->loaders[] = $loader;
$this->hasSourceCache = array();
}
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->getSource($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = $e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function getSourceContext($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
if ($loader instanceof Twig_SourceContextLoaderInterface) {
return $loader->getSourceContext($name);
}
return new Twig_Source($loader->getSource($name), $name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = $e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function exists($name)
{
$name = (string) $name;
if (isset($this->hasSourceCache[$name])) {
return $this->hasSourceCache[$name];
}
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface) {
if ($loader->exists($name)) {
return $this->hasSourceCache[$name] = true;
}
continue;
}
try {
if ($loader instanceof Twig_SourceContextLoaderInterface) {
$loader->getSourceContext($name);
} else {
$loader->getSource($name);
}
return $this->hasSourceCache[$name] = true;
} catch (Twig_Error_Loader $e) {
}
}
return $this->hasSourceCache[$name] = false;
}
public function getCacheKey($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->getCacheKey($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function isFresh($name, $time)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->isFresh($name, $time);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
}
class_alias('Twig_Loader_Chain', 'Twig\Loader\ChainLoader', false);

View File

@ -1,290 +0,0 @@
<?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.
*/
/**
* Loads template from the filesystem.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{
/** Identifier of the main namespace. */
const MAIN_NAMESPACE = '__main__';
protected $paths = array();
protected $cache = array();
protected $errorCache = array();
private $rootPath;
/**
* @param string|array $paths A path or an array of paths where to look for templates
* @param string|null $rootPath The root path common to all relative paths (null for getcwd())
*/
public function __construct($paths = array(), $rootPath = null)
{
$this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR;
if (false !== $realPath = realpath($rootPath)) {
$this->rootPath = $realPath.DIRECTORY_SEPARATOR;
}
if ($paths) {
$this->setPaths($paths);
}
}
/**
* Returns the paths to the templates.
*
* @param string $namespace A path namespace
*
* @return array The array of paths where to look for templates
*/
public function getPaths($namespace = self::MAIN_NAMESPACE)
{
return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
}
/**
* Returns the path namespaces.
*
* The main namespace is always defined.
*
* @return array The array of defined namespaces
*/
public function getNamespaces()
{
return array_keys($this->paths);
}
/**
* Sets the paths where templates are stored.
*
* @param string|array $paths A path or an array of paths where to look for templates
* @param string $namespace A path namespace
*/
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
{
if (!is_array($paths)) {
$paths = array($paths);
}
$this->paths[$namespace] = array();
foreach ($paths as $path) {
$this->addPath($path, $namespace);
}
}
/**
* Adds a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path namespace
*
* @throws Twig_Error_Loader
*/
public function addPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = $this->errorCache = array();
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
}
$this->paths[$namespace][] = rtrim($path, '/\\');
}
/**
* Prepends a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path namespace
*
* @throws Twig_Error_Loader
*/
public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = $this->errorCache = array();
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
}
$path = rtrim($path, '/\\');
if (!isset($this->paths[$namespace])) {
$this->paths[$namespace][] = $path;
} else {
array_unshift($this->paths[$namespace], $path);
}
}
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
return file_get_contents($this->findTemplate($name));
}
public function getSourceContext($name)
{
$path = $this->findTemplate($name);
return new Twig_Source(file_get_contents($path), $name, $path);
}
public function getCacheKey($name)
{
$path = $this->findTemplate($name);
$len = strlen($this->rootPath);
if (0 === strncmp($this->rootPath, $path, $len)) {
return substr($path, $len);
}
return $path;
}
public function exists($name)
{
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return true;
}
try {
return false !== $this->findTemplate($name, false);
} catch (Twig_Error_Loader $exception) {
@trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', get_class($this)), E_USER_DEPRECATED);
return false;
}
}
public function isFresh($name, $time)
{
return filemtime($this->findTemplate($name)) < $time;
}
protected function findTemplate($name)
{
$throw = func_num_args() > 1 ? func_get_arg(1) : true;
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return $this->cache[$name];
}
if (isset($this->errorCache[$name])) {
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
}
$this->validateName($name);
list($namespace, $shortname) = $this->parseName($name);
if (!isset($this->paths[$namespace])) {
$this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
}
foreach ($this->paths[$namespace] as $path) {
if (!$this->isAbsolutePath($path)) {
$path = $this->rootPath.'/'.$path;
}
if (is_file($path.'/'.$shortname)) {
if (false !== $realpath = realpath($path.'/'.$shortname)) {
return $this->cache[$name] = $realpath;
}
return $this->cache[$name] = $path.'/'.$shortname;
}
}
$this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
}
protected function parseName($name, $default = self::MAIN_NAMESPACE)
{
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$shortname = substr($name, $pos + 1);
return array($namespace, $shortname);
}
return array($default, $name);
}
protected function normalizeName($name)
{
return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name));
}
protected function validateName($name)
{
if (false !== strpos($name, "\0")) {
throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
}
$name = ltrim($name, '/');
$parts = explode('/', $name);
$level = 0;
foreach ($parts as $part) {
if ('..' === $part) {
--$level;
} elseif ('.' !== $part) {
++$level;
}
if ($level < 0) {
throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
}
}
}
private function isAbsolutePath($file)
{
return strspn($file, '/\\', 0, 1)
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === substr($file, 1, 1)
&& strspn($file, '/\\', 2, 1)
)
|| null !== parse_url($file, PHP_URL_SCHEME)
;
}
}
class_alias('Twig_Loader_Filesystem', 'Twig\Loader\FilesystemLoader', false);

View File

@ -1,58 +0,0 @@
<?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.
*/
@trigger_error('The Twig_Loader_String class is deprecated since version 1.18.1 and will be removed in 2.0. Use Twig_Loader_Array instead or Twig_Environment::createTemplate().', E_USER_DEPRECATED);
/**
* Loads a template from a string.
*
* This loader should NEVER be used. It only exists for Twig internal purposes.
*
* When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the
* 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)
*
* @internal
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
return $name;
}
public function getSourceContext($name)
{
return new Twig_Source($name, $name);
}
public function exists($name)
{
return true;
}
public function getCacheKey($name)
{
return $name;
}
public function isFresh($name, $time)
{
return true;
}
}

View File

@ -1,57 +0,0 @@
<?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.
*/
/**
* Interface all loaders must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_LoaderInterface
{
/**
* Gets the source code of a template, given its name.
*
* @param string $name The name of the template to load
*
* @return string The template source code
*
* @throws Twig_Error_Loader When $name is not found
*
* @deprecated since 1.27 (to be removed in 2.0), implement Twig_SourceContextLoaderInterface
*/
public function getSource($name);
/**
* Gets the cache key to use for the cache for a given template name.
*
* @param string $name The name of the template to load
*
* @return string The cache key
*
* @throws Twig_Error_Loader When $name is not found
*/
public function getCacheKey($name);
/**
* Returns true if the template is still fresh.
*
* @param string $name The template name
* @param int $time Timestamp of the last modification time of the
* cached template
*
* @return bool true if the template is fresh, false otherwise
*
* @throws Twig_Error_Loader When $name is not found
*/
public function isFresh($name, $time);
}
class_alias('Twig_LoaderInterface', 'Twig\Loader\LoaderInterface', false);

View File

@ -1,39 +0,0 @@
<?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.
*/
/**
* Marks a content as safe.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Markup implements Countable
{
protected $content;
protected $charset;
public function __construct($content, $charset)
{
$this->content = (string) $content;
$this->charset = $charset;
}
public function __toString()
{
return $this->content;
}
public function count()
{
return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
}
}
class_alias('Twig_Markup', 'Twig\Markup', false);

View File

@ -1,256 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a node in the AST.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node implements Twig_NodeInterface
{
protected $nodes;
protected $attributes;
protected $lineno;
protected $tag;
private $name;
/**
* Constructor.
*
* The nodes are automatically made available as properties ($this->node).
* The attributes are automatically made available as array items ($this['name']).
*
* @param array $nodes An array of named nodes
* @param array $attributes An array of attributes (should not be nodes)
* @param int $lineno The line number
* @param string $tag The tag name associated with the Node
*/
public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
{
foreach ($nodes as $name => $node) {
if (!$node instanceof Twig_NodeInterface) {
@trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', (is_object($node) ? get_class($node) : null) === $node ? 'null' : gettype($node), $name, get_class($this)), E_USER_DEPRECATED);
}
}
$this->nodes = $nodes;
$this->attributes = $attributes;
$this->lineno = $lineno;
$this->tag = $tag;
}
public function __toString()
{
$attributes = array();
foreach ($this->attributes as $name => $value) {
$attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
}
$repr = array(get_class($this).'('.implode(', ', $attributes));
if (count($this->nodes)) {
foreach ($this->nodes as $name => $node) {
$len = strlen($name) + 4;
$noderepr = array();
foreach (explode("\n", (string) $node) as $line) {
$noderepr[] = str_repeat(' ', $len).$line;
}
$repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
}
$repr[] = ')';
} else {
$repr[0] .= ')';
}
return implode("\n", $repr);
}
/**
* @deprecated since 1.16.1 (to be removed in 2.0)
*/
public function toXml($asDom = false)
{
@trigger_error(sprintf('%s is deprecated since version 1.16.1 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED);
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$dom->appendChild($xml = $dom->createElement('twig'));
$xml->appendChild($node = $dom->createElement('node'));
$node->setAttribute('class', get_class($this));
foreach ($this->attributes as $name => $value) {
$node->appendChild($attribute = $dom->createElement('attribute'));
$attribute->setAttribute('name', $name);
$attribute->appendChild($dom->createTextNode($value));
}
foreach ($this->nodes as $name => $n) {
if (null === $n) {
continue;
}
$child = $n->toXml(true)->getElementsByTagName('node')->item(0);
$child = $dom->importNode($child, true);
$child->setAttribute('name', $name);
$node->appendChild($child);
}
return $asDom ? $dom : $dom->saveXML();
}
public function compile(Twig_Compiler $compiler)
{
foreach ($this->nodes as $node) {
$node->compile($compiler);
}
}
public function getTemplateLine()
{
return $this->lineno;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getLine()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateLine() instead.', E_USER_DEPRECATED);
return $this->lineno;
}
public function getNodeTag()
{
return $this->tag;
}
/**
* @return bool
*/
public function hasAttribute($name)
{
return array_key_exists($name, $this->attributes);
}
/**
* @return mixed
*/
public function getAttribute($name)
{
if (!array_key_exists($name, $this->attributes)) {
throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
}
return $this->attributes[$name];
}
/**
* @param string $name
* @param mixed $value
*/
public function setAttribute($name, $value)
{
$this->attributes[$name] = $value;
}
public function removeAttribute($name)
{
unset($this->attributes[$name]);
}
/**
* @return bool
*/
public function hasNode($name)
{
return array_key_exists($name, $this->nodes);
}
/**
* @return Twig_Node
*/
public function getNode($name)
{
if (!array_key_exists($name, $this->nodes)) {
throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
}
return $this->nodes[$name];
}
public function setNode($name, $node = null)
{
if (!$node instanceof Twig_NodeInterface) {
@trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', (is_object($node) ? get_class($node) : null) === $node ? 'null' : gettype($node), $name, get_class($this)), E_USER_DEPRECATED);
}
$this->nodes[$name] = $node;
}
public function removeNode($name)
{
unset($this->nodes[$name]);
}
public function count()
{
return count($this->nodes);
}
public function getIterator()
{
return new ArrayIterator($this->nodes);
}
public function setTemplateName($name)
{
$this->name = $name;
foreach ($this->nodes as $node) {
if (null !== $node) {
$node->setTemplateName($name);
}
}
}
public function getTemplateName()
{
return $this->name;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function setFilename($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', E_USER_DEPRECATED);
$this->setTemplateName($name);
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getFilename()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', E_USER_DEPRECATED);
return $this->name;
}
}
class_alias('Twig_Node', 'Twig\Node\Node', false);
class_exists('Twig_Compiler');

View File

@ -1,36 +0,0 @@
<?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.
*/
/**
* Represents an autoescape node.
*
* The value is the escaping strategy (can be html, js, ...)
*
* The true value is equivalent to html.
*
* If autoescaping is disabled, then the value is false.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_AutoEscape extends Twig_Node
{
public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
{
parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
$compiler->subcompile($this->getNode('body'));
}
}
class_alias('Twig_Node_AutoEscape', 'Twig\Node\AutoEscapeNode', false);

View File

@ -1,41 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a block node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Block extends Twig_Node
{
public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
{
parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
->indent()
;
$compiler
->subcompile($this->getNode('body'))
->outdent()
->write("}\n\n")
;
}
}
class_alias('Twig_Node_Block', 'Twig\Node\BlockNode', false);

View File

@ -1,34 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a block call node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
{
public function __construct($name, $lineno, $tag = null)
{
parent::__construct(array(), array('name' => $name), $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
;
}
}
class_alias('Twig_Node_BlockReference', 'Twig\Node\BlockReferenceNode', false);

View File

@ -1,21 +0,0 @@
<?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.
*/
/**
* Represents a body node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Body extends Twig_Node
{
}
class_alias('Twig_Node_Body', 'Twig\Node\BodyNode', false);

View File

@ -1,80 +0,0 @@
<?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.
*/
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_CheckSecurity extends Twig_Node
{
protected $usedFilters;
protected $usedTags;
protected $usedFunctions;
public function __construct(array $usedFilters, array $usedTags, array $usedFunctions)
{
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
$this->usedFunctions = $usedFunctions;
parent::__construct();
}
public function compile(Twig_Compiler $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->getTemplateLine();
} else {
${$type}[$node] = null;
}
}
}
$compiler
->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('Twig_Extension_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->setSourceContext(\$this->getSourceContext());\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\n")
;
}
}
class_alias('Twig_Node_CheckSecurity', 'Twig\Node\CheckSecurityNode', false);

View File

@ -1,35 +0,0 @@
<?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.
*/
/**
* Represents a do node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Do extends Twig_Node
{
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
{
parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('')
->subcompile($this->getNode('expr'))
->raw(";\n")
;
}
}
class_alias('Twig_Node_Do', 'Twig\Node\DoNode', false);

View File

@ -1,46 +0,0 @@
<?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.
*/
/**
* Represents an embed node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Embed extends Twig_Node_Include
{
// we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
public function __construct($name, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
{
parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
$this->setAttribute('name', $name);
// to be removed in 2.0, used name instead
$this->setAttribute('filename', $name);
$this->setAttribute('index', $index);
}
protected function addGetTemplate(Twig_Compiler $compiler)
{
$compiler
->write('$this->loadTemplate(')
->string($this->getAttribute('name'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(', ')
->string($this->getAttribute('index'))
->raw(')')
;
}
}
class_alias('Twig_Node_Embed', 'Twig\Node\EmbedNode', false);

View File

@ -1,22 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Abstract class for all nodes that represents an expression.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Twig_Node_Expression extends Twig_Node
{
}
class_alias('Twig_Node_Expression', 'Twig\Node\Expression\AbstractExpression', false);

View File

@ -1,83 +0,0 @@
<?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_Node_Expression_Array extends Twig_Node_Expression
{
protected $index;
public function __construct(array $elements, $lineno)
{
parent::__construct($elements, array(), $lineno);
$this->index = -1;
foreach ($this->getKeyValuePairs() as $pair) {
if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
$this->index = $pair['key']->getAttribute('value');
}
}
}
public function getKeyValuePairs()
{
$pairs = array();
foreach (array_chunk($this->nodes, 2) as $pair) {
$pairs[] = array(
'key' => $pair[0],
'value' => $pair[1],
);
}
return $pairs;
}
public function hasElement(Twig_Node_Expression $key)
{
foreach ($this->getKeyValuePairs() as $pair) {
// we compare the string representation of the keys
// to avoid comparing the line numbers which are not relevant here.
if ((string) $key === (string) $pair['key']) {
return true;
}
}
return false;
}
public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
{
if (null === $key) {
$key = new Twig_Node_Expression_Constant(++$this->index, $value->getTemplateLine());
}
array_push($this->nodes, $key, $value);
}
public function compile(Twig_Compiler $compiler)
{
$compiler->raw('array(');
$first = true;
foreach ($this->getKeyValuePairs() as $pair) {
if (!$first) {
$compiler->raw(', ');
}
$first = false;
$compiler
->subcompile($pair['key'])
->raw(' => ')
->subcompile($pair['value'])
;
}
$compiler->raw(')');
}
}
class_alias('Twig_Node_Expression_Array', 'Twig\Node\Expression\ArrayExpression', false);

View File

@ -1,25 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('$context[')
->string($this->getAttribute('name'))
->raw(']')
;
}
}
class_alias('Twig_Node_Expression_AssignName', 'Twig\Node\Expression\AssignNameExpression', false);

View File

@ -1,37 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
{
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
{
parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
}
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('left'))
->raw(' ')
;
$this->operator($compiler);
$compiler
->raw(' ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
abstract public function operator(Twig_Compiler $compiler);
}
class_alias('Twig_Node_Expression_Binary', 'Twig\Node\Expression\Binary\AbstractBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('+');
}
}
class_alias('Twig_Node_Expression_Binary_Add', 'Twig\Node\Expression\Binary\AddBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('&&');
}
}
class_alias('Twig_Node_Expression_Binary_And', 'Twig\Node\Expression\Binary\AndBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('&');
}
}
class_alias('Twig_Node_Expression_Binary_BitwiseAnd', 'Twig\Node\Expression\Binary\BitwiseAndBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('|');
}
}
class_alias('Twig_Node_Expression_Binary_BitwiseOr', 'Twig\Node\Expression\Binary\BitwiseOrBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('^');
}
}
class_alias('Twig_Node_Expression_Binary_BitwiseXor', 'Twig\Node\Expression\Binary\BitwiseXorBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('.');
}
}
class_alias('Twig_Node_Expression_Binary_Concat', 'Twig\Node\Expression\Binary\ConcatBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('/');
}
}
class_alias('Twig_Node_Expression_Binary_Div', 'Twig\Node\Expression\Binary\DivBinary', false);

View File

@ -1,32 +0,0 @@
<?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_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(sprintf(') && is_string($%s = ', $right))
->subcompile($this->getNode('right'))
->raw(sprintf(') && (\'\' === $%2$s || $%2$s === substr($%1$s, -strlen($%2$s))))', $left, $right))
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig_Node_Expression_Binary_EndsWith', 'Twig\Node\Expression\Binary\EndsWithBinary', false);

View File

@ -1,19 +0,0 @@
<?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_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('==');
}
}
class_alias('Twig_Node_Expression_Binary_Equal', 'Twig\Node\Expression\Binary\EqualBinary', false);

View File

@ -1,26 +0,0 @@
<?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_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$compiler->raw('(int) floor(');
parent::compile($compiler);
$compiler->raw(')');
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('/');
}
}
class_alias('Twig_Node_Expression_Binary_FloorDiv', 'Twig\Node\Expression\Binary\FloorDivBinary', false);

View File

@ -1,19 +0,0 @@
<?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_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('>');
}
}
class_alias('Twig_Node_Expression_Binary_Greater', 'Twig\Node\Expression\Binary\GreaterBinary', false);

View File

@ -1,19 +0,0 @@
<?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_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('>=');
}
}
class_alias('Twig_Node_Expression_Binary_GreaterEqual', 'Twig\Node\Expression\Binary\GreaterEqualBinary', false);

View File

@ -1,30 +0,0 @@
<?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_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('twig_in_filter(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('in');
}
}
class_alias('Twig_Node_Expression_Binary_In', 'Twig\Node\Expression\Binary\InBinary', false);

View File

@ -1,19 +0,0 @@
<?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_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('<');
}
}
class_alias('Twig_Node_Expression_Binary_Less', 'Twig\Node\Expression\Binary\LessBinary', false);

View File

@ -1,19 +0,0 @@
<?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_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('<=');
}
}
class_alias('Twig_Node_Expression_Binary_LessEqual', 'Twig\Node\Expression\Binary\LessEqualBinary', false);

View File

@ -1,30 +0,0 @@
<?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_Node_Expression_Binary_Matches extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('preg_match(')
->subcompile($this->getNode('right'))
->raw(', ')
->subcompile($this->getNode('left'))
->raw(')')
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig_Node_Expression_Binary_Matches', 'Twig\Node\Expression\Binary\MatchesBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('%');
}
}
class_alias('Twig_Node_Expression_Binary_Mod', 'Twig\Node\Expression\Binary\ModBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('*');
}
}
class_alias('Twig_Node_Expression_Binary_Mul', 'Twig\Node\Expression\Binary\MulBinary', false);

View File

@ -1,19 +0,0 @@
<?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_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('!=');
}
}
class_alias('Twig_Node_Expression_Binary_NotEqual', 'Twig\Node\Expression\Binary\NotEqualBinary', false);

View File

@ -1,30 +0,0 @@
<?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_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('!twig_in_filter(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('not in');
}
}
class_alias('Twig_Node_Expression_Binary_NotIn', 'Twig\Node\Expression\Binary\NotInBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('||');
}
}
class_alias('Twig_Node_Expression_Binary_Or', 'Twig\Node\Expression\Binary\OrBinary', false);

View File

@ -1,34 +0,0 @@
<?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_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
if (PHP_VERSION_ID >= 50600) {
return parent::compile($compiler);
}
$compiler
->raw('pow(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('**');
}
}
class_alias('Twig_Node_Expression_Binary_Power', 'Twig\Node\Expression\Binary\PowerBinary', false);

View File

@ -1,30 +0,0 @@
<?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_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('range(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('..');
}
}
class_alias('Twig_Node_Expression_Binary_Range', 'Twig\Node\Expression\Binary\RangeBinary', false);

View File

@ -1,32 +0,0 @@
<?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_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(sprintf(') && is_string($%s = ', $right))
->subcompile($this->getNode('right'))
->raw(sprintf(') && (\'\' === $%2$s || 0 === strpos($%1$s, $%2$s)))', $left, $right))
;
}
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig_Node_Expression_Binary_StartsWith', 'Twig\Node\Expression\Binary\StartsWithBinary', false);

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('-');
}
}
class_alias('Twig_Node_Expression_Binary_Sub', 'Twig\Node\Expression\Binary\SubBinary', false);

View File

@ -1,93 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a block call node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
{
/**
* @param Twig_Node|null $template
*/
public function __construct(Twig_NodeInterface $name, $template = null, $lineno, $tag = null)
{
if (is_bool($template)) {
@trigger_error(sprintf('The %s method "$asString" argument is deprecated since version 1.28 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED);
$template = null;
}
$nodes = array('name' => $name);
if (null !== $template) {
$nodes['template'] = $template;
}
parent::__construct($nodes, array('is_defined_test' => false, 'output' => false), $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
if ($this->getAttribute('is_defined_test')) {
$this->compileTemplateCall($compiler, 'hasBlock');
} else {
if ($this->getAttribute('output')) {
$compiler->addDebugInfo($this);
$this
->compileTemplateCall($compiler, 'displayBlock')
->raw(";\n");
} else {
$this->compileTemplateCall($compiler, 'renderBlock');
}
}
}
private function compileTemplateCall(Twig_Compiler $compiler, $method)
{
if (!$this->hasNode('template')) {
$compiler->write('$this');
} else {
$compiler
->write('$this->loadTemplate(')
->subcompile($this->getNode('template'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(')')
;
}
$compiler->raw(sprintf('->%s', $method));
$this->compileBlockArguments($compiler);
return $compiler;
}
private function compileBlockArguments(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('name'))
->raw(', $context');
if (!$this->hasNode('template')) {
$compiler->raw(', $blocks');
}
return $compiler->raw(')');
}
}
class_alias('Twig_Node_Expression_BlockReference', 'Twig\Node\Expression\BlockReferenceExpression', false);

View File

@ -1,291 +0,0 @@
<?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.
*/
abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
{
private $reflector;
protected function compileCallable(Twig_Compiler $compiler)
{
$closingParenthesis = false;
if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) {
if (is_string($callable) && false === strpos($callable, '::')) {
$compiler->raw($callable);
} else {
list($r, $callable) = $this->reflectCallable($callable);
if ($r instanceof ReflectionMethod && is_string($callable[0])) {
if ($r->isStatic()) {
$compiler->raw(sprintf('%s::%s', $callable[0], $callable[1]));
} else {
$compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1]));
}
} elseif ($r instanceof ReflectionMethod && $callable[0] instanceof Twig_ExtensionInterface) {
$compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', get_class($callable[0]), $callable[1]));
} else {
$type = ucfirst($this->getAttribute('type'));
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
$closingParenthesis = true;
}
}
} else {
$compiler->raw($this->getAttribute('thing')->compile());
}
$this->compileArguments($compiler);
if ($closingParenthesis) {
$compiler->raw(')');
}
}
protected function compileArguments(Twig_Compiler $compiler)
{
$compiler->raw('(');
$first = true;
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
$compiler->raw('$this->env');
$first = false;
}
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->raw('$context');
$first = false;
}
if ($this->hasAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as $argument) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->string($argument);
$first = false;
}
}
if ($this->hasNode('node')) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->subcompile($this->getNode('node'));
$first = false;
}
if ($this->hasNode('arguments')) {
$callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
$arguments = $this->getArguments($callable, $this->getNode('arguments'));
foreach ($arguments as $node) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->subcompile($node);
$first = false;
}
}
$compiler->raw(')');
}
protected function getArguments($callable, $arguments)
{
$callType = $this->getAttribute('type');
$callName = $this->getAttribute('name');
$parameters = array();
$named = false;
foreach ($arguments as $name => $node) {
if (!is_int($name)) {
$named = true;
$name = $this->normalizeName($name);
} elseif ($named) {
throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName));
}
$parameters[$name] = $node;
}
$isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic');
if (!$named && !$isVariadic) {
return $parameters;
}
if (!$callable) {
if ($named) {
$message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName);
} else {
$message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
}
throw new LogicException($message);
}
$callableParameters = $this->getCallableParameters($callable, $isVariadic);
$arguments = array();
$names = array();
$missingArguments = array();
$optionalArguments = array();
$pos = 0;
foreach ($callableParameters as $callableParameter) {
$names[] = $name = $this->normalizeName($callableParameter->name);
if (array_key_exists($name, $parameters)) {
if (array_key_exists($pos, $parameters)) {
throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName));
}
if (count($missingArguments)) {
throw new Twig_Error_Syntax(sprintf(
'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".',
$name, $callType, $callName, implode(', ', $names), count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments))
);
}
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$name];
unset($parameters[$name]);
$optionalArguments = array();
} elseif (array_key_exists($pos, $parameters)) {
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$pos];
unset($parameters[$pos]);
$optionalArguments = array();
++$pos;
} elseif ($callableParameter->isDefaultValueAvailable()) {
$optionalArguments[] = new Twig_Node_Expression_Constant($callableParameter->getDefaultValue(), -1);
} elseif ($callableParameter->isOptional()) {
if (empty($parameters)) {
break;
} else {
$missingArguments[] = $name;
}
} else {
throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName));
}
}
if ($isVariadic) {
$arbitraryArguments = new Twig_Node_Expression_Array(array(), -1);
foreach ($parameters as $key => $value) {
if (is_int($key)) {
$arbitraryArguments->addElement($value);
} else {
$arbitraryArguments->addElement($value, new Twig_Node_Expression_Constant($key, -1));
}
unset($parameters[$key]);
}
if ($arbitraryArguments->count()) {
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $arbitraryArguments;
}
}
if (!empty($parameters)) {
$unknownParameter = null;
foreach ($parameters as $parameter) {
if ($parameter instanceof Twig_Node) {
$unknownParameter = $parameter;
break;
}
}
throw new Twig_Error_Syntax(sprintf(
'Unknown argument%s "%s" for %s "%s(%s)".',
count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names)
), $unknownParameter ? $unknownParameter->getTemplateLine() : -1);
}
return $arguments;
}
protected function normalizeName($name)
{
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
}
private function getCallableParameters($callable, $isVariadic)
{
list($r) = $this->reflectCallable($callable);
if (null === $r) {
return array();
}
$parameters = $r->getParameters();
if ($this->hasNode('node')) {
array_shift($parameters);
}
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
array_shift($parameters);
}
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
array_shift($parameters);
}
if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as $argument) {
array_shift($parameters);
}
}
if ($isVariadic) {
$argument = end($parameters);
if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) {
array_pop($parameters);
} else {
$callableName = $r->name;
if ($r instanceof ReflectionMethod) {
$callableName = $r->getDeclaringClass()->name.'::'.$callableName;
}
throw new LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = array()".', $callableName, $this->getAttribute('type'), $this->getAttribute('name')));
}
}
return $parameters;
}
private function reflectCallable($callable)
{
if (null !== $this->reflector) {
return $this->reflector;
}
if (is_array($callable)) {
if (!method_exists($callable[0], $callable[1])) {
// __call()
return array(null, array());
}
$r = new ReflectionMethod($callable[0], $callable[1]);
} elseif (is_object($callable) && !$callable instanceof Closure) {
$r = new ReflectionObject($callable);
$r = $r->getMethod('__invoke');
$callable = array($callable, '__invoke');
} elseif (is_string($callable) && false !== $pos = strpos($callable, '::')) {
$class = substr($callable, 0, $pos);
$method = substr($callable, $pos + 2);
if (!method_exists($class, $method)) {
// __staticCall()
return array(null, array());
}
$r = new ReflectionMethod($callable);
$callable = array($class, $method);
} else {
$r = new ReflectionFunction($callable);
}
return $this->reflector = array($r, $callable);
}
}
class_alias('Twig_Node_Expression_Call', 'Twig\Node\Expression\CallExpression', false);

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