Merge pull request 'feature/recode-genericdb-php8' (#44) from feature/recode-genericdb-php8 into dev_php82

Reviewed-on: #44
Dieser Commit ist enthalten in:
Ortwin Pinke 2023-10-11 15:29:53 +00:00
Commit 6a28bd3eaf
235 geänderte Dateien mit 24165 neuen und 2201 gelöschten Zeilen

Datei anzeigen

@ -25,6 +25,9 @@
<excludeFolder url="file://$MODULE_DIR$/conlite/vendor/rector/rector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpmailer/phpmailer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-ctype" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

Datei anzeigen

@ -12,6 +12,12 @@
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
</list>
</option>
</component>

Datei anzeigen

@ -16,6 +16,9 @@
<path value="$PROJECT_DIR$/conlite/external/phpqrcode/tools" />
<path value="$PROJECT_DIR$/vendor/composer" />
<path value="$PROJECT_DIR$/vendor/phpmailer/phpmailer" />
<path value="$PROJECT_DIR$/vendor/twig/twig" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.0">
@ -31,7 +34,7 @@
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/conlite/external/autoload.php" />
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
</phpunit_settings>
</component>
<component name="PsalmOptionsConfiguration">

Datei anzeigen

@ -11,6 +11,12 @@
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
</suites>
</component>
</project>

Datei anzeigen

@ -6,7 +6,6 @@
<option value="$PROJECT_DIR$/conlite/external/endroid/qr-code/tests" />
<option value="$PROJECT_DIR$/conlite/external/phpmailer/phpmailer/tests" />
<option value="$PROJECT_DIR$/tests" />
<option value="$PROJECT_DIR$/tests" />
</list>
</option>
</component>

Datei anzeigen

@ -10,7 +10,8 @@
],
"require": {
"php": "^8.0",
"phpmailer/phpmailer": "v6.8.0"
"phpmailer/phpmailer": "v6.8.0",
"twig/twig": "^3.0"
},
"require-dev": {
"phpstan/phpstan": "^1.10",

238
composer.lock generiert
Datei anzeigen

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "9677dc377e531a46fc52edb0594aa6c8",
"content-hash": "e2e5a5a59b3e9cdbc2023d399f119469",
"packages": [
{
"name": "phpmailer/phpmailer",
@ -85,6 +85,242 @@
}
],
"time": "2023-03-06T14:43:22+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"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.27.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": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.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": "2022-11-03T14:55:06+00:00"
},
{
"name": "twig/twig",
"version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "5cf942bbab3df42afa918caeba947f1b690af64b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/5cf942bbab3df42afa918caeba947f1b690af64b",
"reference": "5cf942bbab3df42afa918caeba947f1b690af64b",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
},
"type": "library",
"autoload": {
"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/v3.7.0"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2023-07-26T07:16:09+00:00"
}
],
"packages-dev": [

Datei anzeigen

@ -59,13 +59,13 @@ class DB_ConLite extends DB_Sql {
* - $options['enableProfiling'] (bool) Optional, flag to enable profiling
* @return void
*/
public function __construct(array $options = array()) {
public function __construct(array $options = []) {
global $cachemeta;
parent::__construct($options);
if (!is_array($cachemeta)) {
$cachemeta = array();
$cachemeta = [];
}
// TODO check this out
@ -109,7 +109,7 @@ class DB_ConLite extends DB_Sql {
*/
public function copyResultToArray($sTable = '') {
$aValues = array();
$aValues = [];
$aMetadata = $this->metadata($sTable);
@ -132,17 +132,8 @@ class DB_ConLite extends DB_Sql {
*
* @deprecated since version 2.0.0, use DB_ConLite instead
*/
class DB_Contenido extends DB_ConLite {
/**
*
* @deprecated since version 2.0.0
* @param array $options
*/
public function __construct(array $options = array()) {
parent::__construct($options);
}
class DB_Contenido extends DB_ConLite
{
}
class Contenido_CT_Sql extends CT_Sql {
@ -176,17 +167,12 @@ class Contenido_CT_Sql extends CT_Sql {
* @param string $id The session id (hash)
* @param string $name Name of the session
* @param string $str The value to store
* @return bool
*/
public function ac_store($id, $name, $str) {
switch ($this->encoding_mode) {
case 'slashes':
$str = addslashes($name . ':' . $str);
break;
case 'base64':
default:
$str = base64_encode($name . ':' . $str);
}
public function ac_store($id, $name, $str): bool {
$str = match ($this->encoding_mode) {
'slashes' => addslashes($name . ':' . $str),
default => base64_encode($name . ':' . $str),
};
$name = addslashes($name);
$now = date('YmdHis', time());
@ -195,7 +181,7 @@ class Contenido_CT_Sql extends CT_Sql {
"REPLACE INTO %s (sid, name, val, changed) VALUES ('%s', '%s', '%s', '%s')", $this->database_table, $id, $name, $str, $now
);
return ($this->db->query($iquery)) ? true : false;
return (bool) $this->db->query($iquery);
}
}
@ -280,14 +266,12 @@ class Contenido_CT_Shm extends CT_Shm {
class Contenido_CT_Session extends CT_Session {
public function __construct() {
$this->ac_start(array(
$this->ac_start([
'namespace' => 'contenido_ct_session_ns',
'session.hash_function' => '1', // use sha-1 function
'session.hash_bits_per_character' => '5', // and set 5 character to achieve 32 chars
# 'session.save_path' => 'your path',
# 'session.name' => 'your session name',
# 'session.gc_maxlifetime' => 'your lifetime in seconds',
));
'session.hash_function' => '1',
// use sha-1 function
'session.hash_bits_per_character' => '5',
]);
}
}
@ -321,8 +305,8 @@ class Contenido_Session extends Session {
}
public function delete() {
$oCol = new InUseCollection();
$oCol->removeSessionMarks($this->id);
$inUseCollection = new InUseCollection();
$inUseCollection->removeSessionMarks($this->id);
parent::delete();
}
@ -436,6 +420,8 @@ class Contenido_Challenge_Auth extends Auth {
}
public function auth_validatelogin() {
$pass = null;
$uid = null;
global $username, $password, $challenge, $response, $timestamp;
if ($password == '') {
@ -523,7 +509,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
public function auth_loglogin($uid) {
global $cfg, $client, $lang, $auth, $sess, $saveLoginTime;
$perm = new Contenido_Perm();
$contenidoPerm = new Contenido_Perm();
$timestamp = date('Y-m-d H:i:s');
$idcatart = '0';
@ -540,7 +526,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
$iTmpClient = $this->db->f('idclient');
$iTmpLang = $this->db->f('idlang');
if ($perm->have_perm_client_lang($iTmpClient, $iTmpLang)) {
if ($contenidoPerm->have_perm_client_lang($iTmpClient, $iTmpLang)) {
$client = $iTmpClient;
$lang = $iTmpLang;
$bFound = true;
@ -565,7 +551,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
return;
}
$idaction = $perm->getIDForAction('login');
$idaction = $contenidoPerm->getIDForAction('login');
$lastentry = $this->db->nextid($cfg['tab']['actionlog']);
$sql = "INSERT INTO
@ -585,9 +571,12 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
}
public function auth_validatelogin() {
$uid = null;
$perm = null;
$pass = null;
global $username, $password, $challenge, $response, $formtimestamp, $auth_handlers;
$gperm = array();
$gperm = [];
if ($password == '') {
return false;
@ -622,11 +611,9 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
$pass = $this->db->f('password'); ## Password is stored as a md5 hash
$bInMaintenance = false;
if ($sMaintenanceMode == 'enabled') {
#sysadmins are allowed to login every time
if (!preg_match('/sysadmin/', $perm)) {
$bInMaintenance = true;
}
#sysadmins are allowed to login every time
if ($sMaintenanceMode == 'enabled' && !preg_match('/sysadmin/', $perm)) {
$bInMaintenance = true;
}
if ($bInMaintenance) {
@ -635,14 +622,11 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
unset($pass);
}
if (is_array($auth_handlers) && !$bInMaintenance) {
if (array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
if (is_array($auth_handlers) && !$bInMaintenance && array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
}
}
@ -664,9 +648,7 @@ class Contenido_Challenge_Crypt_Auth extends Auth {
$gperm[] = $this->db->f('perms');
}
if (is_array($gperm)) {
$perm = implode(',', $gperm);
}
$perm = implode(',', $gperm);
if ($response == '') { ## True when JS is disabled
if (md5($password) != $pass) { ## md5 hash for non-JavaScript browsers
@ -718,8 +700,6 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
global $password;
if ($password == '') {
/* Stay as nobody when an empty password is passed */
$uid = $this->auth['uname'] = $this->auth['uid'] = 'nobody';
return false;
}
@ -736,13 +716,18 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
}
public function auth_validatelogin() {
$perm = null;
$gperm = [];
$pass = null;
global $username, $password, $challenge, $response, $auth_handlers, $client;
$client = (int) $client;
if (isset($username)) {
$this->auth['uname'] = $username; ## This provides access for 'loginform.ihtml'
} else if ($this->nobody) { ## provides for 'default login cancel'
$this->auth['uname'] = $username;
## This provides access for 'loginform.ihtml'
} elseif ($this->nobody) {
## provides for 'default login cancel'
$uid = $this->auth['uname'] = $this->auth['uid'] = 'nobody';
return $uid;
}
@ -768,13 +753,11 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
$perm = $this->db->f('perms');
$pass = $this->db->f('password'); ## Password is stored as a md5 hash
if (is_array($auth_handlers)) {
if (array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
if (is_array($auth_handlers) && array_key_exists($pass, $auth_handlers)) {
$success = call_user_func($auth_handlers[$pass], $username, $password);
if ($success) {
$uid = md5($username);
$pass = md5($password);
}
}
}
@ -796,9 +779,7 @@ class Contenido_Frontend_Challenge_Crypt_Auth extends Auth {
$gperm[] = $this->db->f('perms');
}
if (is_array($gperm)) {
$perm = implode(',', $gperm);
}
$perm = implode(',', $gperm);
}
}
@ -837,16 +818,16 @@ function register_auth_handler($aHandlers) {
global $auth_handlers;
if (!is_array($auth_handlers)) {
$auth_handlers = array();
$auth_handlers = [];
}
if (!is_array($aHandlers)) {
$aHandlers = Array($aHandlers);
$aHandlers = [$aHandlers];
}
foreach ($aHandlers as $sHandler) {
if (!in_array($sHandler, $auth_handlers)) {
$auth_handlers[md5($sHandler)] = $sHandler;
foreach ($aHandlers as $aHandler) {
if (!in_array($aHandler, $auth_handlers)) {
$auth_handlers[md5($aHandler)] = $aHandler;
}
}
}

Datei anzeigen

@ -35,8 +35,8 @@ if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
$_PHPLIB = array();
$_PHPLIB['libdir'] = str_replace ('\\', '/', dirname(__FILE__) . '/');
$_PHPLIB = [];
$_PHPLIB['libdir'] = str_replace ('\\', '/', __DIR__ . '/');
global $cfg;

Datei anzeigen

@ -0,0 +1,29 @@
<?php
namespace ConLite\GenericDb\Driver;
class GenericDbDriver
{
public $_sEncoding;
public $_oItemClassInstance;
public function setEncoding($sEncoding)
{
$this->_sEncoding = $sEncoding;
}
public function setItemClassInstance($oInstance)
{
$this->_oItemClassInstance = $oInstance;
}
public function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey)
{
}
public function buildOperator($sField, $sOperator, $sRestriction)
{
}
}

Datei anzeigen

@ -1,51 +1,32 @@
<?php
/**
* Project:
* Contenido Content Management System
*
* Description:
* MySQL Driver for GenericDB
*
* Requirements:
* @con_php_req 5.0
*
*
* @package Contenido Backend classes
* @version 1.12
* @author Bjoern Behrens
* @copyright four for business AG <www.4fb.de>
* @license http://www.contenido.org/license/LIZENZ.txt
* @link http://www.4fb.de
* @link http://www.contenido.org
*
* {@internal
* created 2006-05-10
* modified 2008-05-23 Added Debug_DevNull and Debug_VisibleAdv
*
* $Id$
* }}
*
*/
if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
namespace ConLite\GenericDb\Driver\MySql;
class gdbMySQL extends gdbDriver {
use cCharacterConverter;
use ConLite\GenericDb\Driver\GenericDbDriver;
use Contenido_Security;
function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey) {
class GenericDbDriverMySql extends GenericDbDriver
{
public $_oItemClassInstance;
public $_sEncoding;
function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey)
{
// Build a regular LEFT JOIN
$field = "$destinationClass.$destinationPrimaryKey";
$tables = "";
$join = "LEFT JOIN $destinationTable AS $destinationClass ON " .
Contenido_Security::toString($sourceClass . "." . $primaryKey) . " = " .
Contenido_Security::toString($destinationClass . "." . $primaryKey);
Contenido_Security::toString($sourceClass . "." . $primaryKey) . " = " .
Contenido_Security::toString($destinationClass . "." . $primaryKey);
$where = "";
return array("field" => $field, "table" => $tables, "join" => $join, "where" => $where);
return ["field" => $field, "table" => $tables, "join" => $join, "where" => $where];
}
function buildOperator($sField, $sOperator, $sRestriction) {
function buildOperator($sField, $sOperator, $sRestriction)
{
$sOperator = strtolower($sOperator);
$sWhereStatement = "";
@ -88,14 +69,14 @@ class gdbMySQL extends gdbDriver {
$GLOBALS["_cCharTable"] = new cCharacterConverter;
}
$aliasSearch = array();
$aliasSearch = [];
$metaCharacters = array("*", "[", "]", "^", '$', "\\", "*", "'", '"', '+');
$metaCharacters = ["*", "[", "]", "^", '$', "\\", "*", "'", '"', '+'];
for ($i = 0; $i < strlen($sRestriction); $i ++) {
for ($i = 0; $i < strlen($sRestriction); $i++) {
$char = substr($sRestriction, $i, 1);
$aliases = array();
$aliases = [];
$aliases = array_merge($aliases, $GLOBALS["_cCharTable"]->fetchDiacriticCharactersForNormalizedChar($this->_sEncoding, $char));
$normalizedChars = $GLOBALS["_cCharTable"]->fetchNormalizedCharsForDiacriticCharacter($this->_sEncoding, $char);
@ -106,9 +87,9 @@ class gdbMySQL extends gdbDriver {
$aliases = array_merge($aliases, $normalizedChars);
if (count($aliases) > 0) {
if ($aliases !== []) {
$aliases[] = $char;
$allAliases = array();
$allAliases = [];
foreach ($aliases as $alias) {
$alias1 = $this->_oItemClassInstance->_inFilter($alias);
@ -119,8 +100,7 @@ class gdbMySQL extends gdbDriver {
$allAliases = array_unique($allAliases);
$aliasSearch[] = "(" . implode("|", $allAliases) . ")";
} else {
$addChars = array();
$addChars = [];
if (in_array($char, $metaCharacters)) {
@ -131,11 +111,7 @@ class gdbMySQL extends gdbDriver {
$vChar = $this->_oItemClassInstance->_inFilter($char);
if ($char != $vChar) {
if (in_array($vChar, $metaCharacters)) {
$addChars[] = "\\\\" . $vChar;
} else {
$addChars[] = $vChar;
}
$addChars[] = in_array($vChar, $metaCharacters) ? "\\\\" . $vChar : $vChar;
}
}
@ -144,7 +120,7 @@ class gdbMySQL extends gdbDriver {
}
$restriction = "'" . implode("", $aliasSearch) . "'";
$sWhereStatement = implode(" ", array($sField, "REGEXP", $restriction));
$sWhereStatement = implode(" ", [$sField, "REGEXP", $restriction]);
break;
case "fulltext":
@ -152,9 +128,9 @@ class gdbMySQL extends gdbDriver {
break;
case "in":
if (is_array($sRestriction)) {
$items = array();
$items = [];
foreach ($sRestriction as $key => $sRestrictionItem) {
foreach ($sRestriction as $sRestrictionItem) {
$items[] = "'" . $this->_oItemClassInstance->_inFilter($sRestrictionItem) . "'";
}
@ -163,14 +139,14 @@ class gdbMySQL extends gdbDriver {
$sRestriction = "'" . $sRestriction . "'";
}
$sWhereStatement = implode(" ", array($sField, "IN (", $sRestriction, ")"));
$sWhereStatement = implode(" ", [$sField, "IN (", $sRestriction, ")"]);
break;
case "notin":
if (is_array($sRestriction)) {
$items = array();
$items = [];
foreach ($sRestriction as $key => $sRestrictionItem) {
$items[] = "'" . $this->_oItemClassInstance->_inFilter($sRestrictionItem) . "'";
foreach ($sRestriction as $Restriction) {
$items[] = "'" . $this->_oItemClassInstance->_inFilter($Restriction) . "'";
}
$sRestriction = implode(", ", $items);
@ -178,17 +154,15 @@ class gdbMySQL extends gdbDriver {
$sRestriction = "'" . $sRestriction . "'";
}
$sWhereStatement = implode(" ", array($sField, "NOT IN (", $sRestriction, ")"));
$sWhereStatement = implode(" ", [$sField, "NOT IN (", $sRestriction, ")"]);
break;
default :
$sRestriction = "'" . $this->_oItemClassInstance->_inFilter($sRestriction) . "'";
$sWhereStatement = implode(" ", array($sField, $sOperator, $sRestriction));
$sWhereStatement = implode(" ", [$sField, $sOperator, $sRestriction]);
}
return $sWhereStatement;
}
}
?>
}

Datei anzeigen

@ -0,0 +1,515 @@
<?php
namespace ConLite\GenericDb;
use stdClass;
abstract class Item extends ItemBaseAbstract
{
/**
* @var string
*/
public $_lastSQL;
/**
* Storage of the source table to use for the user informations
* @var array
*/
public $values;
/**
* Storage of the fields which were modified, where the keys are the
* fieldnames and the values just simple booleans.
* @var array
*/
protected $modifiedValues;
/**
* Stores the old primary key, just in case somebody wants to change it
* @var string
*/
protected $oldPrimaryKey;
/**
* List of funcion names of the filters used when data is stored to the db.
* @var array
*/
protected $_arrInFilters = ['urlencode', 'clHtmlSpecialChars', 'addslashes'];
/**
* List of funcion names of the filtersused when data is retrieved from the db
* @var array
*/
protected $_arrOutFilters = ['stripslashes', 'htmldecode', 'urldecode'];
/**
* Class name of meta object
* @var string
*/
protected $_metaObject;
/**
* Constructor function
*
* @param string $sTable The table to use as information source
* @param string $sPrimaryKey The primary key to use
* @param int $iLifetime
*/
public function __construct($sTable = '', $sPrimaryKey = '', $iLifetime = 10)
{
parent::__construct($sTable, $sPrimaryKey, get_parent_class($this), $iLifetime);
}
function __destruct()
{
//print_r(self::$_oCache);
}
/**
* Loads an item by colum/field from the database.
*
* @param string $sField Specifies the field
* @param mixed $mValue Specifies the value
* @param bool $bSafe Use inFilter or not
* @return bool True if the load was successful
*/
public function loadBy($sField, mixed $mValue, $bSafe = true): bool
{
if ($bSafe) {
$mValue = $this->_inFilter($mValue);
}
if ($sField === $this->primaryKey) {
$aRecordSet = self::$_oCache->getItem($this->table . "_" . $mValue);
} else {
$aRecordSet = self::$_oCache->getItemByProperty($this->table . "_" . $sField, $mValue);
}
if ($aRecordSet) {
// entry in cache found, load entry from cache
$this->loadByRecordSet($aRecordSet);
return true;
}
// SQL-Statement to select by field
$sql = sprintf("SELECT * FROM `%s` WHERE %s = '%s'", $this->table, $sField, $mValue);
//$sql = $this->db->prepare($sql, $this->table, $sField, $mValue);
// Query the database
$this->db->query($sql);
$this->_lastSQL = $sql;
if ($this->db->num_rows() > 1) {
$sMsg = "Tried to load a single line with field $sField and value $mValue from "
. $this->table . " but found more than one row";
cWarning(__FILE__, __LINE__, $sMsg);
}
// Advance to the next record, return false if nothing found
if (!$this->db->next_record()) {
return false;
}
$this->loadByRecordSet($this->db->toArray());
return true;
}
/**
* Loads an item by passed where clause from the database.
* This function is expensive, since it executes allways a query to the database
* to retrieve the primary key, even if the record set is aleady cached.
* NOTE: Passed value has to be escaped before. This will not be done by this function.
*
* @param string $sWhere The where clause like 'idart = 123 AND idlang = 1'
* @return bool True if the load was successful
*/
protected function _loadByWhereClause($sWhere)
{
// SQL-Statement to select by whee clause
$sql = sprintf("SELECT %s AS pk FROM `%s` WHERE ", $this->primaryKey, $this->table) . $sWhere;
//$sql = $this->db->prepare($sql, $this->primaryKey, $this->table);
// Query the database
$this->db->query($sql);
$this->_lastSQL = $sql;
if ($this->db->num_rows() > 1) {
$sMsg = "Tried to load a single line with where clause '" . $sWhere . "' from "
. $this->table . " but found more than one row";
cWarning(__FILE__, __LINE__, $sMsg);
}
// Advance to the next record, return false if nothing found
if (!$this->db->next_record()) {
return false;
}
$id = $this->db->f('pk');
return $this->loadByPrimaryKey($id);
}
/**
* Loads an item by ID from the database.
*
* @param string $mValue Specifies the primary key value
* @return bool True if the load was successful
*/
public function loadByPrimaryKey($mValue)
{
$bSuccess = $this->loadBy($this->primaryKey, $mValue);
if (($bSuccess == true) && method_exists($this, '_onLoad')) {
$this->_onLoad();
}
return $bSuccess;
}
/**
* Loads an item by it's recordset.
*
* @param array $aRecordSet The recordset of the item
*/
public function loadByRecordSet(array $aRecordSet)
{
$this->values = $aRecordSet;
$this->oldPrimaryKey = $this->values[$this->primaryKey];
$this->virgin = false;
self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values);
}
/**
* Checks if a the item is already loaded.
* @return boolean
*/
public function isLoaded()
{
return !$this->virgin;
}
/**
* Function which is called whenever an item is loaded.
* Inherited classes should override this function if desired.
*
* @return void
*/
protected function _onLoad()
{
}
/**
* Gets the value of a specific field.
*
* @param string $sField Specifies the field to retrieve
* @return mixed Value of the field
*/
public function getField($sField)
{
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
return $this->_outFilter($this->values[$sField]);
}
/**
* Wrapper for getField (less to type).
*
* @param string $sField Specifies the field to retrieve
* @return mixed Value of the field
*/
public function get($sField)
{
return $this->getField($sField);
}
/**
* Sets the value of a specific field.
*
* @param string $sField Field name
* @param string $mValue Value to set
* @param bool $bSafe Flag to run defined inFilter on passed value
*/
public function setField($sField, $mValue, $bSafe = true): bool
{
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
$this->modifiedValues[$sField] = true;
if ($sField == $this->primaryKey) {
$this->oldPrimaryKey = $this->values[$sField];
}
$this->values[$sField] = $bSafe == true ? $this->_inFilter($mValue) : $mValue;
return true;
}
/**
* Shortcut to setField.
*
* @param string $sField Field name
* @param string $mValue Value to set
* @param bool $bSafe Flag to run defined inFilter on passed value
*/
public function set($sField, $mValue, $bSafe = true)
{
return $this->setField($sField, $mValue, $bSafe);
}
/**
* Stores the loaded and modified item to the database.
*
* @return bool
*/
public function store()
{
if (!$this->isLoaded()) {
$this->lasterror = 'No item loaded';
return false;
}
$sql = 'UPDATE `' . $this->table . '` SET ';
$first = true;
if (!is_array($this->modifiedValues)) {
return true;
}
foreach (array_keys($this->modifiedValues) as $key) {
if ($first == true) {
$sql .= "`$key` = '" . $this->values[$key] . "'";
$first = false;
} else {
$sql .= ", `$key` = '" . $this->values[$key] . "'";
}
}
$sql .= " WHERE " . $this->primaryKey . " = '" . $this->oldPrimaryKey . "'";
$this->db->query($sql);
$this->_lastSQL = $sql;
if ($this->db->affected_rows() > 0) {
self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values);
}
return $this->db->affected_rows() >= 1;
}
/**
* Returns current item data as an assoziative array.
*/
public function toArray(): array|false
{
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
$aReturn = [];
foreach (array_keys($this->values) as $field) {
$aReturn[$field] = $this->getField($field);
}
return $aReturn;
}
/**
* Returns current item data as an object.
*/
public function toObject(): stdClass|false
{
$return = $this->toArray();
return (false !== $return) ? (object)$return : $return;
}
/**
* Sets a custom property.
*
* @param string $sType Specifies the type
* @param string $sName Specifies the name
* @param mixed $mValue Specifies the value
* @return bool
*/
public function setProperty($sType, $sName, mixed $mValue)
{
// If this object wasn't loaded before, return false
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
// Set the value
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->setValue(
$this->primaryKey, $this->get($this->primaryKey), $sType, $sName, $mValue
);
}
/**
* Returns a custom property.
*
* @param string $sType Specifies the type
* @param string $sName Specifies the name
* @return mixed Value of the given property or false
*/
public function getProperty($sType, $sName)
{
// If this object wasn't loaded before, return false
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
// Return the value
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->getValue(
$this->primaryKey, $this->get($this->primaryKey), $sType, $sName
);
}
/**
* Deletes a custom property.
*
* @param string $sType Specifies the type
* @param string $sName Specifies the name
* @return bool
*/
public function deleteProperty($sType, $sName)
{
// If this object wasn't loaded before, return false
if ($this->virgin == true) {
$this->lasterror = 'No item loaded';
return false;
}
// Delete the value
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->deleteValue(
$this->primaryKey, $this->get($this->primaryKey), $sType, $sName
);
}
/**
* Deletes a custom property by its id.
*
* @param int $idprop Id of property
* @return bool
*/
public function deletePropertyById($idprop)
{
$oProperties = $this->_getPropertiesCollectionInstance();
return $oProperties->delete($idprop);
}
/**
* Deletes the current item
*
* @return void
*/
// Method doesn't work, remove in future versions
// function delete()
// {
// $this->_collectionInstance->delete($item->get($this->primaryKey));
//}
/**
* Define the filter functions used when data is being stored or retrieved
* from the database.
*
* Examples:
* <pre>
* $obj->setFilters(array('addslashes'), array('stripslashes'));
* $obj->setFilters(array('htmlencode', 'addslashes'), array('stripslashes', 'htmlencode'));
* </pre>
*
* @param array $aInFilters Array with function names
* @param array $aOutFilters Array with function names
*
* @return void
*/
public function setFilters($aInFilters = [], $aOutFilters = [])
{
$this->_arrInFilters = $aInFilters;
$this->_arrOutFilters = $aOutFilters;
}
/**
* Filters the passed data using the functions defines in the _arrInFilters array.
*
* @param mixed $mData Data to filter
* @return mixed Filtered data
* @see setFilters
*
* @todo This method is used from public scope, but it should be protected
*
*/
public function _inFilter(mixed $mData)
{
if (is_numeric($mData) || is_array($mData)) {
return $mData;
}
if (is_null($mData)) {
$mData = '';
}
foreach ($this->_arrInFilters as $_arrInFilter) {
if (function_exists($_arrInFilter)) {
$mData = $_arrInFilter($mData);
}
}
return $mData;
}
/**
* Filters the passed data using the functions defines in the _arrOutFilters array.
*
* @param mixed $mData Data to filter
* @return mixed Filtered data
* @see setFilters
*
*/
protected function _outFilter(mixed $mData)
{
if (is_numeric($mData))
return $mData;
foreach ($this->_arrOutFilters as $_arrOutFilter) {
if (function_exists($_arrOutFilter)) {
$mData = $_arrOutFilter($mData);
}
}
return $mData;
}
protected function _setMetaObject($sObjectName)
{
$this->_metaObject = $sObjectName;
}
public function getMetaObject()
{
global $_metaObjectCache;
if (!is_array($_metaObjectCache)) {
$_metaObjectCache = [];
}
$sClassName = $this->_metaObject;
$qclassname = strtolower($sClassName);
if (array_key_exists($qclassname, $_metaObjectCache) && is_object($_metaObjectCache[$qclassname])) {
if (strtolower($_metaObjectCache[$qclassname]::class) === $qclassname) {
$_metaObjectCache[$qclassname]->setPayloadObject($this);
return $_metaObjectCache[$qclassname];
}
}
if (class_exists($sClassName)) {
$_metaObjectCache[$qclassname] = new $sClassName($this);
return $_metaObjectCache[$qclassname];
}
}
}

Datei anzeigen

@ -1,12 +1,16 @@
<?php
/**
*
*/
namespace ConLite\GenericDb;
// security check
defined('CON_FRAMEWORK') or die('Illegal call');
abstract class cItemBaseAbstract {
use DB_ConLite;
use PropertyCollection;
abstract class ItemBaseAbstract
{
/**
* Database instance, contains the database object
@ -29,9 +33,9 @@ abstract class cItemBaseAbstract {
/**
* Item cache instance
* @var Contenido_ItemCache
* @var ItemCache
*/
protected static $_oCache;
protected static ItemCache $_oCache;
/**
* GenericDB settings, see $cfg['sql']
@ -85,17 +89,17 @@ abstract class cItemBaseAbstract {
* @var string
*/
protected $_className;
protected $_bDebug;
/**
* Sets some common properties
*
* @param string $sTable Name of table
* @param string $sPrimaryKey Primary key of table
* @param string $sClassName Name of parent class
* @param int $iLifetime Lifetime of the object in seconds (NOT USED!)
* @throws Contenido_ItemException If table name or primary key is not set
* @param string $sTable Name of table
* @param string $sPrimaryKey Primary key of table
* @param string $sClassName Name of parent class
* @param int $iLifetime Lifetime of the object in seconds (NOT USED!)
* @throws ItemException
*/
protected function __construct($sTable, $sPrimaryKey, $sClassName, $iLifetime = 10) {
global $cfg;
@ -104,17 +108,17 @@ abstract class cItemBaseAbstract {
if ($sTable == '') {
$sMsg = "$sClassName: No table specified. Inherited classes *need* to set a table";
throw new Contenido_ItemException($sMsg);
throw new ItemException($sMsg);
} elseif ($sPrimaryKey == '') {
$sMsg = "No primary key specified. Inherited classes *need* to set a primary key";
throw new Contenido_ItemException($sMsg);
throw new ItemException($sMsg);
}
$this->_settings = $cfg['sql'];
// instanciate caching
$aCacheOpt = (isset($this->_settings['cache'])) ? $this->_settings['cache'] : array();
self::$_oCache = cItemCache::getInstance($sTable, $aCacheOpt);
self::$_oCache = ItemCache::getInstance($sTable, $aCacheOpt);
$this->table = $sTable;
$this->primaryKey = $sPrimaryKey;
@ -159,6 +163,4 @@ abstract class cItemBaseAbstract {
return $this->properties;
}
}
?>
}

Datei anzeigen

@ -1,30 +1,25 @@
<?php
/**
*
*/
namespace ConLite\GenericDb;
// security check
defined('CON_FRAMEWORK') or die('Illegal call');
class cItemCache {
class ItemCache
{
/**
* List of self instances (Contenido_ItemCache)
* @var array
*/
protected static $_oInstances = array();
protected static $_oInstances = [];
/**
* Assoziative cache array
* @var array
*/
protected $_aItemsCache = array();
/**
* Table name for current instance
* @var string
*/
protected $_sTable = '';
protected $_aItemsCache = [];
/**
* Max number of items to cache
@ -41,18 +36,17 @@ class cItemCache {
/**
* Contructor of Contenido_ItemCache
* @param string $sTable Table name
* @param string $_sTable Table name
* @param array $aOptions Options array as follows:
* - $aOptions['max_items_to_cache'] = (int) Number of items to cache
* - $aOptions['enable'] = (bool) Flag to enable caching
*/
protected function __construct($sTable, array $aOptions = array()) {
$this->_sTable = $sTable;
protected function __construct(protected $_sTable, array $aOptions = []) {
if (isset($aOptions['max_items_to_cache']) && (int) $aOptions['max_items_to_cache'] > 0) {
$this->_iMaxItemsToCache = (int) $aOptions['max_items_to_cache'];
}
if (isset($aOptions['enable']) && is_bool($aOptions['enable'])) {
$this->_bEnable = (bool) $aOptions['enable'];
$this->_bEnable = $aOptions['enable'];
}
if (isset($_GET['frame']) && is_numeric($_GET['frame'])) {
@ -62,13 +56,6 @@ class cItemCache {
}
}
/**
* Prevent cloning
*/
protected function __clone() {
}
/**
* Returns item cache instance, creates it, if not done before.
* Works as a singleton for one specific table.
@ -78,7 +65,7 @@ class cItemCache {
* - $aOptions['max_items_to_cache'] = (int) Number of items to cache
* - $aOptions['enable'] = (bool) Flag to enable caching
*/
public static function getInstance($sTable, array $aOptions = array()) {
public static function getInstance($sTable, array $aOptions = []) {
if (!isset(self::$_oInstances[$sTable])) {
self::$_oInstances[$sTable] = new self($sTable, $aOptions);
}
@ -96,11 +83,8 @@ class cItemCache {
/**
* Returns existing entry from cache by it's id.
*
* @param mixed $mId
* @return array|null
*/
public function getItem($mId) {
public function getItem(mixed $mId): ?array {
if (!$this->_bEnable) {
return null;
}
@ -114,19 +98,15 @@ class cItemCache {
/**
* Returns existing entry from cache by matching propery value.
*
* @param mixed $mProperty
* @param mixed $mValue
* @return array|null
*/
public function getItemByProperty($mProperty, $mValue) {
public function getItemByProperty(mixed $mProperty, mixed $mValue): ?array {
if (!$this->_bEnable) {
return null;
}
// loop thru all cached entries and try to find a entry by it's property
if (is_array($this->_aItemsCache[$this->_iFrame]) && count($this->_aItemsCache[$this->_iFrame]) > 0) {
foreach ($this->_aItemsCache[$this->_iFrame] as $id => $aEntry) {
if (is_array($this->_aItemsCache[$this->_iFrame]) && $this->_aItemsCache[$this->_iFrame] !== []) {
foreach ($this->_aItemsCache[$this->_iFrame] as $aEntry) {
if (isset($aEntry[$mProperty]) && $aEntry[$mProperty] == $mValue) {
return $aEntry;
}
@ -139,28 +119,23 @@ class cItemCache {
* Returns existing entry from cache by matching properties and their values.
*
* @param array $aProperties Assoziative key value pairs
* @return array|null
*/
public function getItemByProperties(array $aProperties) {
public function getItemByProperties(array $aProperties): ?array {
if (!$this->_bEnable) {
return null;
}
// loop thru all cached entries and try to find a entry by it's property
foreach ($this->_aItemsCache as $id => $aEntry) {
foreach ($this->_aItemsCache as $_aItemCache) {
$mFound = null;
foreach ($aProperties as $key => $value) {
if (isset($aEntry[$key]) && $aEntry[$key] == $value) {
if (null === $mFound) {
$mFound = true;
}
if (isset($_aItemCache[$key]) && $_aItemCache[$key] == $value) {
$mFound = true;
} else {
$mFound = false;
break;
}
if (true === $mFound) {
return $aEntry;
}
return $_aItemCache;
}
}
return null;
@ -169,11 +144,10 @@ class cItemCache {
/**
* Adds passed item data to internal cache
*
* @param mixed $mId
* @param array $aData Usually the recordset
* @return void
*/
public function addItem($mId, array $aData) {
public function addItem(mixed $mId, array $aData) {
if (!$this->_bEnable) {
return null;
}
@ -181,7 +155,7 @@ class cItemCache {
if (isset($this->_aItemsCache[$this->_iFrame])) {
$aTmpItemsArray = $this->_aItemsCache[$this->_iFrame];
if ($this->_iMaxItemsToCache == count($aTmpItemsArray)) {
if ($this->_iMaxItemsToCache == (is_countable($aTmpItemsArray) ? count($aTmpItemsArray) : 0)) {
// we have reached the maximum number of cached items, remove first entry
$firstEntryKey = array_shift($aTmpItemsArray);
if (is_array($firstEntryKey))
@ -197,10 +171,9 @@ class cItemCache {
/**
* Removes existing cache entry by it's key
*
* @param mixed $mId
* @return void
*/
public function removeItem($mId) {
public function removeItem(mixed $mId) {
if (!$this->_bEnable) {
return null;
}
@ -211,4 +184,4 @@ class cItemCache {
}
}
}
}

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,9 @@
<?php
namespace ConLite\GenericDb;
use Exception;
class ItemException extends Exception {
}

Datei anzeigen

@ -0,0 +1,7 @@
<?php
namespace ConLite\Html;
class Html extends HtmlCommon
{
}

Datei anzeigen

@ -0,0 +1,42 @@
<?php
namespace ConLite\Html;
abstract class HtmlCommon implements \ArrayAccess
{
protected string|array|null $attributes = null;
public function __construct(array|string|null $attributes = null)
{
$this->attributes = $attributes;
}
#[\ReturnTypeWillChange]
public function offsetExists(mixed $offset): bool
{
return isset($this->attributes[strtolower($offset)]);
}
#[\ReturnTypeWillChange]
public function offsetGet(mixed $offset)
{
return $this->getAttribute($offset);
}
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value): void
{
if (null !== $offset) {
$this->setAttribute($offset, $value);
} else {
$this->setAttribute($value);
}
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset): void
{
$this->removeAttribute($offset);
}
}

Datei anzeigen

@ -382,7 +382,8 @@ class DBFSItem extends Item {
parent::store();
}
public function setField($field, $value, $safe = true) {
public function setField($field, $value, $safe = true): bool
{
if ($field == "dirname" || $field == "filename" || $field == "mimetype") {
// Don't do safe encoding
$safe = false;
@ -391,7 +392,7 @@ class DBFSItem extends Item {
$value = str_replace('"', "", $value);
}
parent::setField($field, $value, $safe);
return parent::setField($field, $value, $safe);
}
}

Datei anzeigen

@ -157,12 +157,12 @@ class FrontendUser extends Item
* @param string $field Specifies the field to set
* @param string $value Specifies the value to set
*/
public function setField($field, $value, $safe = true)
public function setField($field, $value, $safe = true): bool
{
if ($field == "password") {
parent::setField($field, md5($value), $safe);
return parent::setField($field, md5($value), $safe);
} else {
parent::setField($field, $value, $safe);
return parent::setField($field, $value, $safe);
}
}

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -447,7 +447,7 @@ class PropertyItem extends Item
* @param string $value
* @param bool $safe Flag to run filter on passed value
*/
public function setField($field, $value, $safe = true)
public function setField($field, $value, $safe = true): bool
{
if (array_key_exists($field, $this->maximumLength)) {
if (strlen($value) > $this->maximumLength[$field]) {
@ -455,7 +455,7 @@ class PropertyItem extends Item
}
}
parent::setField($field, $value, $safe);
return parent::setField($field, $value, $safe);
}
}

Datei anzeigen

@ -57,10 +57,8 @@ class cApiModuleCollection extends ItemCollection {
$oMod = $this->_itemClassInstance;
$oMod->_bNoted = TRUE;
$oMod->loadByPrimaryKey($iIdMod);
if ($oMod->isLoaded()) {
if ($oMod->hasModuleFolder()) {
$oMod->deleteModuleFolder();
}
if ($oMod->isLoaded() && $oMod->hasModuleFolder()) {
$oMod->deleteModuleFolder();
}
unset($oMod);
return parent::delete($iIdMod);
@ -73,6 +71,12 @@ class cApiModuleCollection extends ItemCollection {
*/
class cApiModule extends Item {
public $_oldumask;
/**
* @var mixed
*/
public $_sModAliasOld;
public $_bNoted;
protected $_error;
/**
@ -83,10 +87,7 @@ class cApiModule extends Item {
protected $_bOutputFromFile = false;
protected $_bInputFromFile = false;
/**
* @var array
*/
private $aUsedTemplates = array();
private array $aUsedTemplates = [];
/**
* Configuration Array of ModFileEdit
@ -94,25 +95,12 @@ class cApiModule extends Item {
*
* @var array
*/
private $_aModFileEditConf = array(
'use' => false,
'modFolderName' => 'data/modules'
);
private $_aModFileEditConf = ['use' => false, 'modFolderName' => 'data/modules'];
/**
*
* @var string
*/
private $_sModAlias;
private ?string $_sModAlias = null;
/**
*
* @var string
*/
private $_sModPath;
private $_aModDefaultStruct = array(
'css', 'js', 'php', 'template', 'image', 'lang', 'xml'
);
private ?string $_sModPath = null;
private array $_aModDefaultStruct = ['css', 'js', 'php', 'template', 'image', 'lang', 'xml'];
/**
* Constructor Function
@ -128,13 +116,9 @@ class cApiModule extends Item {
// That's why you don't have to stripslashes values if you store them
// using ->set. You have to add slashes, if you store data directly
// (data not from a form field)
$this->setFilters(array(), array());
$this->setFilters([], []);
$this->_packageStructure = array(
"jsfiles" => $cfgClient["js"]["path"],
"tplfiles" => $cfgClient["tpl"]["path"],
"cssfiles" => $cfgClient["css"]["path"]
);
$this->_packageStructure = ["jsfiles" => $cfgClient["js"]["path"], "tplfiles" => $cfgClient["tpl"]["path"], "cssfiles" => $cfgClient["css"]["path"]];
if (isset($cfg['dceModEdit']) && is_array($cfg['dceModEdit'])) {
$this->_aModFileEditConf['clientPath'] = $cfgClient["path"]["frontend"];
@ -145,9 +129,9 @@ class cApiModule extends Item {
}
}
$oClient = new cApiClient(cRegistry::getClientId());
$aClientProp = $oClient->getPropertiesByType('modfileedit');
if (count($aClientProp) > 0) {
$cApiClient = new cApiClient(cRegistry::getClientId());
$aClientProp = $cApiClient->getPropertiesByType('modfileedit');
if ($aClientProp !== []) {
$this->_aModFileEditConf = array_merge($this->_aModFileEditConf, $aClientProp);
}
@ -164,7 +148,7 @@ class cApiModule extends Item {
try {
mkdir($this->_aModFileEditConf['modPath'], 0777, true);
} catch (Exception $ex) {
$oWriter = cLogWriter::factory("File", array('destination' => $sPathErrorLog));
$oWriter = cLogWriter::factory("File", ['destination' => $sPathErrorLog]);
$oLog = new cLog($oWriter);
$oLog->log($ex->getFile() . " (" . $ex->getLine() . "): " . $ex->getMessage(), cLog::WARN);
}
@ -176,7 +160,7 @@ class cApiModule extends Item {
try {
mkdir($this->getModulePath(), 0777);
} catch (Exception $ex) {
$oWriter = cLogWriter::factory("File", array('destination' => $sPathErrorLog));
$oWriter = cLogWriter::factory("File", ['destination' => $sPathErrorLog]);
$oLog = new cLog($oWriter);
$oLog->log($ex->getFile() . " (" . $ex->getLine() . "): " . $ex->getMessage(), cLog::WARN);
}
@ -187,7 +171,7 @@ class cApiModule extends Item {
umask($this->_oldumask);
}
} else {
$oWriter = cLogWriter::factory("File", array('destination' => $sPathErrorLog));
$oWriter = cLogWriter::factory("File", ['destination' => $sPathErrorLog]);
$oLog = new cLog($oWriter);
$oLog->log(__FILE__ . " (" . __LINE__ . "): " . 'Error: Cannot create mod path '.$this->getModulePath(), cLog::WARN);
}
@ -195,10 +179,8 @@ class cApiModule extends Item {
}
public function deleteModuleFolder() {
if ($this->_aModFileEditConf['use'] == TRUE && is_writable($this->_aModFileEditConf['modPath'])) {
if (is_dir($this->getModulePath())) {
return $this->_recursiveRemoveDirectory($this->getModulePath());
}
if ($this->_aModFileEditConf['use'] == TRUE && is_writable($this->_aModFileEditConf['modPath']) && is_dir($this->getModulePath())) {
return $this->_recursiveRemoveDirectory($this->getModulePath());
}
return FALSE;
}
@ -273,12 +255,12 @@ class cApiModule extends Item {
$code .= $this->get("input");
// Initialize array
$strings = array();
$strings = [];
// Split the code into mi18n chunks
$varr = preg_split('/mi18n([\s]*)\(([\s]*)"/', $code, -1);
if (count($varr) > 1) {
if ((is_countable($varr) ? count($varr) : 0) > 1) {
foreach ($varr as $key => $value) {
// Search first closing
$closing = strpos($value, '")');
@ -298,7 +280,7 @@ class cApiModule extends Item {
preg_match_all('/mi18n([\s]*)\("(.*)"\)/', $varr[$key], $results);
// Append to strings array if there are any results
if (is_array($results[1]) && count($results[2]) > 0) {
if (is_array($results[1]) && (is_countable($results[2]) ? count($results[2]) : 0) > 0) {
$strings = array_merge($strings, $results[2]);
}
@ -310,7 +292,7 @@ class cApiModule extends Item {
// adding dynamically new module translations by content types
// this function was introduced with contenido 4.8.13
// checking if array is set to prevent crashing the module translation page
if (is_array($cfg['translatable_content_types']) && count($cfg['translatable_content_types']) > 0) {
if (is_array($cfg['translatable_content_types']) && $cfg['translatable_content_types'] !== []) {
// iterate over all defines cms content types
foreach ($cfg['translatable_content_types'] as $sContentType) {
// check if the content type exists and include his class file
@ -321,7 +303,7 @@ class cApiModule extends Item {
// add the additional translations for the module
if (class_exists($sContentType) && method_exists($sContentType, 'addModuleTranslations') && preg_match('/' . strtoupper($sContentType) . '\[\d+\]/', $code)) {
$strings = call_user_func(array($sContentType, 'addModuleTranslations'), $strings);
$strings = call_user_func([$sContentType, 'addModuleTranslations'], $strings);
}
}
}
@ -338,7 +320,7 @@ class cApiModule extends Item {
public function moduleInUse($module, $bSetData = false) {
global $cfg;
$db = new DB_ConLite();
$dbConLite = new DB_ConLite();
$sql = "SELECT
c.idmod, c.idtpl, t.name
@ -350,17 +332,17 @@ class cApiModule extends Item {
t.idtpl=c.idtpl
GROUP BY c.idtpl
ORDER BY t.name";
$db->query($sql);
$dbConLite->query($sql);
if ($db->nf() == 0) {
if ($dbConLite->nf() == 0) {
return false;
} else {
$i = 0;
// save the datas of used templates in array
if ($bSetData === true) {
while ($db->next_record()) {
$this->aUsedTemplates[$i]['tpl_name'] = $db->f('name');
$this->aUsedTemplates[$i]['tpl_id'] = (int) $db->f('idmod');
while ($dbConLite->next_record()) {
$this->aUsedTemplates[$i]['tpl_name'] = $dbConLite->f('name');
$this->aUsedTemplates[$i]['tpl_id'] = (int) $dbConLite->f('idmod');
$i++;
}
}
@ -385,16 +367,16 @@ class cApiModule extends Item {
*/
public function isOldModule() {
// Keywords to scan
$scanKeywords = array('$cfgTab', 'idside', 'idsidelang');
$scanKeywords = ['$cfgTab', 'idside', 'idsidelang'];
$input = $this->get("input");
$output = $this->get("output");
foreach ($scanKeywords as $keyword) {
if (strstr($input, $keyword)) {
foreach ($scanKeywords as $scanKeyword) {
if (strstr($input, $scanKeyword)) {
return true;
}
if (strstr($output, $keyword)) {
if (strstr($output, $scanKeyword)) {
return true;
}
}
@ -403,11 +385,8 @@ class cApiModule extends Item {
public function getField($field) {
$value = parent::getField($field);
switch ($field) {
case "name":
if ($value == "") {
$value = i18n("- Unnamed Module -");
}
if ($field === "name" && $value == "") {
$value = i18n("- Unnamed Module -");
}
return ($value);
}
@ -415,7 +394,7 @@ class cApiModule extends Item {
public function store($bJustStore = false) {
global $cfg;
/* dceModFileEdit (c)2009-2011 www.dceonline.de */
if ($this->_aModFileEditConf['use'] == true && ($this->_aModFileEditConf['allModsFromFile'] == true || in_array($this->get('idmod'), $this->_aModFileEditConf['modsFromFile']))) {
if ($this->_aModFileEditConf['use'] == true && ($this->_aModFileEditConf['allModsFromFile'] == true || (is_array($this->_aModFileEditConf['modsFromFile']) && in_array($this->get('idmod'), $this->_aModFileEditConf['modsFromFile'])))) {
$this->modifiedValues['output'] = true;
$this->modifiedValues['input'] = true;
}
@ -430,11 +409,9 @@ class cApiModule extends Item {
conGenerateCodeForAllArtsUsingMod($this->get("idmod"));
if ($this->_shouldStoreToFile()) {
if ($this->_makeFileDirectoryStructure()) {
$sRootPath = $cfg['path']['contenido'] . $cfg['path']['modules'] . $this->get("idclient") . "/";
file_put_contents($sRootPath . $this->get("idmod") . ".xml", $this->export($this->get("idmod") . ".xml", true));
}
if ($this->_shouldStoreToFile() && $this->_makeFileDirectoryStructure()) {
$sRootPath = $cfg['path']['contenido'] . $cfg['path']['modules'] . $this->get("idclient") . "/";
file_put_contents($sRootPath . $this->get("idmod") . ".xml", $this->export($this->get("idmod") . ".xml", true));
}
}
}
@ -443,7 +420,7 @@ class cApiModule extends Item {
return $this->_aModFileEditConf;
}
protected function _recursiveRemoveDirectory($directory) {
protected function _recursiveRemoveDirectory($directory): bool {
foreach (glob("{$directory}/*") as $file) {
if (is_dir($file)) {
$this->_recursiveRemoveDirectory($file);
@ -508,26 +485,23 @@ class cApiModule extends Item {
private function _parseImportFile($sFile, $sType = "module", $sEncoding = "ISO-8859-1") {
global $_mImport;
$oParser = new clXmlParser($sEncoding);
$clXmlParser = new clXmlParser($sEncoding);
if ($sType == "module") {
$oParser->setEventHandlers(array("/module/name" => "cHandler_ModuleData",
"/module/description" => "cHandler_ModuleData",
"/module/type" => "cHandler_ModuleData",
"/module/input" => "cHandler_ModuleData",
"/module/output" => "cHandler_ModuleData"));
$clXmlParser->setEventHandlers(["/module/name" => "cHandler_ModuleData", "/module/description" => "cHandler_ModuleData", "/module/type" => "cHandler_ModuleData", "/module/input" => "cHandler_ModuleData", "/module/output" => "cHandler_ModuleData"]);
} else {
$aHandler = array("/modulepackage/guid" => "cHandler_ModuleData",
$aHandler = [
"/modulepackage/guid" => "cHandler_ModuleData",
#"/modulepackage/repository_guid" => "cHandler_ModuleData",
"/modulepackage/module/name" => "cHandler_ModuleData",
"/modulepackage/module/description" => "cHandler_ModuleData",
"/modulepackage/module/type" => "cHandler_ModuleData",
"/modulepackage/module/input" => "cHandler_ModuleData",
"/modulepackage/module/output" => "cHandler_ModuleData",
"/modulepackage/module/input" => "cHandler_ModuleData");
"/modulepackage/module/input" => "cHandler_ModuleData",
];
// Add file handler (e.g. js, css, templates)
foreach ($this->_packageStructure As $sFileType => $sFilePath) {
foreach (array_keys($this->_packageStructure) As $sFileType) {
// Note, that $aHandler["/modulepackage/" . $sFileType] and using
// a handler which uses the node name (here: FileType) doesn't work,
// as the event handler for the filetype node will be fired
@ -550,13 +524,13 @@ class cApiModule extends Item {
$aHandler["/modulepackage/translations/string/original"] = "cHandler_ItemName";
$aHandler["/modulepackage/translations/string/translation"] = "cHandler_Translation";
$oParser->setEventHandlers($aHandler);
$clXmlParser->setEventHandlers($aHandler);
}
if ($oParser->parseFile($sFile)) {
if ($clXmlParser->parseFile($sFile)) {
return true;
} else {
$this->_error = $oParser->error;
$this->_error = $clXmlParser->error;
return false;
}
}
@ -595,8 +569,8 @@ class cApiModule extends Item {
* @param $return boolean if false, the result is immediately sent to the browser
*/
public function export($filename, $return = false) {
$tree = new XmlTree('1.0', 'ISO-8859-1');
$root = & $tree->addRoot('module');
$xmlTree = new XmlTree('1.0', 'ISO-8859-1');
$root = & $xmlTree->addRoot('module');
$root->appendChild("name", clHtmlSpecialChars($this->get("name")));
$root->appendChild("description", clHtmlSpecialChars($this->get("description")));
@ -607,11 +581,11 @@ class cApiModule extends Item {
if ($return == false) {
ob_end_clean();
header("Content-Type: text/xml");
header("Etag: " . md5(mt_rand()));
header("Etag: " . md5(random_int(0, mt_getrandmax())));
header("Content-Disposition: attachment;filename=\"$filename\"");
$tree->dump(false);
$xmlTree->dump(false);
} else {
return stripslashes($tree->dump(true));
return stripslashes($xmlTree->dump(true));
}
}
@ -619,13 +593,13 @@ class cApiModule extends Item {
global $_mImport;
if ($this->_parseImportFile($sFile, "package")) {
$aData = array();
$aData = [];
$aData["guid"] = $_mImport["module"]["guid"];
$aData["repository_guid"] = $_mImport["module"]["repository_guid"];
$aData["name"] = $_mImport["module"]["name"];
// Files
foreach ($this->_packageStructure as $sFileType => $sFilePath) {
foreach (array_keys($this->_packageStructure) as $sFileType) {
if (is_array($_mImport["items"][$sFileType])) {
$aData[$sFileType] = array_keys($_mImport["items"][$sFileType]);
}
@ -666,26 +640,27 @@ class cApiModule extends Item {
*
* @return bool Returns true, if import has been successfully finished
*/
public function importPackage($sFile, $aOptions = array()) {
public function importPackage($sFile, $aOptions = []) {
$bStore = null;
global $_mImport, $client;
cInclude("includes", "functions.file.php");
cInclude("includes", "functions.lay.php"); // You won't believe the code in there (or what is missing in class.layout.php...)
// Ensure correct options structure
foreach ($this->_packageStructure as $sFileType => $sFilePath) {
foreach (array_keys($this->_packageStructure) as $sFileType) {
if (!is_array($aOptions["items"][$sFileType])) {
$aOptions["items"][$sFileType] = array();
$aOptions["items"][$sFileType] = [];
}
}
// Layouts
if (!is_array($aOptions["items"]["layouts"])) {
$aOptions["items"]["layouts"] = array();
$aOptions["items"]["layouts"] = [];
}
// Translations
if (!is_array($aOptions["translations"])) {
$aOptions["translations"] = array();
$aOptions["translations"] = [];
}
// Parse file
@ -712,7 +687,7 @@ class cApiModule extends Item {
createFile($sFileName, $sFilePath);
}
fileEdit($sFileName, $aContent["content"], $sFilePath);
} else if ($aOptions["items"][$sFileType][clHtmlSpecialChars($sFileName)] == "append") {
} elseif ($aOptions["items"][$sFileType][clHtmlSpecialChars($sFileName)] == "append") {
$sOriginalContent = getFileContent($sFileName, $sFilePath);
fileEdit($sFileName, $sOriginalContent . $aContent["content"], $sFilePath);
}
@ -751,13 +726,13 @@ class cApiModule extends Item {
// Translations
if (is_array($_mImport["translations"])) {
$oTranslations = new cApiModuleTranslationCollection();
$cApiModuleTranslationCollection = new cApiModuleTranslationCollection();
$iID = $this->get($this->primaryKey);
foreach ($_mImport["translations"] as $sPackageLang => $aTranslations) {
foreach (array_keys($_mImport["translations"]) as $sPackageLang) {
if (array_key_exists($sPackageLang, $aOptions["translations"])) {
foreach ($_mImport["translations"][$sPackageLang] as $sOriginal => $sTranslation) {
$oTranslations->create($iID, $aOptions["translations"][$sPackageLang], $sOriginal, $sTranslation);
$cApiModuleTranslationCollection->create($iID, $aOptions["translations"][$sPackageLang], $sOriginal, $sTranslation);
}
}
}
@ -779,21 +754,21 @@ class cApiModule extends Item {
cInclude("includes", "functions.file.php");
$oTree = new XmlTree('1.0', 'ISO-8859-1');
$oRoot = & $oTree->addRoot('modulepackage');
$xmlTree = new XmlTree('1.0', 'ISO-8859-1');
$oRoot = & $xmlTree->addRoot('modulepackage');
$oRoot->appendChild("package_guid", $this->get("package_guid"));
$oRoot->appendChild("package_data", $this->get("package_data")); // This is serialized and more or less informal data
$aData = unserialize($this->get("package_data"));
if (!is_array($aData)) {
$aData = array();
$aData = [];
$aData["repository_guid"] = "";
$aData["jsfiles"] = array();
$aData["tplfiles"] = array();
$aData["cssfiles"] = array();
$aData["layouts"] = array();
$aData["translations"] = array();
$aData["jsfiles"] = [];
$aData["tplfiles"] = [];
$aData["cssfiles"] = [];
$aData["layouts"] = [];
$aData["translations"] = [];
}
// Export basic module
@ -807,14 +782,12 @@ class cApiModule extends Item {
// Export files (e.g. js, css, templates)
foreach ($this->_packageStructure As $sFileType => $sFilePath) {
$oNodeFiles = & $oRoot->appendChild($sFileType);
if (count($aData[$sFileType]) > 0) {
foreach ($aData[$sFileType] as $sFileName) {
if (is_readable($sFilePath . $sFileName)) {
$sContent = getFileContent($sFileName, $sFilePath);
$oNodeFiles->appendChild("area", clHtmlSpecialChars($sFileType));
$oNodeFiles->appendChild("name", clHtmlSpecialChars($sFileName));
$oNodeFiles->appendChild("content", clHtmlSpecialChars($sContent));
}
foreach ($aData[$sFileType] as $sFileName) {
if (is_readable($sFilePath . $sFileName)) {
$sContent = getFileContent($sFileName, $sFilePath);
$oNodeFiles->appendChild("area", clHtmlSpecialChars($sFileType));
$oNodeFiles->appendChild("name", clHtmlSpecialChars($sFileName));
$oNodeFiles->appendChild("content", clHtmlSpecialChars($sContent));
}
}
}
@ -823,11 +796,11 @@ class cApiModule extends Item {
// Export layouts
$oNodeLayouts = & $oRoot->appendChild("layouts");
$oLayouts = new cApiLayoutCollection;
$oLayouts->setWhere("idclient", $client);
$oLayouts->query();
$cApiLayoutCollection = new cApiLayoutCollection;
$cApiLayoutCollection->setWhere("idclient", $client);
$cApiLayoutCollection->query();
while ($oLayout = $oLayouts->next()) {
while ($oLayout = $cApiLayoutCollection->next()) {
if (in_array($oLayout->get($oLayout->primaryKey), $aData["layouts"])) {
$oNodeLayouts->appendChild("area", "layouts");
$oNodeLayouts->appendChild("name", clHtmlSpecialChars($oLayout->get("name")));
@ -836,24 +809,23 @@ class cApiModule extends Item {
}
}
unset($oLayout);
unset($oLayouts);
unset($cApiLayoutCollection);
// Export translations
$oLangs = new cApiLanguageCollection();
$oLangs->setOrder("idlang");
$oLangs->query();
$cApiLanguageCollection = new cApiLanguageCollection();
$cApiLanguageCollection->setOrder("idlang");
$cApiLanguageCollection->query();
if ($oLangs->count() > 0) {
if ($cApiLanguageCollection->count() > 0) {
$iIDMod = $this->get($this->primaryKey);
while ($oLang = $oLangs->next()) {
while ($oLang = $cApiLanguageCollection->next()) {
$iID = $oLang->get($oLang->primaryKey);
if (in_array($iID, $aData["translations"])) {
$oNodeTrans = & $oRoot->appendChild("translations");
// This is nice, but it doesn't help so much,
// as this data is available too late on import ...
$oNodeTrans->setNodeAttribs(array("origin-language-id" => $iID,
"origin-language-name" => clHtmlSpecialChars($oLang->get("name"))));
$oNodeTrans->setNodeAttribs(["origin-language-id" => $iID, "origin-language-name" => clHtmlSpecialChars($oLang->get("name"))]);
// ... so we store the important information with the data
$oNodeTrans->appendChild("language", clHtmlSpecialChars($oLang->get("name")));
@ -870,17 +842,17 @@ class cApiModule extends Item {
}
}
}
unset($oLangs);
unset($cApiLanguageCollection);
unset($oLang);
if ($bReturn == false) {
ob_end_clean();
header("Content-Type: text/xml");
header("Etag: " . md5(mt_rand()));
header("Etag: " . md5(random_int(0, mt_getrandmax())));
header("Content-Disposition: attachment;filename=\"$sPackageFileName\"");
$oTree->dump(false);
$xmlTree->dump(false);
} else {
return stripslashes($oTree->dump(true));
return stripslashes($xmlTree->dump(true));
}
}
@ -926,7 +898,7 @@ class cApiModule extends Item {
}
private function _displayNoteFromFile($bIsOldPath = FALSE) {
if (isset($this->_bNoted) && $this->_bNoted === true) {
if (property_exists($this, '_bNoted') && $this->_bNoted !== null && $this->_bNoted === true) {
return;
}
global $frame, $area;
@ -935,23 +907,22 @@ class cApiModule extends Item {
if ($bIsOldPath) {
$sAddMess .= "<br>" . i18n("Using old CamelCase for name of modulefolder. You may lowercase the name for modulefolder");
}
$oNote = new Contenido_Notification();
$oNote->displayNotification('warning', i18n("Module uses Output- and/or InputFromFile. Editing and Saving may not be possible in backend.") . $sAddMess);
$contenidoNotification = new Contenido_Notification();
$contenidoNotification->displayNotification('warning', i18n("Module uses Output- and/or InputFromFile. Editing and Saving may not be possible in backend.") . $sAddMess);
$this->_bNoted = true;
}
}
/**
* read file and set an object field
*
*
* @param string $sFile
* @param string $sField
* @return boolean
*/
private function _setFieldFromFile($sField, $sFile) {
private function _setFieldFromFile($sField, $sFile): bool {
$bIsOldPath = TRUE;
$sFile = strtolower($sFile);
if (FALSE === strstr($sFile, $this->_aModFileEditConf['modPath'])) {
if (!str_contains($sFile, $this->_aModFileEditConf['modPath'])) {
$sFile = $this->_aModFileEditConf['modPath'] . $sFile;
}
// check for new struct since CL 2.0
@ -996,17 +967,12 @@ class cApiModule extends Item {
}
public function isLoadedFromFile($sWhat = "all") {
switch ($sWhat) {
case "all":
return (($this->_bOutputFromFile || $this->_bInputFromFile) ? TRUE : FALSE);
break;
case "output":
return $this->_bOutputFromFile;
case "input":
return $this->_bInputFromFile;
default:
return false;
}
return match ($sWhat) {
"all" => $this->_bOutputFromFile || $this->_bInputFromFile,
"output" => $this->_bOutputFromFile,
"input" => $this->_bInputFromFile,
default => false,
};
}
/* End dceModFileEdit (c)2009-2012 www.dceonline.de */
@ -1026,10 +992,7 @@ class cApiModule extends Item {
private function _createModulePhpFiles() {
$sPath = $this->_sModPath . "php/";
$aFileTpl = array(
'output' => "<?php\n\n?>",
'input' => "?><?php\n\n?><?php"
);
$aFileTpl = ['output' => "<?php\n\n?>", 'input' => "?><?php\n\n?><?php"];
if (is_writable($sPath)) {
$sOutputFile = $sPath . $this->_sModAlias . "_output.php";
@ -1085,8 +1048,8 @@ class cApiModuleTranslationCollection extends ItemCollection {
public function create($idmod, $idlang, $original, $translation = false) {
// Check if the original already exists. If it does,
// update the translation if passed
$mod = new cApiModuleTranslation();
$sorg = $mod->_inFilter($original);
$cApiModuleTranslation = new cApiModuleTranslation();
$sorg = $cApiModuleTranslation->_inFilter($original);
$this->select("idmod = '$idmod' AND idlang = '$idlang' AND original = '$sorg'");
@ -1142,21 +1105,20 @@ class cApiModuleTranslationCollection extends ItemCollection {
public function import($idmod, $idlang, $file) {
global $_mImport;
$parser = new clXmlParser("ISO-8859-1");
$clXmlParser = new clXmlParser("ISO-8859-1");
$parser->setEventHandlers(array("/module/translation/string/original" => "cHandler_ItemName",
"/module/translation/string/translation" => "cHandler_Translation"));
$clXmlParser->setEventHandlers(["/module/translation/string/original" => "cHandler_ItemName", "/module/translation/string/translation" => "cHandler_Translation"]);
$_mImport["current_item_area"] = "current"; // Pre-specification, as this won't be set from the XML file (here)
if ($parser->parseFile($file)) {
if ($clXmlParser->parseFile($file)) {
foreach ($_mImport["translations"]["current"] as $sOriginal => $sTranslation) {
$this->create($idmod, $idlang, $sOriginal, $sTranslation);
}
return true;
} else {
$this->_error = $parser->error;
$this->_error = $clXmlParser->error;
return false;
}
}
@ -1170,21 +1132,20 @@ class cApiModuleTranslationCollection extends ItemCollection {
* @param $return boolean if false, the result is immediately sent to the browser
*/
public function export($idmod, $idlang, $filename, $return = false) {
$langobj = new cApiLanguage($idlang);
$cApiLanguage = new cApiLanguage($idlang);
#$langstring = $langobj->get("name") . ' ('.$idlang.')';
$translations = new cApiModuleTranslationCollection;
$translations->select("idmod = '$idmod' AND idlang='$idlang'");
$cApiModuleTranslationCollection = new cApiModuleTranslationCollection;
$cApiModuleTranslationCollection->select("idmod = '$idmod' AND idlang='$idlang'");
$tree = new XmlTree('1.0', 'ISO-8859-1');
$root = & $tree->addRoot('module');
$xmlTree = new XmlTree('1.0', 'ISO-8859-1');
$root = & $xmlTree->addRoot('module');
$translation = & $root->appendChild('translation');
$translation->setNodeAttribs(array("origin-language-id" => $idlang,
"origin-language-name" => $langobj->get("name")));
$translation->setNodeAttribs(["origin-language-id" => $idlang, "origin-language-name" => $cApiLanguage->get("name")]);
while ($otranslation = $translations->next()) {
while ($otranslation = $cApiModuleTranslationCollection->next()) {
$string = &$translation->appendChild("string");
$string->appendChild("original", clHtmlSpecialChars($otranslation->get("original")));
@ -1193,11 +1154,11 @@ class cApiModuleTranslationCollection extends ItemCollection {
if ($return == false) {
header("Content-Type: text/xml");
header("Etag: " . md5(mt_rand()));
header("Etag: " . md5(random_int(0, mt_getrandmax())));
header("Content-Disposition: attachment;filename=\"$filename\"");
$tree->dump(false);
$xmlTree->dump(false);
} else {
return $tree->dump(true);
return $xmlTree->dump(true);
}
}

Datei anzeigen

@ -1,46 +0,0 @@
<?php
/**
* Project:
* Contenido Content Management System
*
* @package Contenido Backend classes
* @version 1.3
* @author Timo Hummel
* @copyright four for business AG <www.4fb.de>
* @license http://www.contenido.org/license/LIZENZ.txt
* @link http://www.4fb.de
* @link http://www.contenido.org
*
* $Id$
*/
if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
class gdbDriver {
var $_sEncoding;
var $_oItemClassInstance;
public function __construct() {
}
public function setEncoding($sEncoding) {
$this->_sEncoding = $sEncoding;
}
public function setItemClassInstance($oInstance) {
$this->_oItemClassInstance = $oInstance;
}
public function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey) {
}
public function buildOperator($sField, $sOperator, $sRestriction) {
}
}
?>

Datei anzeigen

@ -1,8 +0,0 @@
This directory contains driver classes for use with Contenido's GenericDB. These
drivers are responsible for building joins and handling database metadata, but
NOT for sending queries and returning results.
Dieses Verzeichnis enthält Treiberklassen für die Verwendung mit der Contenido
GenericDB. Diese Treiber sind ausschließlich dafür da, um Joins aufzubauen und
um die Metadaten zu verwalten. Sie sind NICHT für das Senden von Queries oder
das zurückgeben von Query-Ergebnissen zuständig.

Datei anzeigen

@ -49,21 +49,15 @@ cInclude ("includes", "functions.con.php");
*/
function layEditLayout($idlay, $name, $description, $code) {
global $client, $auth, $cfg, $sess, $area_tree, $perm, $cfgClient;
global $client, $auth, $cfg, $cfgClient;
$db2= new DB_ConLite;
$db = new DB_ConLite;
$db = new DB_ConLite();
$date = date("Y-m-d H:i:s");
$author = "".$auth->auth["uname"]."";
$description = (string) stripslashes($description);
/**
set_magic_quotes_gpc($name);
set_magic_quotes_gpc($description);
set_magic_quotes_gpc($code);
**/
//$code = addslashes($code);
$author = $auth->auth["uname"];
$description = stripslashes($description);
$code = addslashes($code);
if (strlen(trim($name)) == 0) {
$name = i18n('-- Unnamed Layout --');
}

Datei anzeigen

@ -232,7 +232,8 @@ if (!$perm->have_perm_area_action($area)) {
$tpl->set('d', 'CATNAME', i18n("Client name"));
$tpl->set('d', 'BGCOLOR', $cfg["color"]["table_dark"]);
$tpl->set('d', "BORDERCOLOR", $cfg["color"]["table_border"]);
$tpl->set('d', 'CATFIELD', formGenerateField("text", "clientname", clHtmlSpecialChars($db->f("name")), 50, 255));
$clientName = is_null($db->f("name"))?'':clHtmlSpecialChars($db->f("name"));
$tpl->set('d', 'CATFIELD', formGenerateField("text", "clientname", $clientName, 50, 255));
$tpl->set('d', 'BRDRT', 0);
$tpl->set('d', 'BRDRB', 1);
$tpl->set('d', 'FONT', 'text_medium');

Datei anzeigen

@ -41,13 +41,13 @@ $clang = new cApiLanguage($idlang);
#Script for refreshing Language Box in Header
$newOption = '';
$db2 = new DB_ConLite;
$db2 = new DB_ConLite();
$sReload = '<script language="javascript">
var left_bottom = top.content.left.left_bottom;
$sReload = '<script>
let left_bottom = top.content.left.left_bottom;
if (left_bottom) {
var href = left_bottom.location.href;
let href = left_bottom.location.href;
href = href.replace(/&idlang[^&]*/, \'\');
left_bottom.location.href = href+"&idlang="+"' . $idlang . '";
}
@ -59,9 +59,9 @@ if ($action == "lang_newlanguage" || $action == "lang_deletelanguage") {
if ($action == "lang_deletelanguage") {
// finally delete from dropdown in header
$newOption = '<script>
var langList = top.header.document.getElementById("cLanguageSelect");
var thepos="";
for(var i=0;i<langList.length;i++) {
let langList = top.header.document.getElementById("cLanguageSelect");
let thepos="";
for(let i=0;i<langList.length;i++) {
if(langList.options[i].value == ' . $idlang . ') {
thepos = langList.options[i].index;
}
@ -72,15 +72,15 @@ if ($action == "lang_newlanguage" || $action == "lang_deletelanguage") {
if ($action == "lang_newlanguage") {
// update language dropdown in header
$new_idlang = 0;
$new_idlang = 1;
$db->query('SELECT max(idlang) as newlang FROM ' . $cfg["tab"]["lang"] . ';');
if ($db->next_record()) {
$new_idlang = $db->f('newlang');
}
$newOption = '<script language="javascript">
var newLang = new Option("' . i18n("New language") . ' (' . $new_idlang . ')", "' . $new_idlang . '", false, false);
var langList = top.header.document.getElementById("cLanguageSelect");
$newOption = '<script>
let newLang = new Option("' . i18n("New language") . ' (' . $new_idlang . ')", "' . $new_idlang . '", false, false);
let langList = top.header.document.getElementById("cLanguageSelect");
langList.options[langList.options.length] = newLang;
</script>';
$idlang = $new_idlang;

Datei anzeigen

@ -84,9 +84,10 @@ if (!$layout->virgin) {
$ret = tplBrowseLayoutForContainers($idlay);
if (strlen($ret) != 0) {
$container = [];
$types =[];
$containers = explode("&", $ret);
$types = array();
foreach ($containers as $value) {
if ($value != "") {
@ -107,11 +108,7 @@ if (!$layout->virgin) {
}
$types = array_unique($types);
if (version_compare(PHP_VERSION, '7.4.0', '>=')) {
$layout->setProperty("layout", "used-types", implode(";", $types));
} else {
$layout->setProperty("layout", "used-types", implode($types, ";"));
}
$layout->setProperty("layout", "used-types", implode(";", $types));
$msg = "";
@ -138,7 +135,6 @@ if (!$layout->virgin) {
}
foreach ($v->missingNodes as $value) {
$idqualifier = "";
$attr = array();
@ -236,5 +232,4 @@ if (stripslashes($_REQUEST['idlay'])) {
$sReloadScript = "";
}
$page->addScript('reload', $sReloadScript);
$page->render();
?>
$page->render();

Datei anzeigen

@ -142,13 +142,13 @@ require_once($cfg['path']['conlite'] . $cfg['path']['includes'] . '/api/function
include_once($cfg['path']['conlite'] . $cfg['path']['classes'] . 'class.autoload.php');
cAutoload::initialize($cfg);
// init composer autoload
include_once($cfg['path']['conlite'] . 'vendor/autoload.php');
include_once(dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'vendor/autoload.php');
// 2. security check: Check HTTP parameters, if requested
if ($cfg['http_params_check']['enabled'] === true) {
$oHttpInputValidator =
new HttpInputValidator($cfg['path']['conlite'] . $cfg['path']['includes'] . '/config.http_check.php');
new HttpInputValidator($cfg['path']['config'] . CL_ENVIRONMENT . DIRECTORY_SEPARATOR . 'config.http_check.php');
}
/* Generate arrays for available login languages

Datei anzeigen

@ -70,6 +70,8 @@ $sMode = 'training';
#### Check whitelist ####
$aCheck = array();
$aCheck['GET']['error'] = CON_CHECK_INTEGER;
$aCheck['GET']['idart'] = CON_CHECK_INTEGER;
$aCheck['GET']['idcat'] = CON_CHECK_INTEGER;
$aCheck['GET']['idartlang'] = CON_CHECK_INTEGER;
@ -86,6 +88,4 @@ $aCheck['GET']['action'] = CON_CHECK_PRIMITIVESTRING;
$aCheck['GET']['page'] = CON_CHECK_INTEGER;
$aCheck['GET']['catname'] = CON_CHECK_PRIMITIVESTRING;
$aCheck['GET']['contenido'] = CON_CHECK_HASH32;
?>
$aCheck['GET']['contenido'] = CON_CHECK_HASH32;

Datei anzeigen

@ -1,12 +1,24 @@
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
return static function (RectorConfig $rectorConfig): void {
/*
$rectorConfig->autoloadPaths([
__DIR__ . '/conlite',
__DIR__ . '/conlib',
__DIR__ . '/setup',
]);
*/
$rectorConfig->bootstrapFiles([
__DIR__ . '/rector_cl_autoload.php',
]);
$rectorConfig->parallel();
$rectorConfig->paths([
__DIR__,
__DIR__.'/conlite',
]);
$rectorConfig->skip([
__DIR__ . DIRECTORY_SEPARATOR . 'node_modules',
@ -14,5 +26,10 @@ return static function (RectorConfig $rectorConfig): void {
__DIR__ . DIRECTORY_SEPARATOR . 'vendor',
]);
$rectorConfig->importNames();
$rectorConfig->import(LevelSetList::UP_TO_PHP_80);
$rectorConfig->sets([
LevelSetList::UP_TO_PHP_80,
SetList::CODE_QUALITY,
SetList::DEAD_CODE,
SetList::NAMING,
]);
};

13
rector_cl_autoload.php Normale Datei
Datei anzeigen

@ -0,0 +1,13 @@
<?php
if (!defined("CON_FRAMEWORK")) {
define("CON_FRAMEWORK", true);
}
include_once('conlite/classes/class.autoload.php');
$cfg = [
'path' => [
'config' => dirname(__FILE__) . '/data/config/production/',
'contenido' => dirname(__FILE__) . '/conlite/',
],
];
cAutoload::initialize($cfg);

Datei anzeigen

@ -106,13 +106,13 @@ if(!is_dir($cfg['path']['conlite_config'])) {
checkAndInclude($cfg['path']['conlite_config'] . 'config.misc.php');
checkAndInclude($cfg['path']['conlite_config'] . 'cfg_sql.inc.php');
include_once dirname(__DIR__, 2) . '/vendor/autoload.php';
// includes
/** @todo use conlite autoload to load needed classes */
checkAndInclude($cfg['path']['frontend'] . '/pear/HTML/Common2.php');
checkAndInclude($cfg['path']['conlite'] . 'classes/con2con/class.registry.php');
// load all genericdb classes
checkAndInclude($cfg['path']['conlite'] . 'classes/genericdb/class.item.base.abstract.php');
checkAndInclude($cfg['path']['conlite'] . 'classes/genericdb/class.item.cache.php');
checkAndInclude($cfg['path']['conlite'] . 'classes/class.genericdb.php');
checkAndInclude($cfg['path']['conlite'] . 'classes/cHTML5/class.chtml5.common.php');
checkAndInclude($cfg['path']['conlite'] . 'classes/cHTML5/class.chtml.php');

11
vendor/composer/autoload_files.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,11 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
);

Datei anzeigen

@ -6,6 +6,9 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Twig\\' => array($vendorDir . '/twig/twig/src'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
'ConLite\\' => array($baseDir . '/conlite/classes'),
);

Datei anzeigen

@ -52,6 +52,29 @@ class ComposerAutoloaderInit030320213c853f2cfb8481e1bb7caf00
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit030320213c853f2cfb8481e1bb7caf00::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire030320213c853f2cfb8481e1bb7caf00($fileIdentifier, $file);
}
return $loader;
}
}
/**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequire030320213c853f2cfb8481e1bb7caf00($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}

Datei anzeigen

@ -6,7 +6,21 @@ namespace Composer\Autoload;
class ComposerStaticInit030320213c853f2cfb8481e1bb7caf00
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'T' =>
array (
'Twig\\' => 5,
),
'S' =>
array (
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
),
'P' =>
array (
'PHPMailer\\PHPMailer\\' => 20,
@ -18,6 +32,18 @@ class ComposerStaticInit030320213c853f2cfb8481e1bb7caf00
);
public static $prefixDirsPsr4 = array (
'Twig\\' =>
array (
0 => __DIR__ . '/..' . '/twig/twig/src',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'PHPMailer\\PHPMailer\\' =>
array (
0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',

Datei anzeigen

@ -82,6 +82,251 @@
}
],
"install-path": "../phpmailer/phpmailer"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"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.27.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"
}
],
"install-path": "../symfony/polyfill-ctype"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.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"
}
],
"install-path": "../symfony/polyfill-mbstring"
},
{
"name": "twig/twig",
"version": "v3.7.0",
"version_normalized": "3.7.0.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "5cf942bbab3df42afa918caeba947f1b690af64b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/5cf942bbab3df42afa918caeba947f1b690af64b",
"reference": "5cf942bbab3df42afa918caeba947f1b690af64b",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
},
"time": "2023-07-26T07:16:09+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"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/v3.7.0"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"install-path": "../twig/twig"
}
],
"dev": false,

Datei anzeigen

@ -5,7 +5,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '727cad0e1e2ad00ac92dac6aa02e5ea0b4ca1dfb',
'reference' => '9d2f901385912df64e41f232d3aed5c03d588c06',
'name' => 'org.conlite/conlite',
'dev' => false,
),
@ -16,7 +16,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '727cad0e1e2ad00ac92dac6aa02e5ea0b4ca1dfb',
'reference' => '9d2f901385912df64e41f232d3aed5c03d588c06',
'dev_requirement' => false,
),
'phpmailer/phpmailer' => array(
@ -28,5 +28,32 @@
'reference' => 'df16b615e371d81fb79e506277faea67a1be18f1',
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'reference' => '5bbc823adecdae860bb64756d639ecfec17b050a',
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534',
'dev_requirement' => false,
),
'twig/twig' => array(
'pretty_version' => 'v3.7.0',
'version' => '3.7.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../twig/twig',
'aliases' => array(),
'reference' => '5cf942bbab3df42afa918caeba947f1b690af64b',
'dev_requirement' => false,
),
),
);

232
vendor/symfony/polyfill-ctype/Ctype.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,232 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Ctype;
/**
* Ctype implementation through regex.
*
* @internal
*
* @author Gert de Pagter <BackEndTea@gmail.com>
*/
final class Ctype
{
/**
* Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.
*
* @see https://php.net/ctype-alnum
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_alnum($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
}
/**
* Returns TRUE if every character in text is a letter, FALSE otherwise.
*
* @see https://php.net/ctype-alpha
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_alpha($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
}
/**
* Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.
*
* @see https://php.net/ctype-cntrl
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_cntrl($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
}
/**
* Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.
*
* @see https://php.net/ctype-digit
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_digit($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
}
/**
* Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.
*
* @see https://php.net/ctype-graph
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_graph($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
}
/**
* Returns TRUE if every character in text is a lowercase letter.
*
* @see https://php.net/ctype-lower
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_lower($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
}
/**
* Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.
*
* @see https://php.net/ctype-print
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_print($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
}
/**
* Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.
*
* @see https://php.net/ctype-punct
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_punct($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
}
/**
* Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.
*
* @see https://php.net/ctype-space
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_space($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
}
/**
* Returns TRUE if every character in text is an uppercase letter.
*
* @see https://php.net/ctype-upper
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_upper($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
}
/**
* Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
*
* @see https://php.net/ctype-xdigit
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_xdigit($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
}
/**
* Converts integers to their char versions according to normal ctype behaviour, if needed.
*
* If an integer between -128 and 255 inclusive is provided,
* it is interpreted as the ASCII value of a single character
* (negative values have 256 added in order to allow characters in the Extended ASCII range).
* Any other integer is interpreted as a string containing the decimal digits of the integer.
*
* @param mixed $int
* @param string $function
*
* @return mixed
*/
private static function convert_int_to_char_for_ctype($int, $function)
{
if (!\is_int($int)) {
return $int;
}
if ($int < -128 || $int > 255) {
return (string) $int;
}
if (\PHP_VERSION_ID >= 80100) {
@trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED);
}
if ($int < 0) {
$int += 256;
}
return \chr($int);
}
}

19
vendor/symfony/polyfill-ctype/LICENSE vendored Normale Datei
Datei anzeigen

@ -0,0 +1,19 @@
Copyright (c) 2018-2019 Fabien Potencier
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.

12
vendor/symfony/polyfill-ctype/README.md vendored Normale Datei
Datei anzeigen

@ -0,0 +1,12 @@
Symfony Polyfill / Ctype
========================
This component provides `ctype_*` functions to users who run php versions without the ctype extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

Datei anzeigen

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Ctype as p;
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (!function_exists('ctype_alnum')) {
function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
}
if (!function_exists('ctype_print')) {
function ctype_print($text) { return p\Ctype::ctype_print($text); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
}
if (!function_exists('ctype_space')) {
function ctype_space($text) { return p\Ctype::ctype_space($text); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
}

Datei anzeigen

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Ctype as p;
if (!function_exists('ctype_alnum')) {
function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); }
}
if (!function_exists('ctype_print')) {
function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); }
}
if (!function_exists('ctype_space')) {
function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); }
}

Datei anzeigen

@ -0,0 +1,41 @@
{
"name": "symfony/polyfill-ctype",
"type": "library",
"description": "Symfony polyfill for ctype functions",
"keywords": ["polyfill", "compatibility", "portable", "ctype"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Ctype\\": "" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-ctype": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

19
vendor/symfony/polyfill-mbstring/LICENSE vendored Normale Datei
Datei anzeigen

@ -0,0 +1,19 @@
Copyright (c) 2015-2019 Fabien Potencier
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.

Datei anzeigen

@ -0,0 +1,874 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Mbstring;
/**
* Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
*
* Implemented:
* - mb_chr - Returns a specific character from its Unicode code point
* - mb_convert_encoding - Convert character encoding
* - mb_convert_variables - Convert character code in variable(s)
* - mb_decode_mimeheader - Decode string in MIME header field
* - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
* - mb_decode_numericentity - Decode HTML numeric string reference to character
* - mb_encode_numericentity - Encode character to HTML numeric string reference
* - mb_convert_case - Perform case folding on a string
* - mb_detect_encoding - Detect character encoding
* - mb_get_info - Get internal settings of mbstring
* - mb_http_input - Detect HTTP input character encoding
* - mb_http_output - Set/Get HTTP output character encoding
* - mb_internal_encoding - Set/Get internal character encoding
* - mb_list_encodings - Returns an array of all supported encodings
* - mb_ord - Returns the Unicode code point of a character
* - mb_output_handler - Callback function converts character encoding in output buffer
* - mb_scrub - Replaces ill-formed byte sequences with substitute characters
* - mb_strlen - Get string length
* - mb_strpos - Find position of first occurrence of string in a string
* - mb_strrpos - Find position of last occurrence of a string in a string
* - mb_str_split - Convert a string to an array
* - mb_strtolower - Make a string lowercase
* - mb_strtoupper - Make a string uppercase
* - mb_substitute_character - Set/Get substitution character
* - mb_substr - Get part of string
* - mb_stripos - Finds position of first occurrence of a string within another, case insensitive
* - mb_stristr - Finds first occurrence of a string within another, case insensitive
* - mb_strrchr - Finds the last occurrence of a character in a string within another
* - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive
* - mb_strripos - Finds position of last occurrence of a string within another, case insensitive
* - mb_strstr - Finds first occurrence of a string within another
* - mb_strwidth - Return width of string
* - mb_substr_count - Count the number of substring occurrences
*
* Not implemented:
* - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
* - mb_ereg_* - Regular expression with multibyte support
* - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
* - mb_preferred_mime_name - Get MIME charset string
* - mb_regex_encoding - Returns current encoding for multibyte regex as string
* - mb_regex_set_options - Set/Get the default options for mbregex functions
* - mb_send_mail - Send encoded mail
* - mb_split - Split multibyte string using regular expression
* - mb_strcut - Get part of string
* - mb_strimwidth - Get truncated string with specified width
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
final class Mbstring
{
public const MB_CASE_FOLD = \PHP_INT_MAX;
private const CASE_FOLD = [
['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
];
private static $encodingList = ['ASCII', 'UTF-8'];
private static $language = 'neutral';
private static $internalEncoding = 'UTF-8';
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
{
if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
} else {
$fromEncoding = self::getEncoding($fromEncoding);
}
$toEncoding = self::getEncoding($toEncoding);
if ('BASE64' === $fromEncoding) {
$s = base64_decode($s);
$fromEncoding = $toEncoding;
}
if ('BASE64' === $toEncoding) {
return base64_encode($s);
}
if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
$fromEncoding = 'Windows-1252';
}
if ('UTF-8' !== $fromEncoding) {
$s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
}
return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
}
if ('HTML-ENTITIES' === $fromEncoding) {
$s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
$fromEncoding = 'UTF-8';
}
return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
}
public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
{
$ok = true;
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
$ok = false;
}
});
return $ok ? $fromEncoding : false;
}
public static function mb_decode_mimeheader($s)
{
return iconv_mime_decode($s, 2, self::$internalEncoding);
}
public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
{
trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
}
public static function mb_decode_numericentity($s, $convmap, $encoding = null)
{
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}
if (null !== $encoding && !\is_scalar($encoding)) {
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return ''; // Instead of null (cf. mb_encode_numericentity).
}
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
$cnt = floor(\count($convmap) / 4) * 4;
for ($i = 0; $i < $cnt; $i += 4) {
// collector_decode_htmlnumericentity ignores $convmap[$i + 3]
$convmap[$i] += $convmap[$i + 2];
$convmap[$i + 1] += $convmap[$i + 2];
}
$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
$c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
for ($i = 0; $i < $cnt; $i += 4) {
if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
return self::mb_chr($c - $convmap[$i + 2]);
}
}
return $m[0];
}, $s);
if (null === $encoding) {
return $s;
}
return iconv('UTF-8', $encoding.'//IGNORE', $s);
}
public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
{
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}
if (null !== $encoding && !\is_scalar($encoding)) {
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null; // Instead of '' (cf. mb_decode_numericentity).
}
if (null !== $is_hex && !\is_scalar($is_hex)) {
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
$cnt = floor(\count($convmap) / 4) * 4;
$i = 0;
$len = \strlen($s);
$result = '';
while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
$c = self::mb_ord($uchr);
for ($j = 0; $j < $cnt; $j += 4) {
if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
$cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
$result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
continue 2;
}
}
$result .= $uchr;
}
if (null === $encoding) {
return $result;
}
return iconv('UTF-8', $encoding.'//IGNORE', $result);
}
public static function mb_convert_case($s, $mode, $encoding = null)
{
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
if (\MB_CASE_TITLE == $mode) {
static $titleRegexp = null;
if (null === $titleRegexp) {
$titleRegexp = self::getData('titleCaseRegexp');
}
$s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
} else {
if (\MB_CASE_UPPER == $mode) {
static $upper = null;
if (null === $upper) {
$upper = self::getData('upperCase');
}
$map = $upper;
} else {
if (self::MB_CASE_FOLD === $mode) {
$s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
}
static $lower = null;
if (null === $lower) {
$lower = self::getData('lowerCase');
}
$map = $lower;
}
static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
$i = 0;
$len = \strlen($s);
while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
if (isset($map[$uchr])) {
$uchr = $map[$uchr];
$nlen = \strlen($uchr);
if ($nlen == $ulen) {
$nlen = $i;
do {
$s[--$nlen] = $uchr[--$ulen];
} while ($ulen);
} else {
$s = substr_replace($s, $uchr, $i - $ulen, $ulen);
$len += $nlen - $ulen;
$i += $nlen - $ulen;
}
}
}
}
if (null === $encoding) {
return $s;
}
return iconv('UTF-8', $encoding.'//IGNORE', $s);
}
public static function mb_internal_encoding($encoding = null)
{
if (null === $encoding) {
return self::$internalEncoding;
}
$normalizedEncoding = self::getEncoding($encoding);
if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
self::$internalEncoding = $normalizedEncoding;
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
public static function mb_language($lang = null)
{
if (null === $lang) {
return self::$language;
}
switch ($normalizedLang = strtolower($lang)) {
case 'uni':
case 'neutral':
self::$language = $normalizedLang;
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
}
public static function mb_list_encodings()
{
return ['UTF-8'];
}
public static function mb_encoding_aliases($encoding)
{
switch (strtoupper($encoding)) {
case 'UTF8':
case 'UTF-8':
return ['utf8'];
}
return false;
}
public static function mb_check_encoding($var = null, $encoding = null)
{
if (null === $encoding) {
if (null === $var) {
return false;
}
$encoding = self::$internalEncoding;
}
return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
}
public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
{
if (null === $encodingList) {
$encodingList = self::$encodingList;
} else {
if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);
}
foreach ($encodingList as $enc) {
switch ($enc) {
case 'ASCII':
if (!preg_match('/[\x80-\xFF]/', $str)) {
return $enc;
}
break;
case 'UTF8':
case 'UTF-8':
if (preg_match('//u', $str)) {
return 'UTF-8';
}
break;
default:
if (0 === strncmp($enc, 'ISO-8859-', 9)) {
return $enc;
}
}
}
return false;
}
public static function mb_detect_order($encodingList = null)
{
if (null === $encodingList) {
return self::$encodingList;
}
if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);
foreach ($encodingList as $enc) {
switch ($enc) {
default:
if (strncmp($enc, 'ISO-8859-', 9)) {
return false;
}
// no break
case 'ASCII':
case 'UTF8':
case 'UTF-8':
}
}
self::$encodingList = $encodingList;
return true;
}
public static function mb_strlen($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return \strlen($s);
}
return @iconv_strlen($s, $encoding);
}
public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strpos($haystack, $needle, $offset);
}
$needle = (string) $needle;
if ('' === $needle) {
if (80000 > \PHP_VERSION_ID) {
trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
return false;
}
return 0;
}
return iconv_strpos($haystack, $needle, $offset, $encoding);
}
public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strrpos($haystack, $needle, $offset);
}
if ($offset != (int) $offset) {
$offset = 0;
} elseif ($offset = (int) $offset) {
if ($offset < 0) {
if (0 > $offset += self::mb_strlen($needle)) {
$haystack = self::mb_substr($haystack, 0, $offset, $encoding);
}
$offset = 0;
} else {
$haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
}
}
$pos = '' !== $needle || 80000 > \PHP_VERSION_ID
? iconv_strrpos($haystack, $needle, $encoding)
: self::mb_strlen($haystack, $encoding);
return false !== $pos ? $offset + $pos : false;
}
public static function mb_str_split($string, $split_length = 1, $encoding = null)
{
if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
return null;
}
if (1 > $split_length = (int) $split_length) {
if (80000 > \PHP_VERSION_ID) {
trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
return false;
}
throw new \ValueError('Argument #2 ($length) must be greater than 0');
}
if (null === $encoding) {
$encoding = mb_internal_encoding();
}
if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
$rx = '/(';
while (65535 < $split_length) {
$rx .= '.{65535}';
$split_length -= 65535;
}
$rx .= '.{'.$split_length.'})/us';
return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
}
$result = [];
$length = mb_strlen($string, $encoding);
for ($i = 0; $i < $length; $i += $split_length) {
$result[] = mb_substr($string, $i, $split_length, $encoding);
}
return $result;
}
public static function mb_strtolower($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
}
public static function mb_strtoupper($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
}
public static function mb_substitute_character($c = null)
{
if (null === $c) {
return 'none';
}
if (0 === strcasecmp($c, 'none')) {
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
if (\is_int($c) || 'long' === $c || 'entity' === $c) {
return false;
}
throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
}
public static function mb_substr($s, $start, $length = null, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return (string) substr($s, $start, null === $length ? 2147483647 : $length);
}
if ($start < 0) {
$start = iconv_strlen($s, $encoding) + $start;
if ($start < 0) {
$start = 0;
}
}
if (null === $length) {
$length = 2147483647;
} elseif ($length < 0) {
$length = iconv_strlen($s, $encoding) + $length - $start;
if ($length < 0) {
return '';
}
}
return (string) iconv_substr($s, $start, $length, $encoding);
}
public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
return self::mb_strpos($haystack, $needle, $offset, $encoding);
}
public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
{
$pos = self::mb_stripos($haystack, $needle, 0, $encoding);
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
$pos = strrpos($haystack, $needle);
} else {
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = iconv_strrpos($haystack, $needle, $encoding);
}
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
{
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = self::mb_strripos($haystack, $needle, $encoding);
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
return self::mb_strrpos($haystack, $needle, $offset, $encoding);
}
public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
{
$pos = strpos($haystack, $needle);
if (false === $pos) {
return false;
}
if ($part) {
return substr($haystack, 0, $pos);
}
return substr($haystack, $pos);
}
public static function mb_get_info($type = 'all')
{
$info = [
'internal_encoding' => self::$internalEncoding,
'http_output' => 'pass',
'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
'func_overload' => 0,
'func_overload_list' => 'no overload',
'mail_charset' => 'UTF-8',
'mail_header_encoding' => 'BASE64',
'mail_body_encoding' => 'BASE64',
'illegal_chars' => 0,
'encoding_translation' => 'Off',
'language' => self::$language,
'detect_order' => self::$encodingList,
'substitute_character' => 'none',
'strict_detection' => 'Off',
];
if ('all' === $type) {
return $info;
}
if (isset($info[$type])) {
return $info[$type];
}
return false;
}
public static function mb_http_input($type = '')
{
return false;
}
public static function mb_http_output($encoding = null)
{
return null !== $encoding ? 'pass' === $encoding : 'pass';
}
public static function mb_strwidth($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('UTF-8' !== $encoding) {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
$s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);
return ($wide << 1) + iconv_strlen($s, 'UTF-8');
}
public static function mb_substr_count($haystack, $needle, $encoding = null)
{
return substr_count($haystack, $needle);
}
public static function mb_output_handler($contents, $status)
{
return $contents;
}
public static function mb_chr($code, $encoding = null)
{
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
}
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
}
return $s;
}
public static function mb_ord($s, $encoding = null)
{
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
}
if (1 === \strlen($s)) {
return \ord($s);
}
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $s[2] - 0x80;
}
return $code;
}
private static function getSubpart($pos, $part, $haystack, $encoding)
{
if (false === $pos) {
return false;
}
if ($part) {
return self::mb_substr($haystack, 0, $pos, $encoding);
}
return self::mb_substr($haystack, $pos, null, $encoding);
}
private static function html_encoding_callback(array $m)
{
$i = 1;
$entities = '';
$m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
while (isset($m[$i])) {
if (0x80 > $m[$i]) {
$entities .= \chr($m[$i++]);
continue;
}
if (0xF0 <= $m[$i]) {
$c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} elseif (0xE0 <= $m[$i]) {
$c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} else {
$c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
}
$entities .= '&#'.$c.';';
}
return $entities;
}
private static function title_case(array $s)
{
return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
}
private static function getData($file)
{
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
return require $file;
}
return false;
}
private static function getEncoding($encoding)
{
if (null === $encoding) {
return self::$internalEncoding;
}
if ('UTF-8' === $encoding) {
return 'UTF-8';
}
$encoding = strtoupper($encoding);
if ('8BIT' === $encoding || 'BINARY' === $encoding) {
return 'CP850';
}
if ('UTF8' === $encoding) {
return 'UTF-8';
}
return $encoding;
}
}

13
vendor/symfony/polyfill-mbstring/README.md vendored Normale Datei
Datei anzeigen

@ -0,0 +1,13 @@
Symfony Polyfill / Mbstring
===========================
This component provides a partial, native PHP implementation for the
[Mbstring](https://php.net/mbstring) extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,147 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Mbstring as p;
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language($language = null) { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); }
}
if (!function_exists('mb_convert_variables')) {
function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }
}
if (!function_exists('mb_ord')) {
function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}
if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}

Datei anzeigen

@ -0,0 +1,143 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Mbstring as p;
if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); }
}
if (!function_exists('mb_convert_variables')) {
function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }
}
if (!function_exists('mb_ord')) {
function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}
if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}

Datei anzeigen

@ -0,0 +1,41 @@
{
"name": "symfony/polyfill-mbstring",
"type": "library",
"description": "Symfony polyfill for the Mbstring extension",
"keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-mbstring": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

181
vendor/twig/twig/CHANGELOG vendored Normale Datei
Datei anzeigen

@ -0,0 +1,181 @@
# 3.7.0 (2023-07-26)
* Add support for the ...spread operator on arrays and hashes
# 3.6.1 (2023-06-08)
* Suppress some native return type deprecation messages
# 3.6.0 (2023-05-03)
* Allow psr/container 2.0
* Add the new PHP 8.0 IntlDateFormatter::RELATIVE_* constants for date formatting
* Make the Lexer initialize itself lazily
# 3.5.1 (2023-02-08)
* Arrow functions passed to the "reduce" filter now accept the current key as a third argument
* Restores the leniency of the matches twig comparison
* Fix error messages in sandboxed mode for "has some" and "has every"
# 3.5.0 (2022-12-27)
* Make Twig\ExpressionParser non-internal
* Add "has some" and "has every" operators
* Add Compile::reset()
* Throw a better runtime error when the "matches" regexp is not valid
* Add "twig *_names" intl functions
* Fix optimizing closures callbacks
* Add a better exception when getting an undefined constant via `constant`
* Fix `if` nodes when outside of a block and with an empty body
# 3.4.3 (2022-09-28)
* Fix a security issue on filesystem loader (possibility to load a template outside a configured directory)
# 3.4.2 (2022-08-12)
* Allow inherited magic method to still run with calling class
* Fix CallExpression::reflectCallable() throwing TypeError
* Fix typo in naming (currency_code)
# 3.4.1 (2022-05-17)
* Fix optimizing non-public named closures
# 3.4.0 (2022-05-22)
* Add support for named closures
# 3.3.10 (2022-04-06)
* Enable bytecode invalidation when auto_reload is enabled
# 3.3.9 (2022-03-25)
* Fix custom escapers when using multiple Twig environments
* Add support for "constant('class', object)"
* Do not reuse internally generated variable names during parsing
# 3.3.8 (2022-02-04)
* Fix a security issue when in a sandbox: the `sort` filter must require a Closure for the `arrow` parameter
* Fix deprecation notice on `round`
* Fix call to deprecated `convertToHtml` method
# 3.3.7 (2022-01-03)
* Allow more null support when Twig expects a string (for better 8.1 support)
* Only use Commonmark extensions if markdown enabled
# 3.3.6 (2022-01-03)
* Only use Commonmark extensions if markdown enabled
# 3.3.5 (2022-01-03)
* Allow CommonMark extensions to easily be added
* Allow null when Twig expects a string (for better 8.1 support)
* Make some performance optimizations
* Allow Symfony translation contract v3+
# 3.3.4 (2021-11-25)
* Bump minimum supported Symfony component versions
* Fix a deprecated message
# 3.3.3 (2021-09-17)
* Allow Symfony 6
* Improve compatibility with PHP 8.1
* Explicitly specify the encoding for mb_ord in JS escaper
# 3.3.2 (2021-05-16)
* Revert "Throw a proper exception when a template name is an absolute path (as it has never been supported)"
# 3.3.1 (2021-05-12)
* Fix PHP 8.1 compatibility
* Throw a proper exception when a template name is an absolute path (as it has never been supported)
# 3.3.0 (2021-02-08)
* Fix macro calls in a "cache" tag
* Add the slug filter
* Allow extra bundle to be compatible with Twig 2
# 3.2.1 (2021-01-05)
* Fix extra bundle compat with older versions of Symfony
# 3.2.0 (2021-01-05)
* Add the Cache extension in the "extra" repositories: "cache" tag
* Add "registerUndefinedTokenParserCallback"
* Mark built-in node visitors as @internal
* Fix "odd" not working for negative numbers
# 3.1.1 (2020-10-27)
* Fix "include(template_from_string())"
# 3.1.0 (2020-10-21)
* Fix sandbox support when using "include(template_from_string())"
* Make round brackets optional for one argument tests like "same as" or "divisible by"
* Add support for ES2015 style object initialisation shortcut { a } is the same as { 'a': a }
# 3.0.5 (2020-08-05)
* Fix twig_compare w.r.t. whitespace trimming
* Fix sandbox not disabled if syntax error occurs within {% sandbox %} tag
* Fix a regression when not using a space before an operator
* Restrict callables to closures in filters
* Allow trailing commas in argument lists (in calls as well as definitions)
# 3.0.4 (2020-07-05)
* Fix comparison operators
* Fix options not taken into account when using "Michelf\MarkdownExtra"
* Fix "Twig\Extra\Intl\IntlExtension::getCountryName()" to accept "null" as a first argument
* Throw exception in case non-Traversable data is passed to "filter"
* Fix context optimization on PHP 7.4
* Fix PHP 8 compatibility
* Fix ambiguous syntax parsing
# 3.0.3 (2020-02-11)
* Add a check to ensure that iconv() is defined
# 3.0.2 (2020-02-11)
* Avoid exceptions when an intl resource is not found
* Fix implementation of case-insensitivity for method names
# 3.0.1 (2019-12-28)
* fixed Symfony 5.0 support for the HTML extra extension
# 3.0.0 (2019-11-15)
* fixed number formatter in Intl extra extension when using a formatter prototype
# 3.0.0-BETA1 (2019-11-11)
* removed the "if" condition support on the "for" tag
* made the in, <, >, <=, >=, ==, and != operators more strict when comparing strings and integers/floats
* removed the "filter" tag
* added type hints everywhere
* changed Environment::resolveTemplate() to always return a TemplateWrapper instance
* removed Template::__toString()
* removed Parser::isReservedMacroName()
* removed SanboxedPrintNode
* removed Node::setTemplateName()
* made classes maked as "@final" final
* removed InitRuntimeInterface, ExistsLoaderInterface, and SourceContextLoaderInterface
* removed the "spaceless" tag
* removed Twig\Environment::getBaseTemplateClass() and Twig\Environment::setBaseTemplateClass()
* removed the "base_template_class" option on Twig\Environment
* bumped minimum PHP version to 7.2
* removed PSR-0 classes

27
vendor/twig/twig/LICENSE vendored Normale Datei
Datei anzeigen

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

23
vendor/twig/twig/README.rst vendored Normale Datei
Datei anzeigen

@ -0,0 +1,23 @@
Twig, the flexible, fast, and secure template language for PHP
==============================================================
Twig is a template language for PHP.
Twig uses a syntax similar to the Django and Jinja template languages which
inspired the Twig runtime environment.
Sponsors
--------
.. raw:: html
<a href="https://blackfire.io/docs/introduction?utm_source=twig&utm_medium=github_readme&utm_campaign=logo">
<img src="https://static.blackfire.io/assets/intemporals/logo/png/blackfire-io_secondary_horizontal_transparent.png?1" width="255px" alt="Blackfire.io">
</a>
More Information
----------------
Read the `documentation`_ for more information.
.. _documentation: https://twig.symfony.com/documentation

45
vendor/twig/twig/composer.json vendored Normale Datei
Datei anzeigen

@ -0,0 +1,45 @@
{
"name": "twig/twig",
"type": "library",
"description": "Twig, the flexible, fast, and secure template language for PHP",
"keywords": ["templating"],
"homepage": "https://twig.symfony.com",
"license": "BSD-3-Clause",
"minimum-stability": "dev",
"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"
}
],
"require": {
"php": ">=7.2.5",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0",
"psr/container": "^1.0|^2.0"
},
"autoload": {
"psr-4" : {
"Twig\\" : "src/"
}
},
"autoload-dev": {
"psr-4" : {
"Twig\\Tests\\" : "tests/"
}
}
}

Datei anzeigen

@ -0,0 +1,46 @@
<?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.
*/
namespace Twig\Cache;
/**
* 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 CacheInterface
{
/**
* Generates a cache key for the given template class name.
*/
public function generateKey(string $name, string $className): string;
/**
* Writes the compiled template to cache.
*
* @param string $content The template representation as a PHP class
*/
public function write(string $key, string $content): void;
/**
* Loads a template from the cache.
*/
public function load(string $key): void;
/**
* Returns the modification timestamp of a key.
*/
public function getTimestamp(string $key): int;
}

Datei anzeigen

@ -0,0 +1,87 @@
<?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.
*/
namespace Twig\Cache;
/**
* Implements a cache on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
class FilesystemCache implements CacheInterface
{
public const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
public function __construct(string $directory, int $options = 0)
{
$this->directory = rtrim($directory, '\/').'/';
$this->options = $options;
}
public function generateKey(string $name, string $className): string
{
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $className);
return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
public function load(string $key): void
{
if (is_file($key)) {
@include_once $key;
}
}
public function write(string $key, string $content): void
{
$dir = \dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
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') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) {
@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(string $key): int
{
if (!is_file($key)) {
return 0;
}
return (int) @filemtime($key);
}
}

38
vendor/twig/twig/src/Cache/NullCache.php vendored Normale Datei
Datei anzeigen

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

223
vendor/twig/twig/src/Compiler.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,223 @@
<?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.
*/
namespace Twig;
use Twig\Node\Node;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class Compiler
{
private $lastLine;
private $source;
private $indentation;
private $env;
private $debugInfo = [];
private $sourceOffset;
private $sourceLine;
private $varNameSalt = 0;
public function __construct(Environment $env)
{
$this->env = $env;
}
public function getEnvironment(): Environment
{
return $this->env;
}
public function getSource(): string
{
return $this->source;
}
/**
* @return $this
*/
public function reset(int $indentation = 0)
{
$this->lastLine = null;
$this->source = '';
$this->debugInfo = [];
$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;
return $this;
}
/**
* @return $this
*/
public function compile(Node $node, int $indentation = 0)
{
$this->reset($indentation);
$node->compile($this);
return $this;
}
/**
* @return $this
*/
public function subcompile(Node $node, bool $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.
*
* @return $this
*/
public function raw(string $string)
{
$this->source .= $string;
return $this;
}
/**
* Writes a string to the compiled code by adding indentation.
*
* @return $this
*/
public function write(...$strings)
{
foreach ($strings as $string) {
$this->source .= str_repeat(' ', $this->indentation * 4).$string;
}
return $this;
}
/**
* Adds a quoted string to the compiled code.
*
* @return $this
*/
public function string(string $value)
{
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
return $this;
}
/**
* Returns a PHP representation of a given value.
*
* @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(var_export($value, true));
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;
}
/**
* @return $this
*/
public function addDebugInfo(Node $node)
{
if ($node->getTemplateLine() != $this->lastLine) {
$this->write(sprintf("// line %d\n", $node->getTemplateLine()));
$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(): array
{
ksort($this->debugInfo);
return $this->debugInfo;
}
/**
* @return $this
*/
public function indent(int $step = 1)
{
$this->indentation += $step;
return $this;
}
/**
* @return $this
*
* @throws \LogicException When trying to outdent too much so the indentation would become negative
*/
public function outdent(int $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(): string
{
return sprintf('__internal_compile_%d', $this->varNameSalt++);
}
}

841
vendor/twig/twig/src/Environment.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,841 @@
<?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.
*/
namespace Twig;
use Twig\Cache\CacheInterface;
use Twig\Cache\FilesystemCache;
use Twig\Cache\NullCache;
use Twig\Error\Error;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Extension\CoreExtension;
use Twig\Extension\EscaperExtension;
use Twig\Extension\ExtensionInterface;
use Twig\Extension\OptimizerExtension;
use Twig\Loader\ArrayLoader;
use Twig\Loader\ChainLoader;
use Twig\Loader\LoaderInterface;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\RuntimeLoader\RuntimeLoaderInterface;
use Twig\TokenParser\TokenParserInterface;
/**
* Stores the Twig configuration and renders templates.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Environment
{
public const VERSION = '3.7.0';
public const VERSION_ID = 30700;
public const MAJOR_VERSION = 3;
public const MINOR_VERSION = 7;
public const RELEASE_VERSION = 0;
public const EXTRA_VERSION = '';
private $charset;
private $loader;
private $debug;
private $autoReload;
private $cache;
private $lexer;
private $parser;
private $compiler;
/** @var array<string, mixed> */
private $globals = [];
private $resolvedGlobals;
private $loadedTemplates;
private $strictVariables;
private $templateClassPrefix = '__TwigTemplate_';
private $originalCache;
private $extensionSet;
private $runtimeLoaders = [];
private $runtimes = [];
private $optionsHash;
/**
* Constructor.
*
* Available options:
*
* * debug: When set to true, it automatically set "auto_reload" to true as
* well (default to false).
*
* * charset: The charset used by the templates (default to UTF-8).
*
* * cache: An absolute path where to store the compiled templates,
* a \Twig\Cache\CacheInterface implementation,
* or false to disable compilation cache (default).
*
* * auto_reload: Whether to reload the template if the original source changed.
* If you don't provide the auto_reload option, it will be
* determined automatically based on the debug value.
*
* * strict_variables: Whether to ignore invalid variables in templates
* (default to false).
*
* * autoescape: Whether to enable auto-escaping (default to html):
* * false: disable auto-escaping
* * html, js: set the autoescaping to one of the supported strategies
* * name: set the autoescaping strategy based on the template name extension
* * PHP callback: a PHP callback that returns an escaping strategy based on the template "name"
*
* * optimizations: A flag that indicates which optimizations to apply
* (default to -1 which means that all optimizations are enabled;
* set it to 0 to disable).
*/
public function __construct(LoaderInterface $loader, $options = [])
{
$this->setLoader($loader);
$options = array_merge([
'debug' => false,
'charset' => 'UTF-8',
'strict_variables' => false,
'autoescape' => 'html',
'cache' => false,
'auto_reload' => null,
'optimizations' => -1,
], $options);
$this->debug = (bool) $options['debug'];
$this->setCharset($options['charset'] ?? 'UTF-8');
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
$this->strictVariables = (bool) $options['strict_variables'];
$this->setCache($options['cache']);
$this->extensionSet = new ExtensionSet();
$this->addExtension(new CoreExtension());
$this->addExtension(new EscaperExtension($options['autoescape']));
$this->addExtension(new OptimizerExtension($options['optimizations']));
}
/**
* Enables debugging mode.
*/
public function enableDebug()
{
$this->debug = true;
$this->updateOptionsHash();
}
/**
* Disables debugging mode.
*/
public function disableDebug()
{
$this->debug = false;
$this->updateOptionsHash();
}
/**
* Checks if debug mode is enabled.
*
* @return bool true if debug mode is enabled, false otherwise
*/
public function isDebug()
{
return $this->debug;
}
/**
* Enables the auto_reload option.
*/
public function enableAutoReload()
{
$this->autoReload = true;
}
/**
* Disables the auto_reload option.
*/
public function disableAutoReload()
{
$this->autoReload = false;
}
/**
* Checks if the auto_reload option is enabled.
*
* @return bool true if auto_reload is enabled, false otherwise
*/
public function isAutoReload()
{
return $this->autoReload;
}
/**
* Enables the strict_variables option.
*/
public function enableStrictVariables()
{
$this->strictVariables = true;
$this->updateOptionsHash();
}
/**
* Disables the strict_variables option.
*/
public function disableStrictVariables()
{
$this->strictVariables = false;
$this->updateOptionsHash();
}
/**
* Checks if the strict_variables option is enabled.
*
* @return bool true if strict_variables is enabled, false otherwise
*/
public function isStrictVariables()
{
return $this->strictVariables;
}
/**
* Gets the current cache implementation.
*
* @param bool $original Whether to return the original cache option or the real cache instance
*
* @return CacheInterface|string|false A Twig\Cache\CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function getCache($original = true)
{
return $original ? $this->originalCache : $this->cache;
}
/**
* Sets the current cache implementation.
*
* @param CacheInterface|string|false $cache A Twig\Cache\CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function setCache($cache)
{
if (\is_string($cache)) {
$this->originalCache = $cache;
$this->cache = new FilesystemCache($cache, $this->autoReload ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0);
} elseif (false === $cache) {
$this->originalCache = $cache;
$this->cache = new NullCache();
} elseif ($cache instanceof CacheInterface) {
$this->originalCache = $this->cache = $cache;
} else {
throw new \LogicException('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.');
}
}
/**
* Gets the template class associated with the given string.
*
* The generated template class is based on the following parameters:
*
* * The cache key for the given template;
* * The currently enabled extensions;
* * Whether the Twig C extension is available or not;
* * PHP version;
* * Twig version;
* * Options with what environment was created.
*
* @param string $name The name for which to calculate the template class name
* @param int|null $index The index if it is an embedded template
*
* @internal
*/
public function getTemplateClass(string $name, int $index = null): string
{
$key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
}
/**
* Renders a template.
*
* @param string|TemplateWrapper $name The template name
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
* @throws RuntimeError When an error occurred during rendering
*/
public function render($name, array $context = []): string
{
return $this->load($name)->render($context);
}
/**
* Displays a template.
*
* @param string|TemplateWrapper $name The template name
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
* @throws RuntimeError When an error occurred during rendering
*/
public function display($name, array $context = []): void
{
$this->load($name)->display($context);
}
/**
* Loads a template.
*
* @param string|TemplateWrapper $name The template name
*
* @throws LoaderError When the template cannot be found
* @throws RuntimeError When a previously generated cache is corrupted
* @throws SyntaxError When an error occurred during compilation
*/
public function load($name): TemplateWrapper
{
if ($name instanceof TemplateWrapper) {
return $name;
}
return new TemplateWrapper($this, $this->loadTemplate($this->getTemplateClass($name), $name));
}
/**
* Loads a template internal representation.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The template name
* @param int $index The index if it is an embedded template
*
* @throws LoaderError When the template cannot be found
* @throws RuntimeError When a previously generated cache is corrupted
* @throws SyntaxError When an error occurred during compilation
*
* @internal
*/
public function loadTemplate(string $cls, string $name, int $index = null): Template
{
$mainCls = $cls;
if (null !== $index) {
$cls .= '___'.$index;
}
if (isset($this->loadedTemplates[$cls])) {
return $this->loadedTemplates[$cls];
}
if (!class_exists($cls, false)) {
$key = $this->cache->generateKey($name, $mainCls);
if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
$this->cache->load($key);
}
$source = null;
if (!class_exists($cls, false)) {
$source = $this->getLoader()->getSourceContext($name);
$content = $this->compileSource($source);
$this->cache->write($key, $content);
$this->cache->load($key);
if (!class_exists($mainCls, false)) {
/* Last line of defense if either $this->bcWriteCacheFile was used,
* $this->cache is implemented as a no-op or we have a race condition
* where the cache was cleared between the above calls to write to and load from
* the cache.
*/
eval('?>'.$content);
}
if (!class_exists($cls, false)) {
throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
}
}
}
$this->extensionSet->initRuntime();
return $this->loadedTemplates[$cls] = new $cls($this);
}
/**
* Creates a template from source.
*
* This method should not be used as a generic way to load templates.
*
* @param string $template The template source
* @param string $name An optional name of the template to be used in error messages
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
*/
public function createTemplate(string $template, string $name = null): TemplateWrapper
{
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false);
if (null !== $name) {
$name = sprintf('%s (string template %s)', $name, $hash);
} else {
$name = sprintf('__string_template__%s', $hash);
}
$loader = new ChainLoader([
new ArrayLoader([$name => $template]),
$current = $this->getLoader(),
]);
$this->setLoader($loader);
try {
return new TemplateWrapper($this, $this->loadTemplate($this->getTemplateClass($name), $name));
} finally {
$this->setLoader($current);
}
}
/**
* Returns true if the template is still fresh.
*
* Besides checking the loader for freshness information,
* this method also checks if the enabled extensions have
* not changed.
*
* @param int $time The last modification time of the cached template
*/
public function isTemplateFresh(string $name, int $time): bool
{
return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time);
}
/**
* Tries to load a template consecutively from an array.
*
* Similar to load() but it also accepts instances of \Twig\Template and
* \Twig\TemplateWrapper, and an array of templates where each is tried to be loaded.
*
* @param string|TemplateWrapper|array $names A template or an array of templates to try consecutively
*
* @throws LoaderError When none of the templates can be found
* @throws SyntaxError When an error occurred during compilation
*/
public function resolveTemplate($names): TemplateWrapper
{
if (!\is_array($names)) {
return $this->load($names);
}
$count = \count($names);
foreach ($names as $name) {
if ($name instanceof Template) {
return $name;
}
if ($name instanceof TemplateWrapper) {
return $name;
}
if (1 !== $count && !$this->getLoader()->exists($name)) {
continue;
}
return $this->load($name);
}
throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
}
public function setLexer(Lexer $lexer)
{
$this->lexer = $lexer;
}
/**
* @throws SyntaxError When the code is syntactically wrong
*/
public function tokenize(Source $source): TokenStream
{
if (null === $this->lexer) {
$this->lexer = new Lexer($this);
}
return $this->lexer->tokenize($source);
}
public function setParser(Parser $parser)
{
$this->parser = $parser;
}
/**
* Converts a token stream to a node tree.
*
* @throws SyntaxError When the token stream is syntactically or semantically wrong
*/
public function parse(TokenStream $stream): ModuleNode
{
if (null === $this->parser) {
$this->parser = new Parser($this);
}
return $this->parser->parse($stream);
}
public function setCompiler(Compiler $compiler)
{
$this->compiler = $compiler;
}
/**
* Compiles a node and returns the PHP code.
*/
public function compile(Node $node): string
{
if (null === $this->compiler) {
$this->compiler = new Compiler($this);
}
return $this->compiler->compile($node)->getSource();
}
/**
* Compiles a template source code.
*
* @throws SyntaxError When there was an error during tokenizing, parsing or compiling
*/
public function compileSource(Source $source): string
{
try {
return $this->compile($this->parse($this->tokenize($source)));
} catch (Error $e) {
$e->setSourceContext($source);
throw $e;
} catch (\Exception $e) {
throw new SyntaxError(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
}
}
public function setLoader(LoaderInterface $loader)
{
$this->loader = $loader;
}
public function getLoader(): LoaderInterface
{
return $this->loader;
}
public function setCharset(string $charset)
{
if ('UTF8' === $charset = null === $charset ? null : strtoupper($charset)) {
// iconv on Windows requires "UTF-8" instead of "UTF8"
$charset = 'UTF-8';
}
$this->charset = $charset;
}
public function getCharset(): string
{
return $this->charset;
}
public function hasExtension(string $class): bool
{
return $this->extensionSet->hasExtension($class);
}
public function addRuntimeLoader(RuntimeLoaderInterface $loader)
{
$this->runtimeLoaders[] = $loader;
}
/**
* @template TExtension of ExtensionInterface
*
* @param class-string<TExtension> $class
*
* @return TExtension
*/
public function getExtension(string $class): ExtensionInterface
{
return $this->extensionSet->getExtension($class);
}
/**
* Returns the runtime implementation of a Twig element (filter/function/tag/test).
*
* @template TRuntime of object
*
* @param class-string<TRuntime> $class A runtime class name
*
* @return TRuntime The runtime implementation
*
* @throws RuntimeError When the template cannot be found
*/
public function getRuntime(string $class)
{
if (isset($this->runtimes[$class])) {
return $this->runtimes[$class];
}
foreach ($this->runtimeLoaders as $loader) {
if (null !== $runtime = $loader->load($class)) {
return $this->runtimes[$class] = $runtime;
}
}
throw new RuntimeError(sprintf('Unable to load the "%s" runtime.', $class));
}
public function addExtension(ExtensionInterface $extension)
{
$this->extensionSet->addExtension($extension);
$this->updateOptionsHash();
}
/**
* @param ExtensionInterface[] $extensions An array of extensions
*/
public function setExtensions(array $extensions)
{
$this->extensionSet->setExtensions($extensions);
$this->updateOptionsHash();
}
/**
* @return ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on)
*/
public function getExtensions(): array
{
return $this->extensionSet->getExtensions();
}
public function addTokenParser(TokenParserInterface $parser)
{
$this->extensionSet->addTokenParser($parser);
}
/**
* @return TokenParserInterface[]
*
* @internal
*/
public function getTokenParsers(): array
{
return $this->extensionSet->getTokenParsers();
}
/**
* @internal
*/
public function getTokenParser(string $name): ?TokenParserInterface
{
return $this->extensionSet->getTokenParser($name);
}
public function registerUndefinedTokenParserCallback(callable $callable): void
{
$this->extensionSet->registerUndefinedTokenParserCallback($callable);
}
public function addNodeVisitor(NodeVisitorInterface $visitor)
{
$this->extensionSet->addNodeVisitor($visitor);
}
/**
* @return NodeVisitorInterface[]
*
* @internal
*/
public function getNodeVisitors(): array
{
return $this->extensionSet->getNodeVisitors();
}
public function addFilter(TwigFilter $filter)
{
$this->extensionSet->addFilter($filter);
}
/**
* @internal
*/
public function getFilter(string $name): ?TwigFilter
{
return $this->extensionSet->getFilter($name);
}
public function registerUndefinedFilterCallback(callable $callable): void
{
$this->extensionSet->registerUndefinedFilterCallback($callable);
}
/**
* Gets the registered Filters.
*
* Be warned that this method cannot return filters defined with registerUndefinedFilterCallback.
*
* @return TwigFilter[]
*
* @see registerUndefinedFilterCallback
*
* @internal
*/
public function getFilters(): array
{
return $this->extensionSet->getFilters();
}
public function addTest(TwigTest $test)
{
$this->extensionSet->addTest($test);
}
/**
* @return TwigTest[]
*
* @internal
*/
public function getTests(): array
{
return $this->extensionSet->getTests();
}
/**
* @internal
*/
public function getTest(string $name): ?TwigTest
{
return $this->extensionSet->getTest($name);
}
public function addFunction(TwigFunction $function)
{
$this->extensionSet->addFunction($function);
}
/**
* @internal
*/
public function getFunction(string $name): ?TwigFunction
{
return $this->extensionSet->getFunction($name);
}
public function registerUndefinedFunctionCallback(callable $callable): void
{
$this->extensionSet->registerUndefinedFunctionCallback($callable);
}
/**
* Gets registered functions.
*
* Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
*
* @return TwigFunction[]
*
* @see registerUndefinedFunctionCallback
*
* @internal
*/
public function getFunctions(): array
{
return $this->extensionSet->getFunctions();
}
/**
* Registers a Global.
*
* New globals can be added before compiling or rendering a template;
* but after, you can only update existing globals.
*
* @param mixed $value The global value
*/
public function addGlobal(string $name, $value)
{
if ($this->extensionSet->isInitialized() && !\array_key_exists($name, $this->getGlobals())) {
throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
}
if (null !== $this->resolvedGlobals) {
$this->resolvedGlobals[$name] = $value;
} else {
$this->globals[$name] = $value;
}
}
/**
* @internal
*
* @return array<string, mixed>
*/
public function getGlobals(): array
{
if ($this->extensionSet->isInitialized()) {
if (null === $this->resolvedGlobals) {
$this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals);
}
return $this->resolvedGlobals;
}
return array_merge($this->extensionSet->getGlobals(), $this->globals);
}
public function mergeGlobals(array $context): array
{
// we don't use array_merge as the context being generally
// bigger than globals, this code is faster.
foreach ($this->getGlobals() as $key => $value) {
if (!\array_key_exists($key, $context)) {
$context[$key] = $value;
}
}
return $context;
}
/**
* @internal
*
* @return array<string, array{precedence: int, class: class-string<AbstractUnary>}>
*/
public function getUnaryOperators(): array
{
return $this->extensionSet->getUnaryOperators();
}
/**
* @internal
*
* @return array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
*/
public function getBinaryOperators(): array
{
return $this->extensionSet->getBinaryOperators();
}
private function updateOptionsHash(): void
{
$this->optionsHash = implode(':', [
$this->extensionSet->getSignature(),
\PHP_MAJOR_VERSION,
\PHP_MINOR_VERSION,
self::VERSION,
(int) $this->debug,
(int) $this->strictVariables,
]);
}
}

227
vendor/twig/twig/src/Error/Error.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,227 @@
<?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.
*/
namespace Twig\Error;
use Twig\Source;
use Twig\Template;
/**
* 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 Error extends \Exception
{
private $lineno;
private $name;
private $rawMessage;
private $sourcePath;
private $sourceCode;
/**
* Constructor.
*
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param int $lineno The template line where the error occurred
* @param Source|null $source The source context where the error occurred
*/
public function __construct(string $message, int $lineno = -1, Source $source = null, \Exception $previous = null)
{
parent::__construct('', 0, $previous);
if (null === $source) {
$name = null;
} else {
$name = $source->getName();
$this->sourceCode = $source->getCode();
$this->sourcePath = $source->getPath();
}
$this->lineno = $lineno;
$this->name = $name;
$this->rawMessage = $message;
$this->updateRepr();
}
public function getRawMessage(): string
{
return $this->rawMessage;
}
public function getTemplateLine(): int
{
return $this->lineno;
}
public function setTemplateLine(int $lineno): void
{
$this->lineno = $lineno;
$this->updateRepr();
}
public function getSourceContext(): ?Source
{
return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null;
}
public function setSourceContext(Source $source = null): void
{
if (null === $source) {
$this->sourceCode = $this->name = $this->sourcePath = null;
} else {
$this->sourceCode = $source->getCode();
$this->name = $source->getName();
$this->sourcePath = $source->getPath();
}
$this->updateRepr();
}
public function guess(): void
{
$this->guessTemplateInfo();
$this->updateRepr();
}
public function appendMessage($rawMessage): void
{
$this->rawMessage .= $rawMessage;
$this->updateRepr();
}
private function updateRepr(): void
{
$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->name) {
if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name, '__toString'))) {
$name = sprintf('"%s"', $this->name);
} else {
$name = json_encode($this->name);
}
$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 .= '?';
}
}
private function guessTemplateInfo(): void
{
$template = null;
$templateClass = null;
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT);
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Template) {
$currentClass = \get_class($trace['object']);
$isEmbedContainer = null === $templateClass ? false : 0 === strpos($templateClass, $currentClass);
if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
$template = $trace['object'];
$templateClass = \get_class($trace['object']);
}
}
}
// update template name
if (null !== $template && null === $this->name) {
$this->name = $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 = [$e = $this];
while ($e = $e->getPrevious()) {
$exceptions[] = $e;
}
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
array_unshift($traces, ['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;
}
}
}
}
}
}

21
vendor/twig/twig/src/Error/LoaderError.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,21 @@
<?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.
*/
namespace Twig\Error;
/**
* Exception thrown when an error occurs during template loading.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class LoaderError extends Error
{
}

Datei anzeigen

@ -0,0 +1,22 @@
<?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.
*/
namespace Twig\Error;
/**
* Exception thrown when an error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RuntimeError extends Error
{
}

46
vendor/twig/twig/src/Error/SyntaxError.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,46 @@
<?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.
*/
namespace Twig\Error;
/**
* \Exception thrown when a syntax error occurs during lexing or parsing of a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SyntaxError extends 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(string $name, array $items): void
{
$alternatives = [];
foreach ($items as $item) {
$lev = levenshtein($name, $item);
if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
$alternatives[$item] = $lev;
}
}
if (!$alternatives) {
return;
}
asort($alternatives);
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
}
}

842
vendor/twig/twig/src/ExpressionParser.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,842 @@
<?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.
*/
namespace Twig;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ArrowFunctionExpression;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Binary\ConcatBinary;
use Twig\Node\Expression\BlockReferenceExpression;
use Twig\Node\Expression\ConditionalExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\MethodCallExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\ParentExpression;
use Twig\Node\Expression\TestExpression;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\Node\Expression\Unary\NegUnary;
use Twig\Node\Expression\Unary\NotUnary;
use Twig\Node\Expression\Unary\PosUnary;
use Twig\Node\Node;
/**
* 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>
*/
class ExpressionParser
{
public const OPERATOR_LEFT = 1;
public const OPERATOR_RIGHT = 2;
private $parser;
private $env;
/** @var array<string, array{precedence: int, class: class-string<AbstractUnary>}> */
private $unaryOperators;
/** @var array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: self::OPERATOR_*}> */
private $binaryOperators;
public function __construct(Parser $parser, Environment $env)
{
$this->parser = $parser;
$this->env = $env;
$this->unaryOperators = $env->getUnaryOperators();
$this->binaryOperators = $env->getBinaryOperators();
}
public function parseExpression($precedence = 0, $allowArrow = false)
{
if ($allowArrow && $arrow = $this->parseArrow()) {
return $arrow;
}
$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 = $op['callable']($this->parser, $expr);
} else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence'], true);
$class = $op['class'];
$expr = new $class($expr, $expr1, $token->getLine());
}
$token = $this->parser->getCurrentToken();
}
if (0 === $precedence) {
return $this->parseConditionalExpression($expr);
}
return $expr;
}
/**
* @return ArrowFunctionExpression|null
*/
private function parseArrow()
{
$stream = $this->parser->getStream();
// short array syntax (one argument, no parentheses)?
if ($stream->look(1)->test(/* Token::ARROW_TYPE */ 12)) {
$line = $stream->getCurrent()->getLine();
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
$names = [new AssignNameExpression($token->getValue(), $token->getLine())];
$stream->expect(/* Token::ARROW_TYPE */ 12);
return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
}
// first, determine if we are parsing an arrow function by finding => (long form)
$i = 0;
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
return null;
}
++$i;
while (true) {
// variable name
++$i;
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
++$i;
}
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
return null;
}
++$i;
if (!$stream->look($i)->test(/* Token::ARROW_TYPE */ 12)) {
return null;
}
// yes, let's parse it properly
$token = $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(');
$line = $token->getLine();
$names = [];
while (true) {
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
$names[] = new AssignNameExpression($token->getValue(), $token->getLine());
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')');
$stream->expect(/* Token::ARROW_TYPE */ 12);
return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
}
private function getPrimary(): AbstractExpression
{
$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(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$this->parser->getStream()->next();
$expr = $this->parseExpression();
$this->parser->getStream()->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'An opened parenthesis is not properly closed');
return $this->parsePostfixExpression($expr);
}
return $this->parsePrimaryExpression();
}
private function parseConditionalExpression($expr): AbstractExpression
{
while ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, '?')) {
if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$expr2 = $this->parseExpression();
if ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$expr3 = $this->parseExpression();
} else {
$expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine());
}
} else {
$expr2 = $expr;
$expr3 = $this->parseExpression();
}
$expr = new ConditionalExpression($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
}
return $expr;
}
private function isUnary(Token $token): bool
{
return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->unaryOperators[$token->getValue()]);
}
private function isBinary(Token $token): bool
{
return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->binaryOperators[$token->getValue()]);
}
public function parsePrimaryExpression()
{
$token = $this->parser->getCurrentToken();
switch ($token->getType()) {
case /* Token::NAME_TYPE */ 5:
$this->parser->getStream()->next();
switch ($token->getValue()) {
case 'true':
case 'TRUE':
$node = new ConstantExpression(true, $token->getLine());
break;
case 'false':
case 'FALSE':
$node = new ConstantExpression(false, $token->getLine());
break;
case 'none':
case 'NONE':
case 'null':
case 'NULL':
$node = new ConstantExpression(null, $token->getLine());
break;
default:
if ('(' === $this->parser->getCurrentToken()->getValue()) {
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
} else {
$node = new NameExpression($token->getValue(), $token->getLine());
}
}
break;
case /* Token::NUMBER_TYPE */ 6:
$this->parser->getStream()->next();
$node = new ConstantExpression($token->getValue(), $token->getLine());
break;
case /* Token::STRING_TYPE */ 7:
case /* Token::INTERPOLATION_START_TYPE */ 10:
$node = $this->parseStringExpression();
break;
case /* Token::OPERATOR_TYPE */ 8:
if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
$node = new NameExpression($token->getValue(), $token->getLine());
break;
}
if (isset($this->unaryOperators[$token->getValue()])) {
$class = $this->unaryOperators[$token->getValue()]['class'];
if (!\in_array($class, [NegUnary::class, PosUnary::class])) {
throw new SyntaxError(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(/* Token::PUNCTUATION_TYPE */ 9, '[')) {
$node = $this->parseArrayExpression();
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) {
$node = $this->parseHashExpression();
} elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
throw new SyntaxError(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 SyntaxError(sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
}
return $this->parsePostfixExpression($node);
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = [];
// a string cannot be followed by another string in a single expression
$nextCanBeString = true;
while (true) {
if ($nextCanBeString && $token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) {
$nodes[] = new ConstantExpression($token->getValue(), $token->getLine());
$nextCanBeString = false;
} elseif ($stream->nextIf(/* Token::INTERPOLATION_START_TYPE */ 10)) {
$nodes[] = $this->parseExpression();
$stream->expect(/* Token::INTERPOLATION_END_TYPE */ 11);
$nextCanBeString = true;
} else {
break;
}
}
$expr = array_shift($nodes);
foreach ($nodes as $node) {
$expr = new ConcatBinary($expr, $node, $node->getTemplateLine());
}
return $expr;
}
public function parseArrayExpression()
{
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected');
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
if (!$first) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma');
// trailing ,?
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
break;
}
}
$first = false;
if ($stream->test(/* Token::SPREAD_TYPE */ 13)) {
$stream->next();
$expr = $this->parseExpression();
$expr->setAttribute('spread', true);
$node->addElement($expr);
} else {
$node->addElement($this->parseExpression());
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed');
return $node;
}
public function parseHashExpression()
{
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '{', 'A hash element was expected');
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
if (!$first) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma');
// trailing ,?
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
break;
}
}
$first = false;
if ($stream->test(/* Token::SPREAD_TYPE */ 13)) {
$stream->next();
$value = $this->parseExpression();
$value->setAttribute('spread', true);
$node->addElement($value);
continue;
}
// 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(/* Token::NAME_TYPE */ 5)) {
$key = new ConstantExpression($token->getValue(), $token->getLine());
// {a} is a shortcut for {a:a}
if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) {
$value = new NameExpression($key->getAttribute('value'), $key->getTemplateLine());
$node->addElement($value, $key);
continue;
}
} elseif (($token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) || $token = $stream->nextIf(/* Token::NUMBER_TYPE */ 6)) {
$key = new ConstantExpression($token->getValue(), $token->getLine());
} elseif ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$key = $this->parseExpression();
} else {
$current = $stream->getCurrent();
throw new SyntaxError(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".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ':', 'A hash key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed');
return $node;
}
public function parsePostfixExpression($node)
{
while (true) {
$token = $this->parser->getCurrentToken();
if (/* Token::PUNCTUATION_TYPE */ 9 == $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 SyntaxError('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
throw new SyntaxError('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
return new ParentExpression($this->parser->peekBlockStack(), $line);
case 'block':
$args = $this->parseArguments();
if (\count($args) < 1) {
throw new SyntaxError('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
}
return new BlockReferenceExpression($args->getNode(0), \count($args) > 1 ? $args->getNode(1) : null, $line);
case 'attribute':
$args = $this->parseArguments();
if (\count($args) < 2) {
throw new SyntaxError('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
}
return new GetAttrExpression($args->getNode(0), $args->getNode(1), \count($args) > 2 ? $args->getNode(2) : null, Template::ANY_CALL, $line);
default:
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
$arguments = new ArrayExpression([], $line);
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
$node = new MethodCallExpression($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 ArrayExpression([], $lineno);
$type = Template::ANY_CALL;
if ('.' == $token->getValue()) {
$token = $stream->next();
if (
/* Token::NAME_TYPE */ 5 == $token->getType()
||
/* Token::NUMBER_TYPE */ 6 == $token->getType()
||
(/* Token::OPERATOR_TYPE */ 8 == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new ConstantExpression($token->getValue(), $lineno);
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$type = Template::METHOD_CALL;
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
}
} else {
throw new SyntaxError(sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
}
if ($node instanceof NameExpression && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof ConstantExpression) {
throw new SyntaxError(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
}
$name = $arg->getAttribute('value');
$node = new MethodCallExpression($node, 'macro_'.$name, $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
}
} else {
$type = Template::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$slice = true;
$arg = new ConstantExpression(0, $token->getLine());
} else {
$arg = $this->parseExpression();
}
if ($stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$slice = true;
}
if ($slice) {
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
$length = new ConstantExpression(null, $token->getLine());
} else {
$length = $this->parseExpression();
}
$class = $this->getFilterNodeClass('slice', $token->getLine());
$arguments = new Node([$arg, $length]);
$filter = new $class($node, new ConstantExpression('slice', $token->getLine()), $arguments, $token->getLine());
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
return $filter;
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
}
return new GetAttrExpression($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(/* Token::NAME_TYPE */ 5);
$name = new ConstantExpression($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$arguments = new Node();
} else {
$arguments = $this->parseArguments(true, false, true);
}
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '|')) {
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 Node
*
* @throws SyntaxError
*/
public function parseArguments($namedArguments = false, $definition = false, $allowArrow = false)
{
$args = [];
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
if (!empty($args)) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'Arguments must be separated by a comma');
// if the comma above was a trailing comma, early exit the argument parse loop
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
break;
}
}
if ($definition) {
$token = $stream->expect(/* Token::NAME_TYPE */ 5, null, 'An argument must be a name');
$value = new NameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression(0, $allowArrow);
}
$name = null;
if ($namedArguments && $token = $stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) {
if (!$value instanceof NameExpression) {
throw new SyntaxError(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 SyntaxError('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(0, $allowArrow);
}
}
if ($definition) {
if (null === $name) {
$name = $value->getAttribute('name');
$value = new ConstantExpression(null, $this->parser->getCurrentToken()->getLine());
}
$args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'A list of arguments must be closed by a parenthesis');
return new Node($args);
}
public function parseAssignmentExpression()
{
$stream = $this->parser->getStream();
$targets = [];
while (true) {
$token = $this->parser->getCurrentToken();
if ($stream->test(/* Token::OPERATOR_TYPE */ 8) && preg_match(Lexer::REGEX_NAME, $token->getValue())) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
} else {
$stream->expect(/* Token::NAME_TYPE */ 5, null, 'Only variables can be assigned to');
}
$value = $token->getValue();
if (\in_array(strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), ['true', 'false', 'none', 'null'])) {
throw new SyntaxError(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
}
$targets[] = new AssignNameExpression($value, $token->getLine());
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
}
return new Node($targets);
}
public function parseMultitargetExpression()
{
$targets = [];
while (true) {
$targets[] = $this->parseExpression();
if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
}
return new Node($targets);
}
private function parseNotTestExpression(Node $node): NotUnary
{
return new NotUnary($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
}
private function parseTestExpression(Node $node): TestExpression
{
$stream = $this->parser->getStream();
list($name, $test) = $this->getTest($node->getTemplateLine());
$class = $this->getTestNodeClass($test);
$arguments = null;
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$arguments = $this->parseArguments(true);
} elseif ($test->hasOneMandatoryArgument()) {
$arguments = new Node([0 => $this->parsePrimaryExpression()]);
}
if ('defined' === $name && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) {
$node = new MethodCallExpression($alias['node'], $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine());
$node->setAttribute('safe', true);
}
return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
}
private function getTest(int $line): array
{
$stream = $this->parser->getStream();
$name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
if ($test = $this->env->getTest($name)) {
return [$name, $test];
}
if ($stream->test(/* Token::NAME_TYPE */ 5)) {
// try 2-words tests
$name = $name.' '.$this->parser->getCurrentToken()->getValue();
if ($test = $this->env->getTest($name)) {
$stream->next();
return [$name, $test];
}
}
$e = new SyntaxError(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getTests()));
throw $e;
}
private function getTestNodeClass(TwigTest $test): string
{
if ($test->isDeprecated()) {
$stream = $this->parser->getStream();
$message = sprintf('Twig Test "%s" is deprecated', $test->getName());
if ($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->getName(), $stream->getCurrent()->getLine());
@trigger_error($message, \E_USER_DEPRECATED);
}
return $test->getNodeClass();
}
private function getFunctionNodeClass(string $name, int $line): string
{
if (!$function = $this->env->getFunction($name)) {
$e = new SyntaxError(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFunctions()));
throw $e;
}
if ($function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if ($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->getName(), $line);
@trigger_error($message, \E_USER_DEPRECATED);
}
return $function->getNodeClass();
}
private function getFilterNodeClass(string $name, int $line): string
{
if (!$filter = $this->env->getFilter($name)) {
$e = new SyntaxError(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFilters()));
throw $e;
}
if ($filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if ($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->getName(), $line);
@trigger_error($message, \E_USER_DEPRECATED);
}
return $filter->getNodeClass();
}
// checks that the node only contains "constant" elements
private function checkConstantExpression(Node $node): bool
{
if (!($node instanceof ConstantExpression || $node instanceof ArrayExpression
|| $node instanceof NegUnary || $node instanceof PosUnary
)) {
return false;
}
foreach ($node as $n) {
if (!$this->checkConstantExpression($n)) {
return false;
}
}
return true;
}
}

Datei anzeigen

@ -0,0 +1,45 @@
<?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.
*/
namespace Twig\Extension;
abstract class AbstractExtension implements ExtensionInterface
{
public function getTokenParsers()
{
return [];
}
public function getNodeVisitors()
{
return [];
}
public function getFilters()
{
return [];
}
public function getTests()
{
return [];
}
public function getFunctions()
{
return [];
}
public function getOperators()
{
return [];
}
}

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@ -0,0 +1,64 @@
<?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.
*/
namespace Twig\Extension {
use Twig\TwigFunction;
final class DebugExtension extends AbstractExtension
{
public function getFunctions(): array
{
// 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 [
new TwigFunction('dump', 'twig_var_dump', ['is_safe' => $isDumpOutputHtmlSafe ? ['html'] : [], 'needs_context' => true, 'needs_environment' => true, 'is_variadic' => true]),
];
}
}
}
namespace {
use Twig\Environment;
use Twig\Template;
use Twig\TemplateWrapper;
function twig_var_dump(Environment $env, $context, ...$vars)
{
if (!$env->isDebug()) {
return;
}
ob_start();
if (!$vars) {
$vars = [];
foreach ($context as $key => $value) {
if (!$value instanceof Template && !$value instanceof TemplateWrapper) {
$vars[$key] = $value;
}
}
var_dump($vars);
} else {
var_dump(...$vars);
}
return ob_get_clean();
}
}

Datei anzeigen

@ -0,0 +1,416 @@
<?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.
*/
namespace Twig\Extension {
use Twig\FileExtensionEscapingStrategy;
use Twig\NodeVisitor\EscaperNodeVisitor;
use Twig\TokenParser\AutoEscapeTokenParser;
use Twig\TwigFilter;
final class EscaperExtension extends AbstractExtension
{
private $defaultStrategy;
private $escapers = [];
/** @internal */
public $safeClasses = [];
/** @internal */
public $safeLookup = [];
/**
* @param string|false|callable $defaultStrategy An escaping strategy
*
* @see setDefaultStrategy()
*/
public function __construct($defaultStrategy = 'html')
{
$this->setDefaultStrategy($defaultStrategy);
}
public function getTokenParsers(): array
{
return [new AutoEscapeTokenParser()];
}
public function getNodeVisitors(): array
{
return [new EscaperNodeVisitor()];
}
public function getFilters(): array
{
return [
new TwigFilter('escape', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
new TwigFilter('e', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
new TwigFilter('raw', 'twig_raw_filter', ['is_safe' => ['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): void
{
if ('name' === $defaultStrategy) {
$defaultStrategy = [FileExtensionEscapingStrategy::class, '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(string $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;
}
/**
* Defines a new escaper to be used via the escape filter.
*
* @param string $strategy The strategy name that should be used as a strategy in the escape call
* @param callable $callable A valid PHP callable
*/
public function setEscaper($strategy, callable $callable)
{
$this->escapers[$strategy] = $callable;
}
/**
* Gets all defined escapers.
*
* @return callable[] An array of escapers
*/
public function getEscapers()
{
return $this->escapers;
}
public function setSafeClasses(array $safeClasses = [])
{
$this->safeClasses = [];
$this->safeLookup = [];
foreach ($safeClasses as $class => $strategies) {
$this->addSafeClass($class, $strategies);
}
}
public function addSafeClass(string $class, array $strategies)
{
$class = ltrim($class, '\\');
if (!isset($this->safeClasses[$class])) {
$this->safeClasses[$class] = [];
}
$this->safeClasses[$class] = array_merge($this->safeClasses[$class], $strategies);
foreach ($strategies as $strategy) {
$this->safeLookup[$strategy][$class] = true;
}
}
}
}
namespace {
use Twig\Environment;
use Twig\Error\RuntimeError;
use Twig\Extension\EscaperExtension;
use Twig\Markup;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*/
function twig_raw_filter($string)
{
return $string;
}
/**
* Escapes a string.
*
* @param mixed $string The value to be escaped
* @param string $strategy The escaping strategy
* @param string $charset The charset
* @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
*
* @return string
*/
function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
{
if ($autoescape && $string instanceof Markup) {
return $string;
}
if (!\is_string($string)) {
if (\is_object($string) && method_exists($string, '__toString')) {
if ($autoescape) {
$c = \get_class($string);
$ext = $env->getExtension(EscaperExtension::class);
if (!isset($ext->safeClasses[$c])) {
$ext->safeClasses[$c] = [];
foreach (class_parents($string) + class_implements($string) as $class) {
if (isset($ext->safeClasses[$class])) {
$ext->safeClasses[$c] = array_unique(array_merge($ext->safeClasses[$c], $ext->safeClasses[$class]));
foreach ($ext->safeClasses[$class] as $s) {
$ext->safeLookup[$s][$c] = true;
}
}
}
}
if (isset($ext->safeLookup[$strategy][$c]) || isset($ext->safeLookup['all'][$c])) {
return (string) $string;
}
}
$string = (string) $string;
} elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) {
return $string;
}
}
if ('' === $string) {
return '';
}
if (null === $charset) {
$charset = $env->getCharset();
}
switch ($strategy) {
case 'html':
// see https://www.php.net/htmlspecialchars
// Using a static variable to avoid initializing the array
// each time the function is called. Moving the declaration on the
// top of the function slow downs other escaping strategies.
static $htmlspecialcharsCharsets = [
'ISO-8859-1' => true, 'ISO8859-1' => true,
'ISO-8859-15' => true, 'ISO8859-15' => true,
'utf-8' => true, 'UTF-8' => true,
'CP866' => true, 'IBM866' => true, '866' => true,
'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
'1251' => true,
'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
'BIG5' => true, '950' => true,
'GB2312' => true, '936' => true,
'BIG5-HKSCS' => true,
'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
'EUC-JP' => true, 'EUCJP' => true,
'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
];
if (isset($htmlspecialcharsCharsets[$charset])) {
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
}
if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
// cache the lowercase variant for future iterations
$htmlspecialcharsCharsets[$charset] = true;
return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
}
$string = twig_convert_encoding($string, 'UTF-8', $charset);
$string = htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8');
return iconv('UTF-8', $charset, $string);
case 'js':
// escape all non-alphanumeric characters
// into their \x or \uHHHH representations
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', function ($matches) {
$char = $matches[0];
/*
* A few characters have short escape sequences in JSON and JavaScript.
* Escape sequences supported only by JavaScript, not JSON, are omitted.
* \" is also supported but omitted, because the resulting string is not HTML safe.
*/
static $shortMap = [
'\\' => '\\\\',
'/' => '\\/',
"\x08" => '\b',
"\x0C" => '\f',
"\x0A" => '\n',
"\x0D" => '\r',
"\x09" => '\t',
];
if (isset($shortMap[$char])) {
return $shortMap[$char];
}
$codepoint = mb_ord($char, 'UTF-8');
if (0x10000 > $codepoint) {
return sprintf('\u%04X', $codepoint);
}
// Split characters outside the BMP into surrogate pairs
// https://tools.ietf.org/html/rfc2781.html#section-2.1
$u = $codepoint - 0x10000;
$high = 0xD800 | ($u >> 10);
$low = 0xDC00 | ($u & 0x3FF);
return sprintf('\u%04X\u%04X', $high, $low);
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'css':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9]#Su', function ($matches) {
$char = $matches[0];
return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : mb_ord($char, 'UTF-8'));
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'html_attr':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', function ($matches) {
/**
* This function is adapted from code coming from Zend Framework.
*
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com)
* @license https://framework.zend.com/license/new-bsd New BSD License
*/
$chr = $matches[0];
$ord = \ord($chr);
/*
* The following replaces characters undefined in HTML with the
* hex entity for the Unicode replacement character.
*/
if (($ord <= 0x1f && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7f && $ord <= 0x9f)) {
return '&#xFFFD;';
}
/*
* Check if the current character to escape has a name entity we should
* replace it with while grabbing the hex value of the character.
*/
if (1 === \strlen($chr)) {
/*
* While HTML supports far more named entities, the lowest common denominator
* has become HTML5's XML Serialisation which is restricted to the those named
* entities that XML supports. Using HTML entities would result in this error:
* XML Parsing Error: undefined entity
*/
static $entityMap = [
34 => '&quot;', /* quotation mark */
38 => '&amp;', /* ampersand */
60 => '&lt;', /* less-than sign */
62 => '&gt;', /* greater-than sign */
];
if (isset($entityMap[$ord])) {
return $entityMap[$ord];
}
return sprintf('&#x%02X;', $ord);
}
/*
* Per OWASP recommendations, we'll use hex entities for any other
* characters where a named entity does not exist.
*/
return sprintf('&#x%04X;', mb_ord($chr, 'UTF-8'));
}, $string);
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'url':
return rawurlencode($string);
default:
$escapers = $env->getExtension(EscaperExtension::class)->getEscapers();
if (array_key_exists($strategy, $escapers)) {
return $escapers[$strategy]($env, $string, $charset);
}
$validStrategies = implode(', ', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($escapers)));
throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
}
}
/**
* @internal
*/
function twig_escape_filter_is_safe(Node $filterArgs)
{
foreach ($filterArgs as $arg) {
if ($arg instanceof ConstantExpression) {
return [$arg->getAttribute('value')];
}
return [];
}
return ['html'];
}
}

Datei anzeigen

@ -0,0 +1,76 @@
<?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.
*/
namespace Twig\Extension;
use Twig\ExpressionParser;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
/**
* Interface implemented by extension classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ExtensionInterface
{
/**
* Returns the token parser instances to add to the existing list.
*
* @return TokenParserInterface[]
*/
public function getTokenParsers();
/**
* Returns the node visitor instances to add to the existing list.
*
* @return NodeVisitorInterface[]
*/
public function getNodeVisitors();
/**
* Returns a list of filters to add to the existing list.
*
* @return TwigFilter[]
*/
public function getFilters();
/**
* Returns a list of tests to add to the existing list.
*
* @return TwigTest[]
*/
public function getTests();
/**
* Returns a list of functions to add to the existing list.
*
* @return TwigFunction[]
*/
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
*
* @psalm-return array{
* array<string, array{precedence: int, class: class-string<AbstractUnary>}>,
* array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
* }
*/
public function getOperators();
}

Datei anzeigen

@ -0,0 +1,28 @@
<?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.
*/
namespace Twig\Extension;
/**
* Enables usage of the deprecated Twig\Extension\AbstractExtension::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 GlobalsInterface
{
/**
* @return array<string, mixed>
*/
public function getGlobals(): array;
}

Datei anzeigen

@ -0,0 +1,29 @@
<?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.
*/
namespace Twig\Extension;
use Twig\NodeVisitor\OptimizerNodeVisitor;
final class OptimizerExtension extends AbstractExtension
{
private $optimizers;
public function __construct(int $optimizers = -1)
{
$this->optimizers = $optimizers;
}
public function getNodeVisitors(): array
{
return [new OptimizerNodeVisitor($this->optimizers)];
}
}

Datei anzeigen

@ -0,0 +1,52 @@
<?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.
*/
namespace Twig\Extension;
use Twig\Profiler\NodeVisitor\ProfilerNodeVisitor;
use Twig\Profiler\Profile;
class ProfilerExtension extends AbstractExtension
{
private $actives = [];
public function __construct(Profile $profile)
{
$this->actives[] = $profile;
}
/**
* @return void
*/
public function enter(Profile $profile)
{
$this->actives[0]->addProfile($profile);
array_unshift($this->actives, $profile);
}
/**
* @return void
*/
public function leave(Profile $profile)
{
$profile->leave();
array_shift($this->actives);
if (1 === \count($this->actives)) {
$this->actives[0]->leave();
}
}
public function getNodeVisitors(): array
{
return [new ProfilerNodeVisitor(static::class)];
}
}

Datei anzeigen

@ -0,0 +1,19 @@
<?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.
*/
namespace Twig\Extension;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
interface RuntimeExtensionInterface
{
}

Datei anzeigen

@ -0,0 +1,123 @@
<?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.
*/
namespace Twig\Extension;
use Twig\NodeVisitor\SandboxNodeVisitor;
use Twig\Sandbox\SecurityNotAllowedMethodError;
use Twig\Sandbox\SecurityNotAllowedPropertyError;
use Twig\Sandbox\SecurityPolicyInterface;
use Twig\Source;
use Twig\TokenParser\SandboxTokenParser;
final class SandboxExtension extends AbstractExtension
{
private $sandboxedGlobally;
private $sandboxed;
private $policy;
public function __construct(SecurityPolicyInterface $policy, $sandboxed = false)
{
$this->policy = $policy;
$this->sandboxedGlobally = $sandboxed;
}
public function getTokenParsers(): array
{
return [new SandboxTokenParser()];
}
public function getNodeVisitors(): array
{
return [new SandboxNodeVisitor()];
}
public function enableSandbox(): void
{
$this->sandboxed = true;
}
public function disableSandbox(): void
{
$this->sandboxed = false;
}
public function isSandboxed(): bool
{
return $this->sandboxedGlobally || $this->sandboxed;
}
public function isSandboxedGlobally(): bool
{
return $this->sandboxedGlobally;
}
public function setSecurityPolicy(SecurityPolicyInterface $policy)
{
$this->policy = $policy;
}
public function getSecurityPolicy(): SecurityPolicyInterface
{
return $this->policy;
}
public function checkSecurity($tags, $filters, $functions): void
{
if ($this->isSandboxed()) {
$this->policy->checkSecurity($tags, $filters, $functions);
}
}
public function checkMethodAllowed($obj, $method, int $lineno = -1, Source $source = null): void
{
if ($this->isSandboxed()) {
try {
$this->policy->checkMethodAllowed($obj, $method);
} catch (SecurityNotAllowedMethodError $e) {
$e->setSourceContext($source);
$e->setTemplateLine($lineno);
throw $e;
}
}
}
public function checkPropertyAllowed($obj, $property, int $lineno = -1, Source $source = null): void
{
if ($this->isSandboxed()) {
try {
$this->policy->checkPropertyAllowed($obj, $property);
} catch (SecurityNotAllowedPropertyError $e) {
$e->setSourceContext($source);
$e->setTemplateLine($lineno);
throw $e;
}
}
}
public function ensureToStringAllowed($obj, int $lineno = -1, Source $source = null)
{
if ($this->isSandboxed() && \is_object($obj) && method_exists($obj, '__toString')) {
try {
$this->policy->checkMethodAllowed($obj, '__toString');
} catch (SecurityNotAllowedMethodError $e) {
$e->setSourceContext($source);
$e->setTemplateLine($lineno);
throw $e;
}
}
return $obj;
}
}

Datei anzeigen

@ -0,0 +1,100 @@
<?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.
*/
namespace Twig\Extension;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
/**
* Used by \Twig\Environment as a staging area.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
final class StagingExtension extends AbstractExtension
{
private $functions = [];
private $filters = [];
private $visitors = [];
private $tokenParsers = [];
private $tests = [];
public function addFunction(TwigFunction $function): void
{
if (isset($this->functions[$function->getName()])) {
throw new \LogicException(sprintf('Function "%s" is already registered.', $function->getName()));
}
$this->functions[$function->getName()] = $function;
}
public function getFunctions(): array
{
return $this->functions;
}
public function addFilter(TwigFilter $filter): void
{
if (isset($this->filters[$filter->getName()])) {
throw new \LogicException(sprintf('Filter "%s" is already registered.', $filter->getName()));
}
$this->filters[$filter->getName()] = $filter;
}
public function getFilters(): array
{
return $this->filters;
}
public function addNodeVisitor(NodeVisitorInterface $visitor): void
{
$this->visitors[] = $visitor;
}
public function getNodeVisitors(): array
{
return $this->visitors;
}
public function addTokenParser(TokenParserInterface $parser): void
{
if (isset($this->tokenParsers[$parser->getTag()])) {
throw new \LogicException(sprintf('Tag "%s" is already registered.', $parser->getTag()));
}
$this->tokenParsers[$parser->getTag()] = $parser;
}
public function getTokenParsers(): array
{
return $this->tokenParsers;
}
public function addTest(TwigTest $test): void
{
if (isset($this->tests[$test->getName()])) {
throw new \LogicException(sprintf('Test "%s" is already registered.', $test->getName()));
}
$this->tests[$test->getName()] = $test;
}
public function getTests(): array
{
return $this->tests;
}
}

Datei anzeigen

@ -0,0 +1,42 @@
<?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.
*/
namespace Twig\Extension {
use Twig\TwigFunction;
final class StringLoaderExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new TwigFunction('template_from_string', 'twig_template_from_string', ['needs_environment' => true]),
];
}
}
}
namespace {
use Twig\Environment;
use Twig\TemplateWrapper;
/**
* Loads a template from a string.
*
* {{ include(template_from_string("Hello {{ name }}")) }}
*
* @param string $template A template as a string or object implementing __toString()
* @param string $name An optional name of the template to be used in error messages
*/
function twig_template_from_string(Environment $env, $template, string $name = null): TemplateWrapper
{
return $env->createTemplate((string) $template, $name);
}
}

480
vendor/twig/twig/src/ExtensionSet.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,480 @@
<?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.
*/
namespace Twig;
use Twig\Error\RuntimeError;
use Twig\Extension\ExtensionInterface;
use Twig\Extension\GlobalsInterface;
use Twig\Extension\StagingExtension;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
final class ExtensionSet
{
private $extensions;
private $initialized = false;
private $runtimeInitialized = false;
private $staging;
private $parsers;
private $visitors;
/** @var array<string, TwigFilter> */
private $filters;
/** @var array<string, TwigTest> */
private $tests;
/** @var array<string, TwigFunction> */
private $functions;
/** @var array<string, array{precedence: int, class: class-string<AbstractUnary>}> */
private $unaryOperators;
/** @var array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}> */
private $binaryOperators;
/** @var array<string, mixed> */
private $globals;
private $functionCallbacks = [];
private $filterCallbacks = [];
private $parserCallbacks = [];
private $lastModified = 0;
public function __construct()
{
$this->staging = new StagingExtension();
}
public function initRuntime()
{
$this->runtimeInitialized = true;
}
public function hasExtension(string $class): bool
{
return isset($this->extensions[ltrim($class, '\\')]);
}
public function getExtension(string $class): ExtensionInterface
{
$class = ltrim($class, '\\');
if (!isset($this->extensions[$class])) {
throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class));
}
return $this->extensions[$class];
}
/**
* @param ExtensionInterface[] $extensions
*/
public function setExtensions(array $extensions): void
{
foreach ($extensions as $extension) {
$this->addExtension($extension);
}
}
/**
* @return ExtensionInterface[]
*/
public function getExtensions(): array
{
return $this->extensions;
}
public function getSignature(): string
{
return json_encode(array_keys($this->extensions));
}
public function isInitialized(): bool
{
return $this->initialized || $this->runtimeInitialized;
}
public function getLastModified(): int
{
if (0 !== $this->lastModified) {
return $this->lastModified;
}
foreach ($this->extensions as $extension) {
$r = new \ReflectionObject($extension);
if (is_file($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModified) {
$this->lastModified = $extensionTime;
}
}
return $this->lastModified;
}
public function addExtension(ExtensionInterface $extension): void
{
$class = \get_class($extension);
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
}
if (isset($this->extensions[$class])) {
throw new \LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class));
}
$this->extensions[$class] = $extension;
}
public function addFunction(TwigFunction $function): void
{
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
}
$this->staging->addFunction($function);
}
/**
* @return TwigFunction[]
*/
public function getFunctions(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->functions;
}
public function getFunction(string $name): ?TwigFunction
{
if (!$this->initialized) {
$this->initExtensions();
}
if (isset($this->functions[$name])) {
return $this->functions[$name];
}
foreach ($this->functions as $pattern => $function) {
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
array_shift($matches);
$function->setArguments($matches);
return $function;
}
}
foreach ($this->functionCallbacks as $callback) {
if (false !== $function = $callback($name)) {
return $function;
}
}
return null;
}
public function registerUndefinedFunctionCallback(callable $callable): void
{
$this->functionCallbacks[] = $callable;
}
public function addFilter(TwigFilter $filter): void
{
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
}
$this->staging->addFilter($filter);
}
/**
* @return TwigFilter[]
*/
public function getFilters(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->filters;
}
public function getFilter(string $name): ?TwigFilter
{
if (!$this->initialized) {
$this->initExtensions();
}
if (isset($this->filters[$name])) {
return $this->filters[$name];
}
foreach ($this->filters as $pattern => $filter) {
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
array_shift($matches);
$filter->setArguments($matches);
return $filter;
}
}
foreach ($this->filterCallbacks as $callback) {
if (false !== $filter = $callback($name)) {
return $filter;
}
}
return null;
}
public function registerUndefinedFilterCallback(callable $callable): void
{
$this->filterCallbacks[] = $callable;
}
public function addNodeVisitor(NodeVisitorInterface $visitor): void
{
if ($this->initialized) {
throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.');
}
$this->staging->addNodeVisitor($visitor);
}
/**
* @return NodeVisitorInterface[]
*/
public function getNodeVisitors(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->visitors;
}
public function addTokenParser(TokenParserInterface $parser): void
{
if ($this->initialized) {
throw new \LogicException('Unable to add a token parser as extensions have already been initialized.');
}
$this->staging->addTokenParser($parser);
}
/**
* @return TokenParserInterface[]
*/
public function getTokenParsers(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->parsers;
}
public function getTokenParser(string $name): ?TokenParserInterface
{
if (!$this->initialized) {
$this->initExtensions();
}
if (isset($this->parsers[$name])) {
return $this->parsers[$name];
}
foreach ($this->parserCallbacks as $callback) {
if (false !== $parser = $callback($name)) {
return $parser;
}
}
return null;
}
public function registerUndefinedTokenParserCallback(callable $callable): void
{
$this->parserCallbacks[] = $callable;
}
/**
* @return array<string, mixed>
*/
public function getGlobals(): array
{
if (null !== $this->globals) {
return $this->globals;
}
$globals = [];
foreach ($this->extensions as $extension) {
if (!$extension instanceof GlobalsInterface) {
continue;
}
$extGlobals = $extension->getGlobals();
if (!\is_array($extGlobals)) {
throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension)));
}
$globals = array_merge($globals, $extGlobals);
}
if ($this->initialized) {
$this->globals = $globals;
}
return $globals;
}
public function addTest(TwigTest $test): void
{
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
}
$this->staging->addTest($test);
}
/**
* @return TwigTest[]
*/
public function getTests(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->tests;
}
public function getTest(string $name): ?TwigTest
{
if (!$this->initialized) {
$this->initExtensions();
}
if (isset($this->tests[$name])) {
return $this->tests[$name];
}
foreach ($this->tests as $pattern => $test) {
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
if ($count) {
if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
array_shift($matches);
$test->setArguments($matches);
return $test;
}
}
}
return null;
}
/**
* @return array<string, array{precedence: int, class: class-string<AbstractUnary>}>
*/
public function getUnaryOperators(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->unaryOperators;
}
/**
* @return array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
*/
public function getBinaryOperators(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->binaryOperators;
}
private function initExtensions(): void
{
$this->parsers = [];
$this->filters = [];
$this->functions = [];
$this->tests = [];
$this->visitors = [];
$this->unaryOperators = [];
$this->binaryOperators = [];
foreach ($this->extensions as $extension) {
$this->initExtension($extension);
}
$this->initExtension($this->staging);
// Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
$this->initialized = true;
}
private function initExtension(ExtensionInterface $extension): void
{
// filters
foreach ($extension->getFilters() as $filter) {
$this->filters[$filter->getName()] = $filter;
}
// functions
foreach ($extension->getFunctions() as $function) {
$this->functions[$function->getName()] = $function;
}
// tests
foreach ($extension->getTests() as $test) {
$this->tests[$test->getName()] = $test;
}
// token parsers
foreach ($extension->getTokenParsers() as $parser) {
if (!$parser instanceof TokenParserInterface) {
throw new \LogicException('getTokenParsers() must return an array of \Twig\TokenParser\TokenParserInterface.');
}
$this->parsers[$parser->getTag()] = $parser;
}
// node visitors
foreach ($extension->getNodeVisitors() as $visitor) {
$this->visitors[] = $visitor;
}
// operators
if ($operators = $extension->getOperators()) {
if (!\is_array($operators)) {
throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators)));
}
if (2 !== \count($operators)) {
throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
}
$this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
$this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
}
}
}

Datei anzeigen

@ -0,0 +1,60 @@
<?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.
*/
namespace Twig;
/**
* 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 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(string $name)
{
if (\in_array(substr($name, -1), ['/', '\\'])) {
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';
}
}
}

519
vendor/twig/twig/src/Lexer.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,519 @@
<?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.
*/
namespace Twig;
use Twig\Error\SyntaxError;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class Lexer
{
private $isInitialized = false;
private $tokens;
private $code;
private $cursor;
private $lineno;
private $end;
private $state;
private $states;
private $brackets;
private $env;
private $source;
private $options;
private $regexes;
private $position;
private $positions;
private $currentVarBlockLine;
public const STATE_DATA = 0;
public const STATE_BLOCK = 1;
public const STATE_VAR = 2;
public const STATE_STRING = 3;
public const STATE_INTERPOLATION = 4;
public const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
public const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?([Ee][\+\-][0-9]+)?/A';
public const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
public const REGEX_DQ_STRING_DELIM = '/"/A';
public const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
public const PUNCTUATION = '()[]{}?:.,|';
public function __construct(Environment $env, array $options = [])
{
$this->env = $env;
$this->options = array_merge([
'tag_comment' => ['{#', '#}'],
'tag_block' => ['{%', '%}'],
'tag_variable' => ['{{', '}}'],
'whitespace_trim' => '-',
'whitespace_line_trim' => '~',
'whitespace_line_chars' => ' \t\0\x0B',
'interpolation' => ['#{', '}'],
], $options);
}
private function initialize()
{
if ($this->isInitialized) {
return;
}
$this->isInitialized = true;
// when PHP 7.3 is the min version, we will be able to remove the '#' part in preg_quote as it's part of the default
$this->regexes = [
// }}
'lex_var' => '{
\s*
(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '#').'\s*'. // -}}\s*
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_variable'][1], '#').'['.$this->options['whitespace_line_chars'].']*'. // ~}}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_variable'][1], '#'). // }}
')
}Ax',
// %}
'lex_block' => '{
\s*
(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '#').'\s*\n?'. // -%}\s*\n?
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_block'][1], '#').'['.$this->options['whitespace_line_chars'].']*'. // ~%}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_block'][1], '#').'\n?'. // %}\n?
')
}Ax',
// {% endverbatim %}
'lex_raw_data' => '{'.
preg_quote($this->options['tag_block'][0], '#'). // {%
'('.
$this->options['whitespace_trim']. // -
'|'.
$this->options['whitespace_line_trim']. // ~
')?\s*endverbatim\s*'.
'(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '#').'\s*'. // -%}
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_block'][1], '#').'['.$this->options['whitespace_line_chars'].']*'. // ~%}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_block'][1], '#'). // %}
')
}sx',
'operator' => $this->getOperatorRegex(),
// #}
'lex_comment' => '{
(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_comment'][1], '#').'\s*\n?'. // -#}\s*\n?
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_comment'][1], '#').'['.$this->options['whitespace_line_chars'].']*'. // ~#}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_comment'][1], '#').'\n?'. // #}\n?
')
}sx',
// verbatim %}
'lex_block_raw' => '{
\s*verbatim\s*
(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '#').'\s*'. // -%}\s*
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_block'][1], '#').'['.$this->options['whitespace_line_chars'].']*'. // ~%}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_block'][1], '#'). // %}
')
}Asx',
'lex_block_line' => '{\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '#').'}As',
// {{ or {% or {#
'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'], '#'). // -
'|'.
preg_quote($this->options['whitespace_line_trim'], '#'). // ~
')?
}sx',
'interpolation_start' => '{'.preg_quote($this->options['interpolation'][0], '#').'\s*}A',
'interpolation_end' => '{\s*'.preg_quote($this->options['interpolation'][1], '#').'}A',
];
}
public function tokenize(Source $source): TokenStream
{
$this->initialize();
$this->source = $source;
$this->code = str_replace(["\r\n", "\r"], "\n", $source->getCode());
$this->cursor = 0;
$this->lineno = 1;
$this->end = \strlen($this->code);
$this->tokens = [];
$this->state = self::STATE_DATA;
$this->states = [];
$this->brackets = [];
$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(/* Token::EOF_TYPE */ -1);
if (!empty($this->brackets)) {
list($expect, $lineno) = array_pop($this->brackets);
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
return new TokenStream($this->tokens, $this->source);
}
private function lexData(): void
{
// 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(/* Token::TEXT_TYPE */ 0, 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);
// trim?
if (isset($this->positions[2][$this->position][0])) {
if ($this->options['whitespace_trim'] === $this->positions[2][$this->position][0]) {
// whitespace_trim detected ({%-, {{- or {#-)
$text = rtrim($text);
} elseif ($this->options['whitespace_line_trim'] === $this->positions[2][$this->position][0]) {
// whitespace_line_trim detected ({%~, {{~ or {#~)
// don't trim \r and \n
$text = rtrim($text, " \t\0\x0B");
}
}
$this->pushToken(/* Token::TEXT_TYPE */ 0, $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, 0, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lexRawData();
// {% line \d+ %}
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, 0, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lineno = (int) $match[1];
} else {
$this->pushToken(/* Token::BLOCK_START_TYPE */ 1);
$this->pushState(self::STATE_BLOCK);
$this->currentVarBlockLine = $this->lineno;
}
break;
case $this->options['tag_variable'][0]:
$this->pushToken(/* Token::VAR_START_TYPE */ 2);
$this->pushState(self::STATE_VAR);
$this->currentVarBlockLine = $this->lineno;
break;
}
}
private function lexBlock(): void
{
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, 0, $this->cursor)) {
$this->pushToken(/* Token::BLOCK_END_TYPE */ 3);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
private function lexVar(): void
{
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, 0, $this->cursor)) {
$this->pushToken(/* Token::VAR_END_TYPE */ 4);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
private function lexExpression(): void
{
// whitespace
if (preg_match('/\s+/A', $this->code, $match, 0, $this->cursor)) {
$this->moveCursor($match[0]);
if ($this->cursor >= $this->end) {
throw new SyntaxError(sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
}
}
// spread operator
if ('.' === $this->code[$this->cursor] && ($this->cursor + 2 < $this->end) && '.' === $this->code[$this->cursor + 1] && '.' === $this->code[$this->cursor + 2]) {
$this->pushToken(Token::SPREAD_TYPE, '...');
$this->moveCursor('...');
}
// arrow function
elseif ('=' === $this->code[$this->cursor] && '>' === $this->code[$this->cursor + 1]) {
$this->pushToken(Token::ARROW_TYPE, '=>');
$this->moveCursor('=>');
}
// operators
elseif (preg_match($this->regexes['operator'], $this->code, $match, 0, $this->cursor)) {
$this->pushToken(/* Token::OPERATOR_TYPE */ 8, preg_replace('/\s+/', ' ', $match[0]));
$this->moveCursor($match[0]);
}
// names
elseif (preg_match(self::REGEX_NAME, $this->code, $match, 0, $this->cursor)) {
$this->pushToken(/* Token::NAME_TYPE */ 5, $match[0]);
$this->moveCursor($match[0]);
}
// numbers
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, 0, $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(/* Token::NUMBER_TYPE */ 6, $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[] = [$this->code[$this->cursor], $this->lineno];
}
// closing bracket
elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
if (empty($this->brackets)) {
throw new SyntaxError(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 SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
}
$this->pushToken(/* Token::PUNCTUATION_TYPE */ 9, $this->code[$this->cursor]);
++$this->cursor;
}
// strings
elseif (preg_match(self::REGEX_STRING, $this->code, $match, 0, $this->cursor)) {
$this->pushToken(/* Token::STRING_TYPE */ 7, 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, 0, $this->cursor)) {
$this->brackets[] = ['"', $this->lineno];
$this->pushState(self::STATE_STRING);
$this->moveCursor($match[0]);
}
// unlexable
else {
throw new SyntaxError(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
}
private function lexRawData(): void
{
if (!preg_match($this->regexes['lex_raw_data'], $this->code, $match, \PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new SyntaxError('Unexpected end of file: Unclosed "verbatim" block.', $this->lineno, $this->source);
}
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
$this->moveCursor($text.$match[0][0]);
// trim?
if (isset($match[1][0])) {
if ($this->options['whitespace_trim'] === $match[1][0]) {
// whitespace_trim detected ({%-, {{- or {#-)
$text = rtrim($text);
} else {
// whitespace_line_trim detected ({%~, {{~ or {#~)
// don't trim \r and \n
$text = rtrim($text, " \t\0\x0B");
}
}
$this->pushToken(/* Token::TEXT_TYPE */ 0, $text);
}
private function lexComment(): void
{
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, \PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new SyntaxError('Unclosed comment.', $this->lineno, $this->source);
}
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
}
private function lexString(): void
{
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, 0, $this->cursor)) {
$this->brackets[] = [$this->options['interpolation'][0], $this->lineno];
$this->pushToken(/* Token::INTERPOLATION_START_TYPE */ 10);
$this->moveCursor($match[0]);
$this->pushState(self::STATE_INTERPOLATION);
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, 0, $this->cursor) && \strlen($match[0]) > 0) {
$this->pushToken(/* Token::STRING_TYPE */ 7, stripcslashes($match[0]));
$this->moveCursor($match[0]);
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, 0, $this->cursor)) {
list($expect, $lineno) = array_pop($this->brackets);
if ('"' != $this->code[$this->cursor]) {
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
$this->popState();
++$this->cursor;
} else {
// unlexable
throw new SyntaxError(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
}
private function lexInterpolation(): void
{
$bracket = end($this->brackets);
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, 0, $this->cursor)) {
array_pop($this->brackets);
$this->pushToken(/* Token::INTERPOLATION_END_TYPE */ 11);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
private function pushToken($type, $value = ''): void
{
// do not push empty text tokens
if (/* Token::TEXT_TYPE */ 0 === $type && '' === $value) {
return;
}
$this->tokens[] = new Token($type, $value, $this->lineno);
}
private function moveCursor($text): void
{
$this->cursor += \strlen($text);
$this->lineno += substr_count($text, "\n");
}
private function getOperatorRegex(): string
{
$operators = array_merge(
['='],
array_keys($this->env->getUnaryOperators()),
array_keys($this->env->getBinaryOperators())
);
$operators = array_combine($operators, array_map('strlen', $operators));
arsort($operators);
$regex = [];
foreach ($operators as $operator => $length) {
// an operator that ends with a character must be followed by
// a whitespace, a parenthesis, an opening map [ or sequence {
$r = preg_quote($operator, '/');
if (ctype_alpha($operator[$length - 1])) {
$r .= '(?=[\s()\[{])';
}
// an operator that begins with a character must not have a dot or pipe before
if (ctype_alpha($operator[0])) {
$r = '(?<![\.\|])'.$r;
}
// an operator with a space can be any amount of whitespaces
$r = preg_replace('/\s+/', '\s+', $r);
$regex[] = $r;
}
return '/'.implode('|', $regex).'/A';
}
private function pushState($state): void
{
$this->states[] = $this->state;
$this->state = $state;
}
private function popState(): void
{
if (0 === \count($this->states)) {
throw new \LogicException('Cannot pop state without a previous state.');
}
$this->state = array_pop($this->states);
}
}

Datei anzeigen

@ -0,0 +1,77 @@
<?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.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* 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.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class ArrayLoader implements LoaderInterface
{
private $templates = [];
/**
* @param array $templates An array of templates (keys are the names, and values are the source code)
*/
public function __construct(array $templates = [])
{
$this->templates = $templates;
}
public function setTemplate(string $name, string $template): void
{
$this->templates[$name] = $template;
}
public function getSourceContext(string $name): Source
{
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
}
return new Source($this->templates[$name], $name);
}
public function exists(string $name): bool
{
return isset($this->templates[$name]);
}
public function getCacheKey(string $name): string
{
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
}
return $name.':'.$this->templates[$name];
}
public function isFresh(string $name, int $time): bool
{
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
}
return true;
}
}

119
vendor/twig/twig/src/Loader/ChainLoader.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,119 @@
<?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.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* Loads templates from other loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class ChainLoader implements LoaderInterface
{
private $hasSourceCache = [];
private $loaders = [];
/**
* @param LoaderInterface[] $loaders
*/
public function __construct(array $loaders = [])
{
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
public function addLoader(LoaderInterface $loader): void
{
$this->loaders[] = $loader;
$this->hasSourceCache = [];
}
/**
* @return LoaderInterface[]
*/
public function getLoaders(): array
{
return $this->loaders;
}
public function getSourceContext(string $name): Source
{
$exceptions = [];
foreach ($this->loaders as $loader) {
if (!$loader->exists($name)) {
continue;
}
try {
return $loader->getSourceContext($name);
} catch (LoaderError $e) {
$exceptions[] = $e->getMessage();
}
}
throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function exists(string $name): bool
{
if (isset($this->hasSourceCache[$name])) {
return $this->hasSourceCache[$name];
}
foreach ($this->loaders as $loader) {
if ($loader->exists($name)) {
return $this->hasSourceCache[$name] = true;
}
}
return $this->hasSourceCache[$name] = false;
}
public function getCacheKey(string $name): string
{
$exceptions = [];
foreach ($this->loaders as $loader) {
if (!$loader->exists($name)) {
continue;
}
try {
return $loader->getCacheKey($name);
} catch (LoaderError $e) {
$exceptions[] = \get_class($loader).': '.$e->getMessage();
}
}
throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function isFresh(string $name, int $time): bool
{
$exceptions = [];
foreach ($this->loaders as $loader) {
if (!$loader->exists($name)) {
continue;
}
try {
return $loader->isFresh($name, $time);
} catch (LoaderError $e) {
$exceptions[] = \get_class($loader).': '.$e->getMessage();
}
}
throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
}

Datei anzeigen

@ -0,0 +1,283 @@
<?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.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* Loads template from the filesystem.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FilesystemLoader implements LoaderInterface
{
/** Identifier of the main namespace. */
public const MAIN_NAMESPACE = '__main__';
protected $paths = [];
protected $cache = [];
protected $errorCache = [];
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 = [], string $rootPath = null)
{
$this->rootPath = (null === $rootPath ? getcwd() : $rootPath).\DIRECTORY_SEPARATOR;
if (null !== $rootPath && false !== ($realPath = realpath($rootPath))) {
$this->rootPath = $realPath.\DIRECTORY_SEPARATOR;
}
if ($paths) {
$this->setPaths($paths);
}
}
/**
* Returns the paths to the templates.
*/
public function getPaths(string $namespace = self::MAIN_NAMESPACE): array
{
return $this->paths[$namespace] ?? [];
}
/**
* Returns the path namespaces.
*
* The main namespace is always defined.
*/
public function getNamespaces(): array
{
return array_keys($this->paths);
}
/**
* @param string|array $paths A path or an array of paths where to look for templates
*/
public function setPaths($paths, string $namespace = self::MAIN_NAMESPACE): void
{
if (!\is_array($paths)) {
$paths = [$paths];
}
$this->paths[$namespace] = [];
foreach ($paths as $path) {
$this->addPath($path, $namespace);
}
}
/**
* @throws LoaderError
*/
public function addPath(string $path, string $namespace = self::MAIN_NAMESPACE): void
{
// invalidate the cache
$this->cache = $this->errorCache = [];
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new LoaderError(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
}
$this->paths[$namespace][] = rtrim($path, '/\\');
}
/**
* @throws LoaderError
*/
public function prependPath(string $path, string $namespace = self::MAIN_NAMESPACE): void
{
// invalidate the cache
$this->cache = $this->errorCache = [];
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new LoaderError(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 getSourceContext(string $name): Source
{
if (null === $path = $this->findTemplate($name)) {
return new Source('', $name, '');
}
return new Source(file_get_contents($path), $name, $path);
}
public function getCacheKey(string $name): string
{
if (null === $path = $this->findTemplate($name)) {
return '';
}
$len = \strlen($this->rootPath);
if (0 === strncmp($this->rootPath, $path, $len)) {
return substr($path, $len);
}
return $path;
}
/**
* @return bool
*/
public function exists(string $name)
{
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return true;
}
return null !== $this->findTemplate($name, false);
}
public function isFresh(string $name, int $time): bool
{
// false support to be removed in 3.0
if (null === $path = $this->findTemplate($name)) {
return false;
}
return filemtime($path) < $time;
}
/**
* @return string|null
*/
protected function findTemplate(string $name, bool $throw = true)
{
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return $this->cache[$name];
}
if (isset($this->errorCache[$name])) {
if (!$throw) {
return null;
}
throw new LoaderError($this->errorCache[$name]);
}
try {
list($namespace, $shortname) = $this->parseName($name);
$this->validateName($shortname);
} catch (LoaderError $e) {
if (!$throw) {
return null;
}
throw $e;
}
if (!isset($this->paths[$namespace])) {
$this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
if (!$throw) {
return null;
}
throw new LoaderError($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 null;
}
throw new LoaderError($this->errorCache[$name]);
}
private function normalizeName(string $name): string
{
return preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name));
}
private function parseName(string $name, string $default = self::MAIN_NAMESPACE): array
{
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new LoaderError(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$shortname = substr($name, $pos + 1);
return [$namespace, $shortname];
}
return [$default, $name];
}
private function validateName(string $name): void
{
if (false !== strpos($name, "\0")) {
throw new LoaderError('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 LoaderError(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
}
}
}
private function isAbsolutePath(string $file): bool
{
return strspn($file, '/\\', 0, 1)
|| (\strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === $file[1]
&& strspn($file, '/\\', 2, 1)
)
|| null !== parse_url($file, \PHP_URL_SCHEME)
;
}
}

Datei anzeigen

@ -0,0 +1,49 @@
<?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.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* Interface all loaders must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface LoaderInterface
{
/**
* Returns the source context for a given template logical name.
*
* @throws LoaderError When $name is not found
*/
public function getSourceContext(string $name): Source;
/**
* Gets the cache key to use for the cache for a given template name.
*
* @throws LoaderError When $name is not found
*/
public function getCacheKey(string $name): string;
/**
* @param int $time Timestamp of the last modification time of the cached template
*
* @throws LoaderError When $name is not found
*/
public function isFresh(string $name, int $time): bool;
/**
* @return bool
*/
public function exists(string $name);
}

52
vendor/twig/twig/src/Markup.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,52 @@
<?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.
*/
namespace Twig;
/**
* Marks a content as safe.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Markup implements \Countable, \JsonSerializable
{
private $content;
private $charset;
public function __construct($content, $charset)
{
$this->content = (string) $content;
$this->charset = $charset;
}
public function __toString()
{
return $this->content;
}
/**
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return mb_strlen($this->content, $this->charset);
}
/**
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->content;
}
}

Datei anzeigen

@ -0,0 +1,38 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* 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 AutoEscapeNode extends Node
{
public function __construct($value, Node $body, int $lineno, string $tag = 'autoescape')
{
parent::__construct(['body' => $body], ['value' => $value], $lineno, $tag);
}
public function compile(Compiler $compiler): void
{
$compiler->subcompile($this->getNode('body'));
}
}

44
vendor/twig/twig/src/Node/BlockNode.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,44 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a block node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class BlockNode extends Node
{
public function __construct(string $name, Node $body, int $lineno, string $tag = null)
{
parent::__construct(['body' => $body], ['name' => $name], $lineno, $tag);
}
public function compile(Compiler $compiler): void
{
$compiler
->addDebugInfo($this)
->write(sprintf("public function block_%s(\$context, array \$blocks = [])\n", $this->getAttribute('name')), "{\n")
->indent()
->write("\$macros = \$this->macros;\n")
;
$compiler
->subcompile($this->getNode('body'))
->outdent()
->write("}\n\n")
;
}
}

Datei anzeigen

@ -0,0 +1,36 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a block call node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class BlockReferenceNode extends Node implements NodeOutputInterface
{
public function __construct(string $name, int $lineno, string $tag = null)
{
parent::__construct([], ['name' => $name], $lineno, $tag);
}
public function compile(Compiler $compiler): void
{
$compiler
->addDebugInfo($this)
->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
;
}
}

21
vendor/twig/twig/src/Node/BodyNode.php vendored Normale Datei
Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,28 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class CheckSecurityCallNode extends Node
{
public function compile(Compiler $compiler)
{
$compiler
->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n")
->write("\$this->checkSecurity();\n")
;
}
}

Datei anzeigen

@ -0,0 +1,88 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class CheckSecurityNode extends Node
{
private $usedFilters;
private $usedTags;
private $usedFunctions;
public function __construct(array $usedFilters, array $usedTags, array $usedFunctions)
{
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
$this->usedFunctions = $usedFunctions;
parent::__construct();
}
public function compile(Compiler $compiler): void
{
$tags = $filters = $functions = [];
foreach (['tags', 'filters', 'functions'] as $type) {
foreach ($this->{'used'.ucfirst($type)} as $name => $node) {
if ($node instanceof Node) {
${$type}[$name] = $node->getTemplateLine();
} else {
${$type}[$node] = null;
}
}
}
$compiler
->write("\n")
->write("public function checkSecurity()\n")
->write("{\n")
->indent()
->write('static $tags = ')->repr(array_filter($tags))->raw(";\n")
->write('static $filters = ')->repr(array_filter($filters))->raw(";\n")
->write('static $functions = ')->repr(array_filter($functions))->raw(";\n\n")
->write("try {\n")
->indent()
->write("\$this->sandbox->checkSecurity(\n")
->indent()
->write(!$tags ? "[],\n" : "['".implode("', '", array_keys($tags))."'],\n")
->write(!$filters ? "[],\n" : "['".implode("', '", array_keys($filters))."'],\n")
->write(!$functions ? "[]\n" : "['".implode("', '", array_keys($functions))."']\n")
->outdent()
->write(");\n")
->outdent()
->write("} catch (SecurityError \$e) {\n")
->indent()
->write("\$e->setSourceContext(\$this->source);\n\n")
->write("if (\$e instanceof SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
->outdent()
->write("} elseif (\$e instanceof SecurityNotAllowedFilterError && isset(\$filters[\$e->getFilterName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n")
->outdent()
->write("} elseif (\$e instanceof 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")
->outdent()
->write("}\n")
;
}
}

Datei anzeigen

@ -0,0 +1,45 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
/**
* Checks if casting an expression to __toString() is allowed by the sandbox.
*
* For instance, when there is a simple Print statement, like {{ article }},
* and if the sandbox is enabled, we need to check that the __toString()
* method is allowed if 'article' is an object. The same goes for {{ article|upper }}
* or {{ random(article) }}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CheckToStringNode extends AbstractExpression
{
public function __construct(AbstractExpression $expr)
{
parent::__construct(['expr' => $expr], [], $expr->getTemplateLine(), $expr->getNodeTag());
}
public function compile(Compiler $compiler): void
{
$expr = $this->getNode('expr');
$compiler
->raw('$this->sandbox->ensureToStringAllowed(')
->subcompile($expr)
->raw(', ')
->repr($expr->getTemplateLine())
->raw(', $this->source)')
;
}
}

Datei anzeigen

@ -0,0 +1,53 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ConstantExpression;
/**
* Represents a deprecated node.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class DeprecatedNode extends Node
{
public function __construct(AbstractExpression $expr, int $lineno, string $tag = null)
{
parent::__construct(['expr' => $expr], [], $lineno, $tag);
}
public function compile(Compiler $compiler): void
{
$compiler->addDebugInfo($this);
$expr = $this->getNode('expr');
if ($expr instanceof ConstantExpression) {
$compiler->write('@trigger_error(')
->subcompile($expr);
} else {
$varName = $compiler->getVarName();
$compiler->write(sprintf('$%s = ', $varName))
->subcompile($expr)
->raw(";\n")
->write(sprintf('@trigger_error($%s', $varName));
}
$compiler
->raw('.')
->string(sprintf(' ("%s" at line %d).', $this->getTemplateName(), $this->getTemplateLine()))
->raw(", E_USER_DEPRECATED);\n")
;
}
}

38
vendor/twig/twig/src/Node/DoNode.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,38 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
/**
* Represents a do node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DoNode extends Node
{
public function __construct(AbstractExpression $expr, int $lineno, string $tag = null)
{
parent::__construct(['expr' => $expr], [], $lineno, $tag);
}
public function compile(Compiler $compiler): void
{
$compiler
->addDebugInfo($this)
->write('')
->subcompile($this->getNode('expr'))
->raw(";\n")
;
}
}

48
vendor/twig/twig/src/Node/EmbedNode.php vendored Normale Datei
Datei anzeigen

@ -0,0 +1,48 @@
<?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.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ConstantExpression;
/**
* Represents an embed node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class EmbedNode extends IncludeNode
{
// 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(string $name, int $index, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno, string $tag = null)
{
parent::__construct(new ConstantExpression('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
$this->setAttribute('name', $name);
$this->setAttribute('index', $index);
}
protected function addGetTemplate(Compiler $compiler): void
{
$compiler
->write('$this->loadTemplate(')
->string($this->getAttribute('name'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(', ')
->string($this->getAttribute('index'))
->raw(')')
;
}
}

Datei anzeigen

@ -0,0 +1,24 @@
<?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.
*/
namespace Twig\Node\Expression;
use Twig\Node\Node;
/**
* Abstract class for all nodes that represents an expression.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class AbstractExpression extends Node
{
}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen