diff --git a/.github/workflows/phplint.yml b/.github/workflows/phplint.yml new file mode 100644 index 0000000000..338efaa4bc --- /dev/null +++ b/.github/workflows/phplint.yml @@ -0,0 +1,16 @@ +name: PHP Linting +on: + pull_request: + branches: [master] + push: + branches: [master] + +jobs: + phplint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: overtrue/phplint@7.4 + with: + path: . + options: --exclude="system/libs/polyfill-mbstring/bootstrap80.php" diff --git a/.gitignore b/.gitignore index 26fed80c96..728dbd6123 100644 --- a/.gitignore +++ b/.gitignore @@ -3,16 +3,36 @@ Thumbs.db .idea # git rm --cached -r .idea +# composer +composer.lock +vendor + # npm node_modules +# cypress +cypress.env.json +cypress/e2e/2-advanced-examples + +# created by release.sh +releases +tmp + config.local.php -logs/ + +# all custom templates +templates/* +!templates/tibiacom +!templates/kathrine # guild images images/guilds/* !images/guilds/default.gif +# editor images +images/editor/* +!images/editor/index.html + # cache system/cache/* !system/cache/index.html @@ -27,7 +47,23 @@ system/php_sessions/* # logs system/logs/* !system/logs/index.html +logs/ # data system/data/* !system/data/index.html + +# plugins +plugins/* +!plugins/.htaccess +!plugins/example.json +!plugins/account-create-hint.json +!plugins/account-create-hint +!plugins/email-confirmed-reward.json +!plugins/email-confirmed-reward +!plugins/email-confirmed-reward.json +!plugins/email-confirmed-reward +landing + +# others/rest +system/pages/downloads.php diff --git a/.htaccess b/.htaccess.dist similarity index 100% rename from .htaccess rename to .htaccess.dist diff --git a/CHANGELOG.md b/CHANGELOG.md index 231975b419..9273b552fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,90 @@ # Changelog +## [0.8.10 - 18.05.2023] + +### Changed +* PHP 7.2.5 is now required, cause of Twig 2.x +* allow pages to be placed in templates folder, under pages/ subfolder + +### Fixed +* Twig error with global variable on create account +* links/redirects from facebook, etc. like ?fbclid=x +* do not allow to continue install when there is no server database imported +* cannot go forward when config.local.php cannot be saved +* when server uses another items serializer +* small bug on install + +## [0.8.9 - 16.03.2023] + +### Added +* You can now disable server status checking for testing purposes, useful for local testing when there is no server running + * with this, the page won't need 2 seconds to load + * set status_enabled to false in config.php +* new buttons code for tibiacom template, can create button with any text +* patched some small changes from develop branch + +### Changed +* add .git to denied folders in nginx-sample.conf +* plugins folder is now accessible from outside +* add plugins folder to twig search paths + +### Fixed +* player save with new ipv6 +* more php 8.x compatibility +* rel path for exception message, causing message to be not in red background + +## [0.8.8 - 18.02.2023] + +### Added +* mail confirmed reward +* support for latest group changes in TFS +* new function: escapeHtml + +### Updated +* TinyMCE to v4.9.1 (latest release in 4.x series) +* Twig to v2.15.4 + +### Changed +* you can now place custom pages in your template directory under pages/ folder +* HOOK_LOGOUT parameters, now only account_id is passed + +### Fixed +* ipv6 introduced in latest TFS +* config.account_premium_days +* better compatibility with GesiorAAC +* PHP 8.1 compatibility +* myaac_ db table detection failure +* reload creatures error, when items cache has been cleared + +### Removed +* accounts.blocked column, which is not used by AAC + +## [0.8.7 - 31.08.2022] +### Added +* login.php for client 12.x is now part of official repo +* browsehappy code +* config use character sample skill (#201, @gpedro) +* custom words blocked (#190, @gpedro) + +### Changed +* save php sessions in myaac dir +* don't count deleted players when creating new character + +### Fixed +* patch vulnerability in change_rank.php (#194, @gesior, @thatmichaelguy) +* fix guild invite page (#196, @worthdavi) +* players not showing on highscores page (#195) +* highscores page bug with high pages +* $player->getStorage() does not work at all (#169, @gesior) +* copying sample character when it have items with quotes (#200, @gpedro) +* IPv6 issue when env is set to dev (#171) +* admin page changed feet to match body colour (#174, @silic0nalph4) +* exception being thrown when creating duplicated character name (#191) +* rules page formatting (#177, @silic0nalph4) +* account character create if auto_login is enabled +* undefined variable notice on database_log enabled +* removed VERSION file + ## [0.8.6 - 10.07.2021] This update contains very important security fix. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt new file mode 100644 index 0000000000..3adb1e5f82 --- /dev/null +++ b/CONTRIBUTORS.txt @@ -0,0 +1,9 @@ +# automatically exported using this script: +# git log --all --format='%cN <%cE>' | sort -u > contributors +# in no particular order +# cleaned for readability + +Elson Costa +Majesty <32709570+majestyotbr@users.noreply.github.com> +lucaslking +slawkens diff --git a/CREDITS b/CREDITS index 50461327fa..0d69a4050a 100644 --- a/CREDITS +++ b/CREDITS @@ -1,2 +1,3 @@ * Gesior.pl (2007 - 2008) * Slawkens (2009 - 2020) +* Contributors listed in CONTRIBUTORS.txt diff --git a/VERSION b/VERSION deleted file mode 100644 index 7fc2521fd7..0000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.8.6 diff --git a/admin/index.php b/admin/index.php index 4a34f7d347..05e2d58d51 100644 --- a/admin/index.php +++ b/admin/index.php @@ -1,27 +1,25 @@ - - install/ directory exists. Please visit this url to start MyAAC Installation.
Delete install/ directory if you already installed MyAAC.
Remember to REFRESH this page when you\'re done!'); +if (file_exists(BASE . 'config.local.php')) { + require_once BASE . 'config.local.php'; } -define('ADMIN_PANEL', true); +if (file_exists(BASE . 'install') && (!isset($config['installed']) || !$config['installed'])) { + header('Location: ' . BASE_URL . 'install/'); + throw new RuntimeException('Setup detected that install/ directory exists. Please visit this url to start MyAAC Installation.
Delete install/ directory if you already installed MyAAC.
Remember to REFRESH this page when you\'re done!'); +} $content = ''; // validate page $page = isset($_GET['p']) ? $_GET['p'] : ''; -if(empty($page) || preg_match("/[^a-zA-Z0-9_\-]/", $page)) - $page = 'dashboard'; +if (empty($page) || preg_match("/[^a-zA-Z0-9_\-]/", $page)) + $page = 'dashboard'; $page = strtolower($page); define('PAGE', $page); @@ -29,10 +27,10 @@ require SYSTEM . 'functions.php'; require SYSTEM . 'init.php'; -if(config('env') === 'dev') { - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); +if (config('env') === 'dev') { + ini_set('display_errors', 1); + ini_set('display_startup_errors', 1); + error_reporting(E_ALL); } // event system @@ -49,15 +47,15 @@ $twig->addGlobal('status', $status); // if we're not logged in - show login box -if(!$logged || !admin()) { - $page = 'login'; +if (!$logged || !admin()) { + $page = 'login'; } // include our page $file = ADMIN . 'pages/' . $page . '.php'; -if(!@file_exists($file)) { - $page = '404'; - $file = SYSTEM . 'pages/404.php'; +if (!@file_exists($file)) { + $page = '404'; + $file = SYSTEM . 'pages/404.php'; } ob_start(); @@ -71,7 +69,7 @@ require ADMIN . $template_path . 'template.php'; ?> - - - - \ No newline at end of file + + + + diff --git a/admin/pages/accounts.php b/admin/pages/accounts.php index 21e58771a9..a1339defa6 100644 --- a/admin/pages/accounts.php +++ b/admin/pages/accounts.php @@ -272,11 +272,15 @@ class="form-horizontal col-md-8">
- getAccGroupId(); - if ($hasTypeColumn) { - $acc_type = array("Normal", "Tutor", "Senior Tutor", "Gamemaster", "God"); ?> -
+ getAccGroupId(); + if ($hasTypeColumn) { + $groups = new OTS_Groups_List(); + $acc_type = ($groups->getHighestId() == 6) + ? ["Normal", "Tutor", "Senior Tutor", "Gamemaster", "Community Manager", "God"] + : ["Normal", "Tutor", "Senior Tutor", "Gamemaster", "God"]; + ?> +
+ echo '
  • - + - +
  • '; $i++; @@ -134,4 +134,4 @@ $twig->display('admin.menus.form.html.twig', array( 'templates' => $templates )); -} \ No newline at end of file +} diff --git a/admin/pages/news.php b/admin/pages/news.php index 8838780a2f..20c2bbb89d 100644 --- a/admin/pages/news.php +++ b/admin/pages/news.php @@ -117,7 +117,7 @@ 'news_link_form' => '?p=news&action=' . ($action == 'edit' ? 'edit' : 'add'), 'news_id' => isset($id) ? $id : null, 'title' => isset($p_title) ? $p_title : '', - 'body' => isset($body) ? htmlentities($body, ENT_COMPAT, 'UTF-8') : '', + 'body' => isset($body) ? escapeHtml($body) : '', 'type' => isset($type) ? $type : null, 'player' => isset($player) && $player->isLoaded() ? $player : null, 'player_id' => isset($player_id) ? $player_id : null, diff --git a/admin/pages/pages.php b/admin/pages/pages.php index 50ae59f4a6..68ca1d984d 100644 --- a/admin/pages/pages.php +++ b/admin/pages/pages.php @@ -105,7 +105,7 @@ 'title' => $p_title, 'php' => $php, 'enable_tinymce' => $enable_tinymce, - 'body' => isset($body) ? htmlentities($body, ENT_COMPAT, 'UTF-8') : '', + 'body' => isset($body) ? escapeHtml($body) : '', 'groups' => $groups->getGroups(), 'access' => $access )); diff --git a/admin/pages/players.php b/admin/pages/players.php index d49d1d4045..0a8a9260fb 100644 --- a/admin/pages/players.php +++ b/admin/pages/players.php @@ -332,9 +332,9 @@ function verify_number($number, $name, $max_length)
    - - - + + +
    - -
    + +
    hasColumn('players', 'loss_experience')): ?>
    @@ -892,4 +893,4 @@ function updateOutfit() $("#player_outfit").attr("src", new_outfit); console.log(new_outfit); } - \ No newline at end of file + diff --git a/admin/tools/phpinfo.php b/admin/tools/phpinfo.php index 5b791d0787..c2990df8ec 100644 --- a/admin/tools/phpinfo.php +++ b/admin/tools/phpinfo.php @@ -1,14 +1,16 @@ diff --git a/admin/tools/status.php b/admin/tools/status.php index 7d0a77abea..a2a65a85ae 100644 --- a/admin/tools/status.php +++ b/admin/tools/status.php @@ -1,21 +1,22 @@ -Server:
    -Version:

    - -Monsters:
    -Map: , author: , size:
    -MOTD:

    - -Last check: +Server:
    +Version:

    +Monsters:
    +Map: , author: , +size:
    +MOTD:

    +Last check: diff --git a/common.php b/common.php index a263f686b3..96b1ee0fec 100644 --- a/common.php +++ b/common.php @@ -23,11 +23,11 @@ * @copyright 2019 MyAAC * @link https://my-aac.org */ -if (version_compare(phpversion(), '5.6', '<')) die('PHP version 5.6 or higher is required.'); +if (version_compare(phpversion(), '7.2.5', '<')) die('PHP version 7.2.5 or higher is required.'); define('MYAAC', true); -define('MYAAC_VERSION', '0.8.6'); -define('DATABASE_VERSION', 33); +define('MYAAC_VERSION', '0.8.10'); +define('DATABASE_VERSION', 34); define('TABLE_PREFIX', 'myaac_'); define('START_TIME', microtime(true)); define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX')); @@ -86,8 +86,10 @@ define('TFS_FIRST', TFS_02); define('TFS_LAST', TFS_03); -session_save_path(SYSTEM . 'php_sessions'); -session_start(); +if (!IS_CLI) { + session_save_path(SYSTEM . 'php_sessions'); + session_start(); +} // basedir $basedir = ''; diff --git a/config.php b/config.php index 2c3b31918e..ea356b1d54 100644 --- a/config.php +++ b/config.php @@ -96,6 +96,13 @@ 'account_create_auto_login' => false, // auto login after creating account? 'account_create_character_create' => true, // allow directly to create character on create account page? 'account_mail_verify' => false, // force users to confirm their email addresses when registering account + 'account_mail_confirmed_reward' => [ // reward users for confirming their E-Mails + // account_mail_verify needs to be enabled too + 'premium_days' => 0, + 'premium_points' => 0, + 'coins' => 0, + 'message' => 'You received %d %s for confirming your E-Mail address.' // example: You received 20 coins for confirming your E-Mail address. + ], 'account_mail_unique' => true, // email addresses cannot be duplicated? (one account = one email) 'account_premium_days' => 0, // default premium days on new account 'account_premium_points' => 0, // default premium points on new account @@ -168,6 +175,8 @@ 4 => 'Knight Sample' ), + 'use_character_sample_skills' => false, + // it must show limited number of players after using search in character page 'characters_search_limit' => 15, @@ -336,6 +345,7 @@ 'last_kills_limit' => 50, // max. number of deaths shown on the last kills page // status, took automatically from config file if empty + 'status_enabled' => true, // you can disable status checking by settings this to "false" 'status_ip' => '', 'status_port' => '', 'status_timeout' => 2, // how long to wait for the initial response from the server (default: 2 seconds) @@ -357,5 +367,12 @@ 'date_timezone' => 'Europe/Berlin', // more info at http://php.net/manual/en/timezones.php 'footer_show_load_time' => true, // display load time of the page in the footer - 'npc' => array() + 'npc' => [], + + // character name blocked + 'character_name_blocked' => [ + 'prefix' => [], + 'names' => [], + 'words' => [], + ], ); diff --git a/index.php b/index.php index c5981636c2..cb33226285 100644 --- a/index.php +++ b/index.php @@ -313,8 +313,10 @@ if(SITE_CLOSED && admin()) $content .= '

    Site is under maintenance (closed mode). Only privileged users can see it.

    '; - if($config['backward_support']) - require SYSTEM . 'compat_pages.php'; + if ($config['backward_support']) { + require SYSTEM . 'compat/pages.php'; + require SYSTEM . 'compat/classes.php'; + } $ignore = false; @@ -323,24 +325,26 @@ $logged_access = $account_logged->getAccess(); } - $success = false; - $tmp_content = getCustomPage($page, $success); - if($success) { - $content .= $tmp_content; - if(hasFlag(FLAG_CONTENT_PAGES) || superAdmin()) { - $pageInfo = getCustomPageInfo($page); - $content = $twig->render('admin.pages.links.html.twig', array( - 'page' => array('id' => $pageInfo !== null ? $pageInfo['id'] : 0, 'hidden' => $pageInfo !== null ? $pageInfo['hidden'] : '0') - )) . $content; - } - } else { - $file = SYSTEM . 'pages/' . $page . '.php'; - if(!@file_exists($file) || preg_match('/[^A-z0-9_\-]/', $page)) - { - $page = '404'; - $file = SYSTEM . 'pages/404.php'; - } - } + $success = false; + $tmp_content = getCustomPage($page, $success); + if ($success) { + $content .= $tmp_content; + if (hasFlag(FLAG_CONTENT_PAGES) || superAdmin()) { + $pageInfo = getCustomPageInfo($page); + $content = $twig->render('admin.pages.links.html.twig', array( + 'page' => array('id' => $pageInfo !== null ? $pageInfo['id'] : 0, 'hidden' => $pageInfo !== null ? $pageInfo['hidden'] : '0') + )) . $content; + } + } else { + $file = TEMPLATES . "$template_name/pages/$page.php"; + if (!@file_exists($file) || preg_match('/[^A-z0-9_\-]/', $page)) { + $file = SYSTEM . "pages/$page.php"; + if (!@file_exists($file) || preg_match('/[^A-z0-9_\-]/', $page)) { + $page = '404'; + $file = SYSTEM . 'pages/404.php'; + } + } + } ob_start(); if($hooks->trigger(HOOK_BEFORE_PAGE)) { diff --git a/install/includes/schema.sql b/install/includes/schema.sql index 011819e9fa..4db281211c 100644 --- a/install/includes/schema.sql +++ b/install/includes/schema.sql @@ -1,4 +1,4 @@ -SET @myaac_database_version = 33; +SET @myaac_database_version = 34; CREATE TABLE `myaac_account_actions` ( @@ -351,7 +351,7 @@ CREATE TABLE `myaac_spells` CREATE TABLE `myaac_visitors` ( - `ip` VARCHAR(16) NOT NULL, + `ip` VARCHAR(45) NOT NULL, `lastvisit` INT(11) NOT NULL DEFAULT 0, `page` VARCHAR(2048) NOT NULL, UNIQUE (`ip`) diff --git a/install/includes/twig_error.html b/install/includes/twig_error.html index 933a36c1ed..cbf836ea51 100644 --- a/install/includes/twig_error.html +++ b/install/includes/twig_error.html @@ -1,11 +1,12 @@ -We have detected that you don't have access to write to the system/cache directory. Under linux you can fix it by using this two command, where first one should be enough (for apache):

    chown -R www-data.www-data /var/www/*
    chmod -R 660 system/cache +We have detected that you don't have access to write to the system/cache directory. Under linux you can fix it by using this two command, where first one should be enough (for apache): +

    chown -R www-data.www-data /var/www/*
    chmod -R 660 system/cache \ No newline at end of file + .console { + font-family: Courier, serif; + color: #CCCCCC; + background: #000000; + border: 3px double #CCCCCC; + padding: 0; + } + diff --git a/install/index.php b/install/index.php index 255d89e234..480bc90078 100644 --- a/install/index.php +++ b/install/index.php @@ -70,9 +70,9 @@ $key = str_replace('var_', '', $key); - if(in_array($key, array('account', 'password', 'email', 'player_name'))) { - continue; - } + if (in_array($key, array('account', 'account_id', 'password', 'email', 'player_name'))) { + continue; + } if($key != 'usage' && empty($value)) { $errors[] = $locale['please_fill_all']; @@ -112,18 +112,13 @@ if(!empty($errors)) { $step = 'config'; } -} -else if($step == 'admin') { - $config_failed = true; - if(file_exists(BASE . 'config.local.php') && isset($config['installed']) && $config['installed'] && isset($_SESSION['saved'])) { - $config_failed = false; - } - - if($config_failed) { - $step = 'database'; - } -} -else if($step == 'finish') { +} else if ($step == 'admin') { + if (!file_exists(BASE . 'config.local.php') || !isset($config['installed']) || !$config['installed']) { + $step = 'database'; + } else { + $_SESSION['saved'] = true; + } +} else if ($step == 'finish') { $email = $_SESSION['var_email']; $password = $_SESSION['var_password']; $player_name = $_SESSION['var_player_name']; diff --git a/install/steps/4-config.php b/install/steps/4-config.php index b1555201eb..dd69c3918f 100644 --- a/install/steps/4-config.php +++ b/install/steps/4-config.php @@ -1,21 +1,21 @@ display('install.config.html.twig', array( - 'clients' => $clients, - 'timezones' => DateTimeZone::listIdentifiers(), - 'locale' => $locale, - 'session' => $_SESSION, - 'errors' => isset($errors) ? $errors : null, - 'buttons' => next_buttons() + 'clients' => $clients, + 'timezones' => DateTimeZone::listIdentifiers(), + 'locale' => $locale, + 'session' => $_SESSION, + 'errors' => $errors ?? null, + 'buttons' => next_buttons() )); -?> \ No newline at end of file diff --git a/install/steps/5-database.php b/install/steps/5-database.php index 081a9aadea..a2077f8b7d 100644 --- a/install/steps/5-database.php +++ b/install/steps/5-database.php @@ -5,103 +5,115 @@ ini_set('max_execution_time', 300); $error = false; -if(!isset($_SESSION['var_server_path'])) { - error($locale['step_database_error_path']); - $error = true; +if (!isset($_SESSION['var_server_path'])) { + error($locale['step_database_error_path']); + $error = true; } -if(!$error) { - $content = " $value) - { - if(strpos($key, 'var_') !== false) - { - if($key === 'var_server_path') - { - $value = str_replace("\\", "/", $value); - if($value[strlen($value) - 1] !== '/') - $value .= '/'; - } - - if($key === 'var_usage') { - $content .= '$config[\'anonymous_usage_statistics\'] = ' . ((int)$value == 1 ? 'true' : 'false') . ';'; - $content .= PHP_EOL; - } - else if(!in_array($key, array('var_account', 'var_account_id', 'var_password', 'var_step', 'var_email', 'var_player_name'), true)) { - $content .= '$config[\'' . str_replace('var_', '', $key) . '\'] = \'' . $value . '\';'; - $content .= PHP_EOL; - } - } - } - - require BASE . 'install/includes/config.php'; - - if(!$error) { - require BASE . 'install/includes/database.php'; - - $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); - success($locale['step_database_importing']); - - if(isset($database_error)) { // we failed connect to the database - error($database_error); - } - else { - $twig->display('install.installer.html.twig', array( - 'url' => 'tools/5-database.php', - 'message' => $locale['loading_spinner'] - )); - - if(!$error) { - if(!Validator::email($_SESSION['var_mail_admin'])) { - error($locale['step_config_mail_admin_error']); - $error = true; - } - if(!Validator::email($_SESSION['var_mail_address'])) { - error($locale['step_config_mail_address_error']); - $error = true; - } - - $content .= '$config[\'session_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';'; - $content .= PHP_EOL; - $content .= '$config[\'cache_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';'; - - $saved = true; - if(!$error) { - $saved = file_put_contents(BASE . 'config.local.php', $content); - } - - if($saved) { - if(!$error) { - $_SESSION['saved'] = true; - } - } - else { - $_SESSION['config_content'] = $content; - unset($_SESSION['saved']); - - $locale['step_database_error_file'] = str_replace('$FILE$', '' . BASE . 'config.local.php', $locale['step_database_error_file']); - warning($locale['step_database_error_file'] . '
    - '); - } - } - } - } +if (!$error) { + $content = " $value) { + if (strpos($key, 'var_') !== false) { + if ($key === 'var_server_path') { + $value = str_replace("\\", "/", $value); + if ($value[strlen($value) - 1] !== '/') + $value .= '/'; + } + + if ($key === 'var_usage') { + $content .= '$config[\'anonymous_usage_statistics\'] = ' . ((int)$value == 1 ? 'true' : 'false') . ';'; + $content .= PHP_EOL; + } else if (!in_array($key, array('var_account', 'var_account_id', 'var_password', 'var_step', 'var_email', 'var_player_name'), true)) { + $content .= '$config[\'' . str_replace('var_', '', $key) . '\'] = \'' . $value . '\';'; + $content .= PHP_EOL; + } + } + } + + require BASE . 'install/includes/config.php'; + + if (!$error) { + require BASE . 'install/includes/database.php'; + + $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); + success($locale['step_database_importing']); + + if (isset($database_error)) { // we failed connect to the database + error($database_error); + } else { + if (!$db->hasTable('accounts')) { + $tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']); + error($tmp); + $error = true; + } + + if (!$db->hasTable('players')) { + $tmp = str_replace('$TABLE$', 'players', $locale['step_database_error_table']); + error($tmp); + $error = true; + } + + if (!$db->hasTable('guilds')) { + $tmp = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']); + error($tmp); + $error = true; + } + + if (!$error) { + $twig->display('install.installer.html.twig', array( + 'url' => 'tools/5-database.php', + 'message' => $locale['loading_spinner'] + )); + + if (!Validator::email($_SESSION['var_mail_admin'])) { + error($locale['step_config_mail_admin_error']); + $error = true; + } + + if (!Validator::email($_SESSION['var_mail_address'])) { + error($locale['step_config_mail_address_error']); + $error = true; + } + + $content .= '$config[\'session_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';'; + $content .= PHP_EOL; + $content .= '$config[\'cache_prefix\'] = \'myaac_' . generateRandomString(8, true, false, true, false) . '_\';'; + + $saved = true; + if (!$error) { + $saved = file_put_contents(BASE . 'config.local.php', $content); + } + + if ($saved) { + success($locale['step_database_config_saved']); + if (!$error) { + $_SESSION['saved'] = true; + } + } else { + $_SESSION['config_content'] = $content; + unset($_SESSION['saved']); + + $locale['step_database_error_file'] = str_replace('$FILE$', '' . BASE . 'config.local.php', $locale['step_database_error_file']); + error($locale['step_database_error_file'] . '
    '); + } + } + } + } } ?> -
    - - -
    \ No newline at end of file +
    + + +
    diff --git a/install/steps/7-finish.php b/install/steps/7-finish.php index f17a7da282..a2f083dc01 100644 --- a/install/steps/7-finish.php +++ b/install/steps/7-finish.php @@ -66,7 +66,6 @@ $new_account->setPassword(encrypt($password)); $new_account->setEMail($email); - $new_account->unblock(); $new_account->save(); $new_account->setCustomField('created', time()); @@ -83,7 +82,7 @@ if($db->hasColumn('accounts', 'group_id')) $account_used->setCustomField('group_id', $groups->getHighestId()); if($db->hasColumn('accounts', 'type')) - $account_used->setCustomField('type', 5); + $account_used->setCustomField('type', 6); if(!$player_db->isLoaded()) $player->setAccountId($account_used->getId()); diff --git a/install/tools/5-database.php b/install/tools/5-database.php index e80aba7077..a8e52bf504 100644 --- a/install/tools/5-database.php +++ b/install/tools/5-database.php @@ -1,4 +1,6 @@ hasTable('accounts')) { - $locale['step_database_error_table'] = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']); - error($locale['step_database_error_table']); - return; -} +if ($db->hasTable(TABLE_PREFIX . 'account_actions')) { + $locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']); + warning($locale['step_database_error_table_exist']); +} else { + // import schema + try { + $db->query(file_get_contents(BASE . 'install/includes/schema.sql')); -if(!$db->hasTable('players')) { - $locale['step_database_error_table'] = str_replace('$TABLE$', 'players', $locale['step_database_error_table']); - error($locale['step_database_error_table']); - return; + $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); + success($locale['step_database_success_schema']); + } catch (PDOException $error_) { + error($locale['step_database_error_schema'] . ' ' . $error_); + return; + } } -if(!$db->hasTable('guilds')) { - $locale['step_database_error_table'] = str_replace('$TABLE$', 'guilds', $locale['step_database_error_table']); - error($locale['step_database_error_table']); - return; +if (!$db->hasColumn('accounts', 'email')) { + if (query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';")) + success($locale['step_database_adding_field'] . ' accounts.email...'); } -if($db->hasTable(TABLE_PREFIX . 'account_actions')) { - $locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']); - warning($locale['step_database_error_table_exist']); +if ($db->hasColumn('accounts', 'key')) { + if (query("ALTER TABLE `accounts` MODIFY `key` VARCHAR(64) NOT NULL DEFAULT '';")) + success($locale['step_database_modifying_field'] . ' accounts.key...'); +} else { + if (query("ALTER TABLE `accounts` ADD `key` VARCHAR(64) NOT NULL DEFAULT '' AFTER `email`;")) + success($locale['step_database_adding_field'] . ' accounts.key...'); } -else { - // import schema - try { - $db->query(file_get_contents(BASE . 'install/includes/schema.sql')); - $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); - success($locale['step_database_success_schema']); - } - catch(PDOException $error_) { - error($locale['step_database_error_schema'] . ' ' . $error_); - return; - } +if (!$db->hasColumn('accounts', 'created')) { + if (query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . ($db->hasColumn('accounts', 'group_id') ? 'group_id' : 'email') . "`;")) + success($locale['step_database_adding_field'] . ' accounts.created...'); } -if(!$db->hasColumn('accounts', 'email')) { - if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';")) - success($locale['step_database_adding_field'] . ' accounts.email...'); +if (!$db->hasColumn('accounts', 'rlname')) { + if (query("ALTER TABLE `accounts` ADD `rlname` VARCHAR(255) NOT NULL DEFAULT '' AFTER `created`;")) + success($locale['step_database_adding_field'] . ' accounts.rlname...'); } -if($db->hasColumn('accounts', 'key')) { - if(query("ALTER TABLE `accounts` MODIFY `key` VARCHAR(64) NOT NULL DEFAULT '';")) - success($locale['step_database_modifying_field'] . ' accounts.key...'); -} -else { - if(query("ALTER TABLE `accounts` ADD `key` VARCHAR(64) NOT NULL DEFAULT '' AFTER `email`;")) - success($locale['step_database_adding_field'] . ' accounts.key...'); +if (!$db->hasColumn('accounts', 'location')) { + if (query("ALTER TABLE `accounts` ADD `location` VARCHAR(255) NOT NULL DEFAULT '' AFTER `rlname`;")) + success($locale['step_database_adding_field'] . ' accounts.location...'); } -if(!$db->hasColumn('accounts', 'blocked')) { - if(query("ALTER TABLE `accounts` ADD `blocked` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT 'internal usage' AFTER `key`;")) - success($locale['step_database_adding_field'] . ' accounts.blocked...'); +if (!$db->hasColumn('accounts', 'country')) { + if (query("ALTER TABLE `accounts` ADD `country` VARCHAR(3) NOT NULL DEFAULT '' AFTER `location`;")) + success($locale['step_database_adding_field'] . ' accounts.country...'); } -if(!$db->hasColumn('accounts', 'created')) { - if(query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . ($db->hasColumn('accounts', 'group_id') ? 'group_id' : 'blocked') . "`;")) - success($locale['step_database_adding_field'] . ' accounts.created...'); +if ($db->hasColumn('accounts', 'page_lastday')) { + if (query("ALTER TABLE `accounts` CHANGE `page_lastday` `web_lastlogin` INT(11) NOT NULL DEFAULT 0;")) { + $tmp = str_replace('$FIELD$', 'accounts.page_lastday', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'accounts.web_lastlogin', $tmp); + success($tmp); + } +} else if (!$db->hasColumn('accounts', 'web_lastlogin')) { + if (query("ALTER TABLE `accounts` ADD `web_lastlogin` INT(11) NOT NULL DEFAULT 0 AFTER `country`;")) + success($locale['step_database_adding_field'] . ' accounts.web_lastlogin...'); } -if(!$db->hasColumn('accounts', 'rlname')) { - if(query("ALTER TABLE `accounts` ADD `rlname` VARCHAR(255) NOT NULL DEFAULT '' AFTER `created`;")) - success($locale['step_database_adding_field'] . ' accounts.rlname...'); +if (!$db->hasColumn('accounts', 'web_flags')) { + if (query("ALTER TABLE `accounts` ADD `web_flags` INT(11) NOT NULL DEFAULT 0 AFTER `web_lastlogin`;")) + success($locale['step_database_adding_field'] . ' accounts.web_flags...'); } -if(!$db->hasColumn('accounts', 'location')) { - if(query("ALTER TABLE `accounts` ADD `location` VARCHAR(255) NOT NULL DEFAULT '' AFTER `rlname`;")) - success($locale['step_database_adding_field'] . ' accounts.location...'); +if (!$db->hasColumn('accounts', 'email_hash')) { + if (query("ALTER TABLE `accounts` ADD `email_hash` VARCHAR(32) NOT NULL DEFAULT '' AFTER `web_flags`;")) + success($locale['step_database_adding_field'] . ' accounts.email_hash...'); } -if(!$db->hasColumn('accounts', 'country')) { - if(query("ALTER TABLE `accounts` ADD `country` VARCHAR(3) NOT NULL DEFAULT '' AFTER `location`;")) - success($locale['step_database_adding_field'] . ' accounts.country...'); +if (!$db->hasColumn('accounts', 'email_verified')) { + if (query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `email_hash`;")) + success($locale['step_database_adding_field'] . ' accounts.email_verified...'); } -if($db->hasColumn('accounts', 'page_lastday')) { - if(query("ALTER TABLE `accounts` CHANGE `page_lastday` `web_lastlogin` INT(11) NOT NULL DEFAULT 0;")) { - $tmp = str_replace('$FIELD$', 'accounts.page_lastday', $locale['step_database_changing_field']); - $tmp = str_replace('$FIELD_NEW$', 'accounts.web_lastlogin', $tmp); - success($tmp); - } -} -else if(!$db->hasColumn('accounts', 'web_lastlogin')) { - if(query("ALTER TABLE `accounts` ADD `web_lastlogin` INT(11) NOT NULL DEFAULT 0 AFTER `country`;")) - success($locale['step_database_adding_field'] . ' accounts.web_lastlogin...'); +if (!$db->hasColumn('accounts', 'email_new')) { + if (query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_hash`;")) + success($locale['step_database_adding_field'] . ' accounts.email_new...'); } -if(!$db->hasColumn('accounts', 'web_flags')) { - if(query("ALTER TABLE `accounts` ADD `web_flags` INT(11) NOT NULL DEFAULT 0 AFTER `web_lastlogin`;")) - success($locale['step_database_adding_field'] . ' accounts.web_flags...'); +if (!$db->hasColumn('accounts', 'email_new_time')) { + if (query("ALTER TABLE `accounts` ADD `email_new_time` INT(11) NOT NULL DEFAULT 0 AFTER `email_new`;")) + success($locale['step_database_adding_field'] . ' accounts.email_new_time...'); } -if(!$db->hasColumn('accounts', 'email_hash')) { - if(query("ALTER TABLE `accounts` ADD `email_hash` VARCHAR(32) NOT NULL DEFAULT '' AFTER `web_flags`;")) - success($locale['step_database_adding_field'] . ' accounts.email_hash...'); +if (!$db->hasColumn('accounts', 'email_code')) { + if (query("ALTER TABLE `accounts` ADD `email_code` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_new_time`;")) + success($locale['step_database_adding_field'] . ' accounts.email_code...'); } -if(!$db->hasColumn('accounts', 'email_verified')) { - if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `email_hash`;")) - success($locale['step_database_adding_field'] . ' accounts.email_verified...'); +if ($db->hasColumn('accounts', 'next_email')) { + if (!$db->hasColumn('accounts', 'email_next')) { + if (query("ALTER TABLE `accounts` CHANGE `next_email` `email_next` INT(11) NOT NULL DEFAULT 0;")) { + $tmp = str_replace('$FIELD$', 'accounts.next_email', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'accounts.email_next', $tmp); + success($tmp); + } + } +} else if (!$db->hasColumn('accounts', 'email_next')) { + if (query("ALTER TABLE `accounts` ADD `email_next` INT(11) NOT NULL DEFAULT 0 AFTER `email_code`;")) + success($locale['step_database_adding_field'] . ' accounts.email_next...'); } -if(!$db->hasColumn('accounts', 'email_new')) { - if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_hash`;")) - success($locale['step_database_adding_field'] . ' accounts.email_new...'); +if (!$db->hasColumn('accounts', 'premium_points')) { + if (query("ALTER TABLE `accounts` ADD `premium_points` INT(11) NOT NULL DEFAULT 0 AFTER `email_next`;")) + success($locale['step_database_adding_field'] . ' accounts.premium_points...'); } -if(!$db->hasColumn('accounts', 'email_new_time')) { - if(query("ALTER TABLE `accounts` ADD `email_new_time` INT(11) NOT NULL DEFAULT 0 AFTER `email_new`;")) - success($locale['step_database_adding_field'] . ' accounts.email_new_time...'); +if ($db->hasColumn('guilds', 'checkdata')) { + if (query("ALTER TABLE `guilds` MODIFY `checkdata` INT NOT NULL DEFAULT 0;")) + success($locale['step_database_modifying_field'] . ' guilds.checkdata...'); } -if(!$db->hasColumn('accounts', 'email_code')) { - if(query("ALTER TABLE `accounts` ADD `email_code` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_new_time`;")) - success($locale['step_database_adding_field'] . ' accounts.email_code...'); +if (!$db->hasColumn('guilds', 'motd')) { + if (query("ALTER TABLE `guilds` ADD `motd` VARCHAR(255) NOT NULL DEFAULT '';")) + success($locale['step_database_adding_field'] . ' guilds.motd...'); +} else { + if (query("ALTER TABLE `guilds` MODIFY `motd` VARCHAR(255) NOT NULL DEFAULT '';")) + success($locale['step_database_modifying_field'] . ' guilds.motd...'); } -if($db->hasColumn('accounts', 'next_email')) { - if(!$db->hasColumn('accounts', 'email_next')) { - if(query("ALTER TABLE `accounts` CHANGE `next_email` `email_next` INT(11) NOT NULL DEFAULT 0;")) { - $tmp = str_replace('$FIELD$', 'accounts.next_email', $locale['step_database_changing_field']); - $tmp = str_replace('$FIELD_NEW$', 'accounts.email_next', $tmp); - success($tmp); - } - } -} -else if(!$db->hasColumn('accounts', 'email_next')) { - if(query("ALTER TABLE `accounts` ADD `email_next` INT(11) NOT NULL DEFAULT 0 AFTER `email_code`;")) - success($locale['step_database_adding_field'] . ' accounts.email_next...'); +if (!$db->hasColumn('guilds', 'description')) { + if (query("ALTER TABLE `guilds` ADD `description` TEXT NOT NULL;")) + success($locale['step_database_adding_field'] . ' guilds.description...'); } -if(!$db->hasColumn('accounts', 'premium_points')) { - if(query("ALTER TABLE `accounts` ADD `premium_points` INT(11) NOT NULL DEFAULT 0 AFTER `email_next`;")) - success($locale['step_database_adding_field'] . ' accounts.premium_points...'); +if ($db->hasColumn('guilds', 'logo_gfx_name')) { + if (query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) { + $tmp = str_replace('$FIELD$', 'guilds.logo_gfx_name', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'guilds.logo_name', $tmp); + success($tmp); + } +} else if (!$db->hasColumn('guilds', 'logo_name')) { + if (query("ALTER TABLE `guilds` ADD `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) + success($locale['step_database_adding_field'] . ' guilds.logo_name...'); } -if($db->hasColumn('guilds', 'checkdata')) { - if(query("ALTER TABLE `guilds` MODIFY `checkdata` INT NOT NULL DEFAULT 0;")) - success($locale['step_database_modifying_field'] . ' guilds.checkdata...'); +if (!$db->hasColumn('players', 'created')) { + if (query("ALTER TABLE `players` ADD `created` INT(11) NOT NULL DEFAULT 0;")) + success($locale['step_database_adding_field'] . ' players.created...'); } -if(!$db->hasColumn('guilds', 'motd')) { - if(query("ALTER TABLE `guilds` ADD `motd` VARCHAR(255) NOT NULL DEFAULT '';")) - success($locale['step_database_adding_field'] . ' guilds.motd...'); -} -else { - if(query("ALTER TABLE `guilds` MODIFY `motd` VARCHAR(255) NOT NULL DEFAULT '';")) - success($locale['step_database_modifying_field'] . ' guilds.motd...'); +if (!$db->hasColumn('players', 'deleted') && !$db->hasColumn('players', 'deletion')) { + if (query("ALTER TABLE `players` ADD `deleted` TINYINT(1) NOT NULL DEFAULT 0;")) + success($locale['step_database_adding_field'] . ' players.deleted...'); } -if(!$db->hasColumn('guilds', 'description')) { - if(query("ALTER TABLE `guilds` ADD `description` TEXT NOT NULL;")) - success($locale['step_database_adding_field'] . ' guilds.description...'); +if ($db->hasColumn('players', 'hide_char')) { + if (!$db->hasColumn('players', 'hidden')) { + if (query("ALTER TABLE `players` CHANGE `hide_char` `hidden` TINYINT(1) NOT NULL DEFAULT 0;")) { + $tmp = str_replace('$FIELD$', 'players.hide_char', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'players.hidden', $tmp); + success($tmp); + } + } +} else if (!$db->hasColumn('players', 'hidden')) { + if (query("ALTER TABLE `players` ADD `hidden` TINYINT(1) NOT NULL DEFAULT 0;")) + success($locale['step_database_adding_field'] . ' players.hidden...'); } -if($db->hasColumn('guilds', 'logo_gfx_name')) { - if(query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) { - $tmp = str_replace('$FIELD$', 'guilds.logo_gfx_name', $locale['step_database_changing_field']); - $tmp = str_replace('$FIELD_NEW$', 'guilds.logo_name', $tmp); - success($tmp); - } -} -else if(!$db->hasColumn('guilds', 'logo_name')) { - if(query("ALTER TABLE `guilds` ADD `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) - success($locale['step_database_adding_field'] . ' guilds.logo_name...'); +if (!$db->hasColumn('players', 'comment')) { + if (query("ALTER TABLE `players` ADD `comment` TEXT NOT NULL;")) + success($locale['step_database_adding_field'] . ' players.comment...'); } -if(!$db->hasColumn('players', 'created')) { - if(query("ALTER TABLE `players` ADD `created` INT(11) NOT NULL DEFAULT 0;")) - success($locale['step_database_adding_field'] . ' players.created...'); -} +if ($db->hasColumn('players', 'rank_id')) { + if (query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;")) + success($locale['step_database_modifying_field'] . ' players.rank_id...'); -if(!$db->hasColumn('players', 'deleted') && !$db->hasColumn('players', 'deletion')) { - if(query("ALTER TABLE `players` ADD `deleted` TINYINT(1) NOT NULL DEFAULT 0;")) - success($locale['step_database_adding_field'] . ' players.deleted...'); + if ($db->hasColumn('players', 'guildnick')) { + if (query("ALTER TABLE players MODIFY `guildnick` VARCHAR(255) NOT NULL DEFAULT '';")) { + success($locale['step_database_modifying_field'] . ' players.guildnick...'); + } + } } -if($db->hasColumn('players', 'hide_char')) { - if(!$db->hasColumn('players', 'hidden')) { - if(query("ALTER TABLE `players` CHANGE `hide_char` `hidden` TINYINT(1) NOT NULL DEFAULT 0;")) { - $tmp = str_replace('$FIELD$', 'players.hide_char', $locale['step_database_changing_field']); - $tmp = str_replace('$FIELD_NEW$', 'players.hidden', $tmp); - success($tmp); - } - } -} -else if(!$db->hasColumn('players', 'hidden')) { - if(query("ALTER TABLE `players` ADD `hidden` TINYINT(1) NOT NULL DEFAULT 0;")) - success($locale['step_database_adding_field'] . ' players.hidden...'); -} - -if(!$db->hasColumn('players', 'comment')) { - if(query("ALTER TABLE `players` ADD `comment` TEXT NOT NULL;")) - success($locale['step_database_adding_field'] . ' players.comment...'); -} +if ($db->hasTable('z_forum')) { + if (!$db->hasColumn('z_forum', 'post_html')) { + if (query("ALTER TABLE `z_forum` ADD `post_html` tinyint(1) NOT NULL DEFAULT '0' AFTER `post_smile`;")) { + success($locale['step_database_adding_field'] . ' z_forum.post_html...'); + } + } -if($db->hasColumn('players', 'rank_id')) { - if(query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;")) - success($locale['step_database_modifying_field'] . ' players.rank_id...'); + if (!$db->hasColumn('z_forum', 'sticked')) { + if (query("ALTER TABLE `z_forum` ADD `sticked` tinyint(1) NOT NULL DEFAULT '0';")) { + success($locale['step_database_adding_field'] . ' z_forum.sticked...'); + } + } - if($db->hasColumn('players', 'guildnick')) { - if(query("ALTER TABLE players MODIFY `guildnick` VARCHAR(255) NOT NULL DEFAULT '';")) { - success($locale['step_database_modifying_field'] . ' players.guildnick...'); - } - } + if (!$db->hasColumn('z_forum', 'closed')) { + if (query("ALTER TABLE `z_forum` ADD `closed` tinyint(1) NOT NULL DEFAULT '0';")) { + success($locale['step_database_adding_field'] . ' z_forum.closed...'); + } + } } - -if($db->hasTable('z_forum')) { - if(!$db->hasColumn('z_forum', 'post_html')) { - if(query("ALTER TABLE `z_forum` ADD `post_html` tinyint(1) NOT NULL DEFAULT '0' AFTER `post_smile`;")) { - success($locale['step_database_adding_field'] . ' z_forum.post_html...'); - } - } - - if(!$db->hasColumn('z_forum', 'sticked')) { - if(query("ALTER TABLE `z_forum` ADD `sticked` tinyint(1) NOT NULL DEFAULT '0';")) { - success($locale['step_database_adding_field'] . ' z_forum.sticked...'); - } - } - - if(!$db->hasColumn('z_forum', 'closed')) { - if(query("ALTER TABLE `z_forum` ADD `closed` tinyint(1) NOT NULL DEFAULT '0';")) { - success($locale['step_database_adding_field'] . ' z_forum.closed...'); - } - } -} \ No newline at end of file diff --git a/install/tools/7-finish.php b/install/tools/7-finish.php index da1239d795..087b4d6ec3 100644 --- a/install/tools/7-finish.php +++ b/install/tools/7-finish.php @@ -1,4 +1,6 @@ hasColumn('accounts', 'coins'); +if ($hasCoinsColumn && $reward['coins'] > 0) { + log_append('email_confirm_error.log', 'accounts.coins column does not exist.'); +} + +if (!isset($account) || !$account->isLoaded()) { + log_append('email_confirm_error.log', 'Account not loaded.'); + return; +} + +if ($reward['premium_points'] > 0) { + $account->setCustomField('premium_points', (int)$account->getCustomField('premium_points') + $reward['premium_points']); + + success(sprintf($reward['message'], $reward['premium_points'], 'premium points')); +} + +if ($reward['coins'] > 0 && $hasCoinsColumn) { + $account->setCustomField('coins', (int)$account->getCustomField('coins') + $reward['coins']); + + success(sprintf($reward['message'], $reward['coins'], 'coins')); +} + +if ($reward['premium_days'] > 0) { + $account->setPremDays($account->getPremDays() + $reward['premium_days']); + $account->save(); + + success(sprintf($reward['message'], $reward['premium_days'], 'premium days')); +} diff --git a/release.sh b/release.sh new file mode 100644 index 0000000000..7e157d6df7 --- /dev/null +++ b/release.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# myaac release script +# +# places compressed archives into releases/ directory +# + +if [ $# -eq 0 ]; then + echo "No arguments supplied" + echo "Usage: release.sh prepare/pack" + exit 1 +fi + +if [ $1 = "prepare" ]; then + # define release version + version=`php system/get_version_for_release.php` + + echo "Preparing to release version $version of the MyAAC Project!" + + # make required directories + mkdir -p releases + mkdir -p tmp + + # get myaac from git archive + git archive --format zip --output tmp/myaac.zip master + + cd tmp/ || exit + + dir="myaac-$version" + if [ -d "$dir" ] ; then + echo "Fatal error: Version $version already exists!!" + exit + fi + + unzip -q myaac.zip -d $dir + rm myaac.zip + + echo "Now you can make changes to $dir. When you are ready, type 'release.sh pack'" + exit +fi + +if [ $1 = "pack" ]; then + # define release version + version=`php system/get_version_for_release.php` + + cd tmp || exit + + # tar.gz + echo "Creating .tar.gz package.." + file="myaac-$version.tar.gz" + tar -czf $file * + mv $file ../releases/ + + # zip + echo "Creating .zip package.." + file="myaac-$version.zip" + zip -rq $file * + mv $file ../releases/ + + cd .. + rm -R tmp + echo "Done. Released files can be found in 'releases' directory." + + exit +fi diff --git a/system/autoload.php b/system/autoload.php index a13db1db46..af9d311926 100644 --- a/system/autoload.php +++ b/system/autoload.php @@ -9,6 +9,10 @@ // register the base directories for the namespace prefix $loader->addNamespace('Composer\Semver', LIBS . 'semver'); $loader->addNamespace('Twig', LIBS . 'Twig'); +$loader->addNamespace('Symfony\Polyfill\Mbstring', LIBS . 'polyfill-mbstring'); + +// load polyfill-mbstring bootstrap +require LIBS . 'polyfill-mbstring/bootstrap.php'; /** * An example of a general-purpose implementation that includes the optional * functionality of allowing multiple base directories for a single namespace @@ -203,4 +207,4 @@ protected function requireFile($file) } return false; } -} \ No newline at end of file +} diff --git a/system/clients.conf.php b/system/clients.conf.php index a4919555ff..0d42c5eb77 100644 --- a/system/clients.conf.php +++ b/system/clients.conf.php @@ -93,10 +93,14 @@ 1260, 1270, 1280, + 1285, + 1286, + 1290, 1291, 1300, 1310, 1311, + 1312, 1316, ]; diff --git a/system/compat.php b/system/compat.php deleted file mode 100644 index 40d2617efa..0000000000 --- a/system/compat.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @copyright 2019 MyAAC - * @link https://my-aac.org - */ -defined('MYAAC') or die('Direct access not allowed!'); - -function check_name($name, &$errors = '') { - if(Validator::characterName($name)) - return true; - - $errors = Validator::getLastError(); - return false; -} - -function check_account_id($id, &$errors = '') { - if(Validator::accountId($id)) - return true; - - $errors = Validator::getLastError(); - return false; -} - -function check_account_name($name, &$errors = '') { - if(Validator::accountName($name)) - return true; - - $errors = Validator::getLastError(); - return false; -} - -function check_name_new_char($name, &$errors = '') { - if(Validator::newCharacterName($name)) - return true; - - $errors = Validator::getLastError(); - return false; -} - -function check_rank_name($name, &$errors = '') { - if(Validator::rankName($name)) - return true; - - $errors = Validator::getLastError(); - return false; -} - -function check_guild_name($name, &$errors = '') { - if(Validator::guildName($name)) - return true; - - $errors = Validator::getLastError(); - return false; -} - -function news_place() { - return tickers(); -} - -function tableExist($table) -{ - global $db; - return $db->hasTable($table); -} - -function fieldExist($field, $table) -{ - global $db; - return $db->hasColumn($table, $field); -} -?> \ No newline at end of file diff --git a/system/compat/base.php b/system/compat/base.php new file mode 100644 index 0000000000..c85721406f --- /dev/null +++ b/system/compat/base.php @@ -0,0 +1,83 @@ + + * @copyright 2019 MyAAC + * @link https://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +function check_name($name, &$errors = '') +{ + if (Validator::characterName($name)) + return true; + + $errors = Validator::getLastError(); + return false; +} + +function check_account_id($id, &$errors = '') +{ + if (Validator::accountId($id)) + return true; + + $errors = Validator::getLastError(); + return false; +} + +function check_account_name($name, &$errors = '') +{ + if (Validator::accountName($name)) + return true; + + $errors = Validator::getLastError(); + return false; +} + +function check_name_new_char($name, &$errors = '') +{ + if (Validator::newCharacterName($name)) + return true; + + $errors = Validator::getLastError(); + return false; +} + +function check_rank_name($name, &$errors = '') +{ + if (Validator::rankName($name)) + return true; + + $errors = Validator::getLastError(); + return false; +} + +function check_guild_name($name, &$errors = '') +{ + if (Validator::guildName($name)) + return true; + + $errors = Validator::getLastError(); + return false; +} + +function news_place() +{ + return tickers(); +} + +function tableExist($table) +{ + global $db; + return $db->hasTable($table); +} + +function fieldExist($field, $table) +{ + global $db; + return $db->hasColumn($table, $field); +} + +?> diff --git a/system/compat/classes.php b/system/compat/classes.php new file mode 100644 index 0000000000..051fbdf2ce --- /dev/null +++ b/system/compat/classes.php @@ -0,0 +1,15 @@ + + * @copyright 2022 MyAAC + * @link https://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +class Player extends OTS_Player {} +class Guild extends OTS_Guild {} +class GuildRank extends OTS_GuildRank {} +class House extends OTS_House {} diff --git a/system/compat/pages.php b/system/compat/pages.php new file mode 100644 index 0000000000..fb891963d5 --- /dev/null +++ b/system/compat/pages.php @@ -0,0 +1,39 @@ + + * @copyright 2019 MyAAC + * @link https://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +switch ($page) { + case 'whoisonline': + $page = 'online'; + break; + + case 'latestnews': + $page = 'news'; + break; + + case 'tibiarules': + $page = 'rules'; + break; + + case 'killstatistics': + $page = 'lastkills'; + break; + + case 'buypoints': + $page = 'points'; + break; + + case 'shopsystem': + $page = 'gifts'; + break; + + default: + break; +} +?> diff --git a/system/compat_pages.php b/system/compat_pages.php deleted file mode 100644 index 1830ecd5da..0000000000 --- a/system/compat_pages.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @copyright 2019 MyAAC - * @link https://my-aac.org - */ -defined('MYAAC') or die('Direct access not allowed!'); -switch($page) -{ - case 'whoisonline': - $page = 'online'; - break; - - case 'latestnews': - $page = 'news'; - break; - - case 'tibiarules': - $page = 'rules'; - break; - - case 'killstatistics': - $page = 'lastkills'; - break; - - case 'buypoints': - $page = 'points'; - break; - - case 'shopsystem': - $page = 'gifts'; - break; - - default: - break; -} -?> diff --git a/system/exception.php b/system/exception.php index 17a48de81b..9b4d79b0bf 100644 --- a/system/exception.php +++ b/system/exception.php @@ -5,42 +5,43 @@ /** * @param Exception $exception */ -function exception_handler($exception) { - $message = $exception->getMessage(); - if($exception instanceof SensitiveException) { - $message = 'This error is sensitive and has been logged into ' . LOGS . 'error.log.
    View this file for more information.'; +function exception_handler($exception) +{ + $message = $exception->getMessage(); + if ($exception instanceof SensitiveException) { + $message = 'This error is sensitive and has been logged into ' . LOGS . 'error.log.
    View this file for more information.'; - // log error to file - $f = fopen(LOGS . 'error.log', 'ab'); - if(!$f) { - $message = 'We wanted to save detailed informations about this error, but file: ' . LOGS . "error.log couldn't be opened for writing.. so the detailed information couldn't be saved.. are you sure directory system/logs is writable by web server? Correct this, and then refresh this site."; - } - else { - fwrite($f, '[' . date(DateTime::RFC1123) . '] ' . $exception->getMessage() . PHP_EOL); - fclose($f); - } - } + // log error to file + $f = fopen(LOGS . 'error.log', 'ab'); + if (!$f) { + $message = 'We wanted to save detailed informations about this error, but file: ' . LOGS . "error.log couldn't be opened for writing.. so the detailed information couldn't be saved.. are you sure directory system/logs is writable by web server? Correct this, and then refresh this site."; + } else { + fwrite($f, '[' . date(DateTime::RFC1123) . '] ' . $exception->getMessage() . PHP_EOL); + fclose($f); + } + } - $backtrace_formatted = nl2br($exception->getTraceAsString()); + $backtrace_formatted = nl2br($exception->getTraceAsString()); + $message = $message . "

    File: {$exception->getFile()}
    Line: {$exception->getLine()}"; - // display basic error message without template - // template is missing, why? probably someone deleted templates dir, or it wasn't downloaded right - $template_file = SYSTEM . 'templates/exception.html.twig'; - if(!file_exists($template_file)) { - echo 'Something went terribly wrong..

    '; - echo "$message

    "; - echo 'Backtrace:
    '; - echo $backtrace_formatted; - return; - } + // display basic error message without template + // template is missing, why? probably someone deleted templates dir, or it wasn't downloaded right + $template_file = SYSTEM . 'templates/exception.html.twig'; + if (!file_exists($template_file)) { + echo 'Something went terribly wrong..

    '; + echo "$message

    "; + echo 'Backtrace:
    '; + echo $backtrace_formatted; + return; + } - // display beautiful error message - // the file is .twig.html, but its not really parsed by Twig - // we just replace some values manually - // cause in case Twig throws exception, we can show it too - $content = file_get_contents($template_file); - $content = str_replace(array('{{ BASE_URL }}', '{{ exceptionClass }}', '{{ message }}', '{{ backtrace }}', '{{ powered_by }}'), array(BASE_URL, get_class($exception), $message, $backtrace_formatted, base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=')), $content); - echo $content; + // display beautiful error message + // the file is .twig.html, but its not really parsed by Twig + // we just replace some values manually + // cause in case Twig throws exception, we can show it too + $content = file_get_contents($template_file); + $content = str_replace(array('{{ BASE_URL }}', '{{ exceptionClass }}', '{{ message }}', '{{ backtrace }}', '{{ powered_by }}'), array(BASE_URL, get_class($exception), $message, $backtrace_formatted, base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=')), $content); + echo $content; } set_exception_handler('exception_handler'); diff --git a/system/functions.php b/system/functions.php index ec309a11b6..0bc0e0bcb2 100644 --- a/system/functions.php +++ b/system/functions.php @@ -1259,6 +1259,10 @@ function getAccountLoginByLabel() return $ret; } +function escapeHtml($html) { + return htmlentities($html, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); +} + // validator functions require_once LIBS . 'validator.php'; -require_once SYSTEM . 'compat.php'; +require_once SYSTEM . 'compat/base.php'; diff --git a/system/get_version_for_release.php b/system/get_version_for_release.php new file mode 100644 index 0000000000..484e8c1b63 --- /dev/null +++ b/system/get_version_for_release.php @@ -0,0 +1,6 @@ +hasColumn('accounts', 'name')); define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number')); @@ -189,7 +189,7 @@ } else { if ($db->hasTable('towns')) { $query = $db - ->query('SELECT `towns`.`id`, `towns`.`name` FROM `towns` INNER JOIN `houses` + ->query('SELECT `towns`.`id`, `towns`.`name` FROM `towns` INNER JOIN `houses` ON `towns`.`id` = `houses`.`town_id` GROUP BY `towns`.`id` ORDER BY `towns`.`name`;') ->fetchAll(PDO::FETCH_ASSOC); diff --git a/system/libs/CreateCharacter.php b/system/libs/CreateCharacter.php index 297951b581..24df59cc38 100644 --- a/system/libs/CreateCharacter.php +++ b/system/libs/CreateCharacter.php @@ -13,68 +13,98 @@ class CreateCharacter { /** * @param string $name - * @param int $sex - * @param int $vocation - * @param int $town * @param array $errors * @return bool */ - public function check($name, $sex, &$vocation, &$town, &$errors) { - $minLength = config('character_name_min_length'); - $maxLength = config('character_name_max_length'); - - if(empty($name)) - $errors['name'] = 'Please enter a name for your character!'; - else if(strlen($name) > $maxLength) - $errors['name'] = 'Name is too long. Max. length '.$maxLength.' letters.'; - else if(strlen($name) < $minLength) - $errors['name'] = 'Name is too short. Min. length '.$minLength.' letters.'; - else { - if(!admin() && !Validator::newCharacterName($name)) { - $errors['name'] = Validator::getLastError(); - } - } + public function checkName($name, &$errors) + { + $minLength = config('character_name_min_length'); + $maxLength = config('character_name_max_length'); - if(empty($sex) && $sex != "0") - $errors['sex'] = 'Please select the sex for your character!'; + if (empty($name)) { + $errors['name'] = 'Please enter a name for your character!'; + return false; + } - if(count(config('character_samples')) > 1) - { - if(!isset($vocation)) - $errors['vocation'] = 'Please select a vocation for your character.'; - } - else - $vocation = config('character_samples')[0]; + $name_length = strlen($name); - if(count(config('character_towns')) > 1) { - if(!isset($town)) - $errors['town'] = 'Please select a town for your character.'; - } - else { - $town = config('character_towns')[0]; - } + if ($name_length > $maxLength) { + $errors['name'] = 'Name is too long. Max. length ' . $maxLength . ' letters.'; + return false; + } - if(empty($errors)) { - if(!isset(config('genders')[$sex])) - $errors['sex'] = 'Sex is invalid.'; - if(!in_array($town, config('character_towns'), false)) - $errors['town'] = 'Please select valid town.'; - if(count(config('character_samples')) > 1) - { - $newchar_vocation_check = false; - foreach((array)config('character_samples') as $char_vocation_key => $sample_char) - if($vocation === $char_vocation_key) - $newchar_vocation_check = true; - if(!$newchar_vocation_check) - $errors['vocation'] = 'Unknown vocation. Please fill in form again.'; - } - else - $vocation = 0; - } + if ($name_length < $minLength) { + $errors['name'] = 'Name is too short. Min. length ' . $minLength . ' letters.'; + return false; + } + + if (strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) { + $errors['name'] = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.'; + return false; + } + + if(!preg_match("/[A-z ']/", $name)) { + $errors['name'] = 'Your name contains illegal characters.'; + return false; + } + + if(!admin() && !Validator::newCharacterName($name)) { + $errors['name'] = Validator::getLastError(); + return false; + } return empty($errors); } + /** + * @param string $name + * @param int $sex + * @param int $vocation + * @param int $town + * @param array $errors + * @return bool + */ + public function check($name, $sex, &$vocation, &$town, &$errors) + { + $this->checkName($name, $errors); + + if(empty($sex) && $sex != "0") { + $errors['sex'] = 'Please select the sex for your character!'; + } + + if (count(config('character_samples')) > 1) { + if (!isset($vocation)) + $errors['vocation'] = 'Please select a vocation for your character.'; + } else + $vocation = config('character_samples')[0]; + + if (count(config('character_towns')) > 1) { + if (!isset($town)) { + $errors['town'] = 'Please select a town for your character.'; + } + } else { + $town = config('character_towns')[0]; + } + + if (empty($errors)) { + if (!isset(config('genders')[$sex])) + $errors['sex'] = 'Sex is invalid.'; + if (!in_array($town, config('character_towns'), false)) + $errors['town'] = 'Please select valid town.'; + if (count(config('character_samples')) > 1) { + $newchar_vocation_check = false; + foreach ((array)config('character_samples') as $char_vocation_key => $sample_char) + if ($vocation === $char_vocation_key) + $newchar_vocation_check = true; + if (!$newchar_vocation_check) + $errors['vocation'] = 'Unknown vocation. Please fill in form again.'; + } else + $vocation = 0; + } + + return empty($errors); + } + /** * @param string $name * @param int $sex @@ -96,7 +126,7 @@ public function doCreate($name, $sex, $vocation, $town, $account, &$errors) if(empty($errors)) { - $number_of_players_on_account = $account->getPlayersList()->count(); + $number_of_players_on_account = $account->getPlayersList(false)->count(); if($number_of_players_on_account >= config('characters_per_account')) $errors[] = 'You have too many characters on your account ('.$number_of_players_on_account.'/'.config('characters_per_account').')!'; } @@ -151,8 +181,10 @@ public function doCreate($name, $sex, $vocation, $town, $account, &$errors) $player->setManaSpent($char_to_copy->getManaSpent()); $player->setSoul($char_to_copy->getSoul()); - for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) - $player->setSkill($skill, 10); + for ($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) { + $player->setSkill($skill, + config('use_character_sample_skills') ? $char_to_copy->getSkill($skill) : 10); + } $player->setLookBody($char_to_copy->getLookBody()); $player->setLookFeet($char_to_copy->getLookFeet()); @@ -193,18 +225,22 @@ public function doCreate($name, $sex, $vocation, $town, $account, &$errors) return false; } - if($db->hasTable('player_skills')) { - for($i=0; $i<7; $i++) { - $skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $i); - if($skillExists->rowCount() <= 0) { - $db->query('INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ('.$player->getId().', '.$i.', 10, 0)'); - } - } - } + if ($db->hasTable('player_skills')) { + for ($i = 0; $i < 7; $i++) { + $value = config('use_character_sample_skills') ? $char_to_copy->getSkill($i) : 10; + $skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $i); + if ($skillExists->rowCount() <= 0) { + $db->query("INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ({$player->getId()}, {$i}, {$value}, 0)"); + } + } + } - $loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId().""); - foreach($loaded_items_to_copy as $save_item) - $db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', '".$save_item['attributes']."');"); + if ($db->hasTableAndColumns('player_items', ['pid', 'sid', 'itemtype'])) { + $loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = {$char_to_copy->getId()}"); + foreach ($loaded_items_to_copy as $save_item) { + $db->query("INSERT INTO `player_items` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ({$player->getId()}, {$db->quote($save_item['pid'])}, {$db->quote($save_item['sid'])}, {$db->quote($save_item['itemtype'])}, {$db->quote($save_item['count'])}, {$db->quote($save_item['attributes'])});"); + } + } global $twig; $twig->display('success.html.twig', array( diff --git a/system/libs/Twig/Cache/FilesystemCache.php b/system/libs/Twig/Cache/FilesystemCache.php index b7c1e438e7..c32c81884b 100644 --- a/system/libs/Twig/Cache/FilesystemCache.php +++ b/system/libs/Twig/Cache/FilesystemCache.php @@ -18,7 +18,7 @@ */ class FilesystemCache implements CacheInterface { - const FORCE_BYTECODE_INVALIDATION = 1; + public const FORCE_BYTECODE_INVALIDATION = 1; private $directory; private $options; @@ -35,7 +35,7 @@ public function __construct($directory, $options = 0) public function generateKey($name, $className) { - $hash = hash('sha256', $className); + $hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $className); return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php'; } @@ -67,7 +67,7 @@ public function write($key, $content) 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)) { + 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); diff --git a/system/libs/Twig/Cache/NullCache.php b/system/libs/Twig/Cache/NullCache.php index c1b37c1243..02c868cdb8 100644 --- a/system/libs/Twig/Cache/NullCache.php +++ b/system/libs/Twig/Cache/NullCache.php @@ -14,11 +14,9 @@ /** * Implements a no-cache strategy. * - * @final - * * @author Fabien Potencier */ -class NullCache implements CacheInterface +final class NullCache implements CacheInterface { public function generateKey($name, $className) { diff --git a/system/libs/Twig/Compiler.php b/system/libs/Twig/Compiler.php index e47003ae19..8727991d1b 100644 --- a/system/libs/Twig/Compiler.php +++ b/system/libs/Twig/Compiler.php @@ -12,23 +12,22 @@ namespace Twig; -use Twig\Node\ModuleNode; +use Twig\Node\Node; /** * Compiles a node to PHP code. * * @author Fabien Potencier */ -class Compiler implements \Twig_CompilerInterface +class Compiler { - protected $lastLine; - protected $source; - protected $indentation; - protected $env; - protected $debugInfo = []; - protected $sourceOffset; - protected $sourceLine; - protected $filename; + private $lastLine; + private $source; + private $indentation; + private $env; + private $debugInfo = []; + private $sourceOffset; + private $sourceLine; private $varNameSalt = 0; public function __construct(Environment $env) @@ -36,16 +35,6 @@ public function __construct(Environment $env) $this->env = $env; } - /** - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - return $this->filename; - } - /** * Returns the environment instance related to this compiler. * @@ -73,7 +62,7 @@ public function getSource() * * @return $this */ - public function compile(\Twig_NodeInterface $node, $indentation = 0) + public function compile(Node $node, $indentation = 0) { $this->lastLine = null; $this->source = ''; @@ -84,17 +73,12 @@ public function compile(\Twig_NodeInterface $node, $indentation = 0) $this->indentation = $indentation; $this->varNameSalt = 0; - if ($node instanceof ModuleNode) { - // to be removed in 2.0 - $this->filename = $node->getTemplateName(); - } - $node->compile($this); return $this; } - public function subcompile(\Twig_NodeInterface $node, $raw = true) + public function subcompile(Node $node, $raw = true) { if (false === $raw) { $this->source .= str_repeat(' ', $this->indentation * 4); @@ -124,9 +108,8 @@ public function raw($string) * * @return $this */ - public function write() + public function write(...$strings) { - $strings = \func_get_args(); foreach ($strings as $string) { $this->source .= str_repeat(' ', $this->indentation * 4).$string; } @@ -134,22 +117,6 @@ public function write() return $this; } - /** - * Appends an indentation to the current PHP code after compilation. - * - * @return $this - * - * @deprecated since 1.27 (to be removed in 2.0). - */ - public function addIndentation() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use write(\'\') instead.', E_USER_DEPRECATED); - - $this->source .= str_repeat(' ', $this->indentation * 4); - - return $this; - } - /** * Adds a quoted string to the compiled code. * @@ -174,21 +141,21 @@ public function string($value) public function repr($value) { if (\is_int($value) || \is_float($value)) { - if (false !== $locale = setlocale(LC_NUMERIC, '0')) { - setlocale(LC_NUMERIC, 'C'); + if (false !== $locale = setlocale(\LC_NUMERIC, '0')) { + setlocale(\LC_NUMERIC, 'C'); } $this->raw(var_export($value, true)); if (false !== $locale) { - setlocale(LC_NUMERIC, $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('['); + $this->raw('array('); $first = true; foreach ($value as $key => $v) { if (!$first) { @@ -199,7 +166,7 @@ public function repr($value) $this->raw(' => '); $this->repr($v); } - $this->raw(']'); + $this->raw(')'); } else { $this->string($value); } @@ -212,22 +179,12 @@ public function repr($value) * * @return $this */ - public function addDebugInfo(\Twig_NodeInterface $node) + public function addDebugInfo(Node $node) { if ($node->getTemplateLine() != $this->lastLine) { $this->write(sprintf("// line %d\n", $node->getTemplateLine())); - // when mbstring.func_overload is set to 2 - // mb_substr_count() replaces substr_count() - // but they have different signatures! - if (((int) ini_get('mbstring.func_overload')) & 2) { - @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED); - - // this is much slower than the "right" version - $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n"); - } else { - $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); - } + $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); $this->sourceOffset = \strlen($this->source); $this->debugInfo[$this->sourceLine] = $node->getTemplateLine(); @@ -281,7 +238,7 @@ public function outdent($step = 1) public function getVarName() { - return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->varNameSalt++)); + return sprintf('__internal_compile_%d', $this->varNameSalt++); } } diff --git a/system/libs/Twig/Environment.php b/system/libs/Twig/Environment.php index 1f80f3a873..96f725106f 100644 --- a/system/libs/Twig/Environment.php +++ b/system/libs/Twig/Environment.php @@ -21,65 +21,46 @@ use Twig\Extension\CoreExtension; use Twig\Extension\EscaperExtension; use Twig\Extension\ExtensionInterface; -use Twig\Extension\GlobalsInterface; -use Twig\Extension\InitRuntimeInterface; use Twig\Extension\OptimizerExtension; -use Twig\Extension\StagingExtension; use Twig\Loader\ArrayLoader; use Twig\Loader\ChainLoader; use Twig\Loader\LoaderInterface; -use Twig\Loader\SourceContextLoaderInterface; use Twig\Node\ModuleNode; +use Twig\Node\Node; use Twig\NodeVisitor\NodeVisitorInterface; use Twig\RuntimeLoader\RuntimeLoaderInterface; use Twig\TokenParser\TokenParserInterface; /** - * Stores the Twig configuration. + * Stores the Twig configuration and renders templates. * * @author Fabien Potencier */ class Environment { - const VERSION = '1.42.4'; - const VERSION_ID = 14204; - const MAJOR_VERSION = 1; - const MINOR_VERSION = 42; - const RELEASE_VERSION = 4; - const EXTRA_VERSION = ''; - - protected $charset; - protected $loader; - protected $debug; - protected $autoReload; - protected $cache; - protected $lexer; - protected $parser; - protected $compiler; - protected $baseTemplateClass; - protected $extensions; - protected $parsers; - protected $visitors; - protected $filters; - protected $tests; - protected $functions; - protected $globals; - protected $runtimeInitialized = false; - protected $extensionInitialized = false; - protected $loadedTemplates; - protected $strictVariables; - protected $unaryOperators; - protected $binaryOperators; - protected $templateClassPrefix = '__TwigTemplate_'; - protected $functionCallbacks = []; - protected $filterCallbacks = []; - protected $staging; - + public const VERSION = '2.15.4'; + public const VERSION_ID = 21504; + public const MAJOR_VERSION = 2; + public const MINOR_VERSION = 15; + public const RELEASE_VERSION = 4; + public const EXTRA_VERSION = ''; + + private $charset; + private $loader; + private $debug; + private $autoReload; + private $cache; + private $lexer; + private $parser; + private $compiler; + private $baseTemplateClass; + private $globals = []; + private $resolvedGlobals; + private $loadedTemplates; + private $strictVariables; + private $templateClassPrefix = '__TwigTemplate_'; private $originalCache; - private $bcWriteCacheFile = false; - private $bcGetCacheFilename = false; - private $lastModifiedExtension = 0; - private $extensionsByClass = []; + private $extensionSet; private $runtimeLoaders = []; private $runtimes = []; private $optionsHash; @@ -110,7 +91,6 @@ class Environment * * * autoescape: Whether to enable auto-escaping (default to html): * * false: disable auto-escaping - * * true: equivalent to html * * 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" @@ -119,18 +99,14 @@ class Environment * (default to -1 which means that all optimizations are enabled; * set it to 0 to disable). */ - public function __construct(LoaderInterface $loader = null, $options = []) + public function __construct(LoaderInterface $loader, $options = []) { - if (null !== $loader) { - $this->setLoader($loader); - } else { - @trigger_error('Not passing a "Twig\Lodaer\LoaderInterface" as the first constructor argument of "Twig\Environment" is deprecated since version 1.21.', E_USER_DEPRECATED); - } + $this->setLoader($loader); $options = array_merge([ 'debug' => false, 'charset' => 'UTF-8', - 'base_template_class' => '\Twig\Template', + 'base_template_class' => Template::class, 'strict_variables' => false, 'autoescape' => 'html', 'cache' => false, @@ -139,33 +115,19 @@ public function __construct(LoaderInterface $loader = null, $options = []) ], $options); $this->debug = (bool) $options['debug']; - $this->charset = strtoupper($options['charset']); - $this->baseTemplateClass = $options['base_template_class']; + $this->setCharset($options['charset']); + $this->baseTemplateClass = '\\'.ltrim($options['base_template_class'], '\\'); + if ('\\'.Template::class !== $this->baseTemplateClass && '\Twig_Template' !== $this->baseTemplateClass) { + @trigger_error('The "base_template_class" option on '.__CLASS__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED); + } $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'])); - $this->staging = new StagingExtension(); - - // For BC - if (\is_string($this->originalCache)) { - $r = new \ReflectionMethod($this, 'writeCacheFile'); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error('The Twig\Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - - $this->bcWriteCacheFile = true; - } - - $r = new \ReflectionMethod($this, 'getCacheFilename'); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error('The Twig\Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - - $this->bcGetCacheFilename = true; - } - } } /** @@ -175,6 +137,10 @@ public function __construct(LoaderInterface $loader = null, $options = []) */ public function getBaseTemplateClass() { + if (1 > \func_num_args() || \func_get_arg(0)) { + @trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED); + } + return $this->baseTemplateClass; } @@ -185,6 +151,8 @@ public function getBaseTemplateClass() */ public function setBaseTemplateClass($class) { + @trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED); + $this->baseTemplateClass = $class; $this->updateOptionsHash(); } @@ -296,39 +264,17 @@ public function setCache($cache) { if (\is_string($cache)) { $this->originalCache = $cache; - $this->cache = new FilesystemCache($cache); + $this->cache = new FilesystemCache($cache, $this->autoReload ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0); } elseif (false === $cache) { $this->originalCache = $cache; $this->cache = new NullCache(); - } elseif (null === $cache) { - @trigger_error('Using "null" as the cache strategy is deprecated since version 1.23 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - $this->originalCache = false; - $this->cache = new NullCache(); } elseif ($cache instanceof CacheInterface) { $this->originalCache = $this->cache = $cache; } else { - throw new \LogicException(sprintf('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.')); + throw new \LogicException('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.'); } } - /** - * Gets the cache filename for a given template. - * - * @param string $name The template name - * - * @return string|false The cache file name or false when caching is disabled - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function getCacheFilename($name) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - $key = $this->cache->generateKey($name, $this->getTemplateClass($name)); - - return !$key ? false : $key; - } - /** * Gets the template class associated with the given string. * @@ -345,26 +291,14 @@ public function getCacheFilename($name) * @param int|null $index The index if it is an embedded template * * @return string The template class name + * + * @internal */ public function getTemplateClass($name, $index = null) { $key = $this->getLoader()->getCacheKey($name).$this->optionsHash; - return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '___'.$index); - } - - /** - * Gets the template class prefix. - * - * @return string The template class prefix - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function getTemplateClassPrefix() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - return $this->templateClassPrefix; + return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index); } /** @@ -402,7 +336,7 @@ public function display($name, array $context = []) /** * Loads a template. * - * @param string|TemplateWrapper|\Twig\Template $name The template name + * @param string|TemplateWrapper $name The template name * * @throws LoaderError When the template cannot be found * @throws RuntimeError When a previously generated cache is corrupted @@ -417,6 +351,8 @@ public function load($name) } if ($name instanceof Template) { + @trigger_error('Passing a \Twig\Template instance to '.__METHOD__.' is deprecated since Twig 2.7.0, use \Twig\TemplateWrapper instead.', \E_USER_DEPRECATED); + return new TemplateWrapper($this, $name); } @@ -432,7 +368,7 @@ public function load($name) * @param string $name The template name * @param int $index The index if it is an embedded template * - * @return \Twig_TemplateInterface A template instance representing the given template name + * @return Template A template instance representing the given template name * * @throws LoaderError When the template cannot be found * @throws RuntimeError When a previously generated cache is corrupted @@ -460,11 +396,7 @@ public function loadClass($cls, $name, $index = null) } if (!class_exists($cls, false)) { - if ($this->bcGetCacheFilename) { - $key = $this->getCacheFilename($name); - } else { - $key = $this->cache->generateKey($name, $mainCls); - } + $key = $this->cache->generateKey($name, $mainCls); if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) { $this->cache->load($key); @@ -472,21 +404,10 @@ public function loadClass($cls, $name, $index = null) $source = null; if (!class_exists($cls, false)) { - $loader = $this->getLoader(); - if (!$loader instanceof SourceContextLoaderInterface) { - $source = new Source($loader->getSource($name), $name); - } else { - $source = $loader->getSourceContext($name); - } - + $source = $this->getLoader()->getSourceContext($name); $content = $this->compileSource($source); - - if ($this->bcWriteCacheFile) { - $this->writeCacheFile($key, $content); - } else { - $this->cache->write($key, $content); - $this->cache->load($key); - } + $this->cache->write($key, $content); + $this->cache->load($key); if (!class_exists($mainCls, false)) { /* Last line of defense if either $this->bcWriteCacheFile was used, @@ -496,16 +417,15 @@ public function loadClass($cls, $name, $index = null) */ 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); + 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); + } } } - if (!$this->runtimeInitialized) { - $this->initRuntime(); - } + // to be removed in 3.0 + $this->extensionSet->initRuntime($this); return $this->loadedTemplates[$cls] = new $cls($this); } @@ -523,9 +443,9 @@ public function loadClass($cls, $name, $index = null) * @throws LoaderError When the template cannot be found * @throws SyntaxError When an error occurred during compilation */ - public function createTemplate($template, $name = null) + public function createTemplate($template, string $name = null) { - $hash = hash('sha256', $template, false); + $hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false); if (null !== $name) { $name = sprintf('%s (string template %s)', $name, $hash); } else { @@ -539,19 +459,10 @@ public function createTemplate($template, $name = null) $this->setLoader($loader); try { - $template = new TemplateWrapper($this, $this->loadTemplate($name)); - } catch (\Exception $e) { + return new TemplateWrapper($this, $this->loadTemplate($name)); + } finally { $this->setLoader($current); - - throw $e; - } catch (\Throwable $e) { - $this->setLoader($current); - - throw $e; } - $this->setLoader($current); - - return $template; } /** @@ -568,16 +479,7 @@ public function createTemplate($template, $name = null) */ public function isTemplateFresh($name, $time) { - if (0 === $this->lastModifiedExtension) { - foreach ($this->extensions as $extension) { - $r = new \ReflectionObject($extension); - if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) { - $this->lastModifiedExtension = $extensionTime; - } - } - } - - return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time); + return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time); } /** @@ -586,7 +488,7 @@ public function isTemplateFresh($name, $time) * 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|Template|\Twig\TemplateWrapper|array $names A template or an array of templates to try consecutively + * @param string|TemplateWrapper|array $names A template or an array of templates to try consecutively * * @return TemplateWrapper|Template * @@ -599,6 +501,7 @@ public function resolveTemplate($names) $names = [$names]; } + $count = \count($names); foreach ($names as $name) { if ($name instanceof Template) { return $name; @@ -607,67 +510,17 @@ public function resolveTemplate($names) return $name; } - try { - return $this->loadTemplate($name); - } catch (LoaderError $e) { - if (1 === \count($names)) { - throw $e; - } - } - } - - throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); - } - - /** - * Clears the internal template cache. - * - * @deprecated since 1.18.3 (to be removed in 2.0) - */ - public function clearTemplateCache() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.18.3 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - $this->loadedTemplates = []; - } - - /** - * Clears the template cache files on the filesystem. - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function clearCacheFiles() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - if (\is_string($this->originalCache)) { - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->originalCache), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - if ($file->isFile()) { - @unlink($file->getPathname()); - } + if (1 !== $count && !$this->getLoader()->exists($name)) { + continue; } - } - } - - /** - * Gets the Lexer instance. - * - * @return \Twig_LexerInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getLexer() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - if (null === $this->lexer) { - $this->lexer = new Lexer($this); + return $this->loadTemplate($name); } - return $this->lexer; + throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); } - public function setLexer(\Twig_LexerInterface $lexer) + public function setLexer(Lexer $lexer) { $this->lexer = $lexer; } @@ -675,20 +528,12 @@ public function setLexer(\Twig_LexerInterface $lexer) /** * Tokenizes a source code. * - * @param string|Source $source The template source code - * @param string $name The template name (deprecated) - * * @return TokenStream * * @throws SyntaxError When the code is syntactically wrong */ - public function tokenize($source, $name = null) + public function tokenize(Source $source) { - if (!$source instanceof Source) { - @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Source($source, $name); - } - if (null === $this->lexer) { $this->lexer = new Lexer($this); } @@ -696,25 +541,7 @@ public function tokenize($source, $name = null) return $this->lexer->tokenize($source); } - /** - * Gets the Parser instance. - * - * @return \Twig_ParserInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getParser() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->parser) { - $this->parser = new Parser($this); - } - - return $this->parser; - } - - public function setParser(\Twig_ParserInterface $parser) + public function setParser(Parser $parser) { $this->parser = $parser; } @@ -735,25 +562,7 @@ public function parse(TokenStream $stream) return $this->parser->parse($stream); } - /** - * Gets the Compiler instance. - * - * @return \Twig_CompilerInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getCompiler() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->compiler) { - $this->compiler = new Compiler($this); - } - - return $this->compiler; - } - - public function setCompiler(\Twig_CompilerInterface $compiler) + public function setCompiler(Compiler $compiler) { $this->compiler = $compiler; } @@ -763,7 +572,7 @@ public function setCompiler(\Twig_CompilerInterface $compiler) * * @return string The compiled PHP source code */ - public function compile(\Twig_NodeInterface $node) + public function compile(Node $node) { if (null === $this->compiler) { $this->compiler = new Compiler($this); @@ -775,20 +584,12 @@ public function compile(\Twig_NodeInterface $node) /** * Compiles a template source code. * - * @param string|Source $source The template source code - * @param string $name The template name (deprecated) - * * @return string The compiled PHP source code * * @throws SyntaxError When there was an error during tokenizing, parsing or compiling */ - public function compileSource($source, $name = null) + public function compileSource(Source $source) { - if (!$source instanceof Source) { - @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Source($source, $name); - } - try { return $this->compile($this->parse($this->tokenize($source))); } catch (Error $e) { @@ -801,10 +602,6 @@ public function compileSource($source, $name = null) public function setLoader(LoaderInterface $loader) { - if (!$loader instanceof SourceContextLoaderInterface && 0 !== strpos(\get_class($loader), 'Mock_')) { - @trigger_error(sprintf('Twig loader "%s" should implement Twig\Loader\SourceContextLoaderInterface since version 1.27.', \get_class($loader)), E_USER_DEPRECATED); - } - $this->loader = $loader; } @@ -815,10 +612,6 @@ public function setLoader(LoaderInterface $loader) */ public function getLoader() { - if (null === $this->loader) { - throw new \LogicException('You must set a loader first.'); - } - return $this->loader; } @@ -829,7 +622,12 @@ public function getLoader() */ public function setCharset($charset) { - $this->charset = strtoupper($charset); + if ('UTF8' === $charset = null === $charset ? null : strtoupper($charset)) { + // iconv on Windows requires "UTF-8" instead of "UTF8" + $charset = 'UTF-8'; + } + + $this->charset = $charset; } /** @@ -842,29 +640,6 @@ public function getCharset() return $this->charset; } - /** - * Initializes the runtime environment. - * - * @deprecated since 1.23 (to be removed in 2.0) - */ - public function initRuntime() - { - $this->runtimeInitialized = true; - - foreach ($this->getExtensions() as $name => $extension) { - if (!$extension instanceof InitRuntimeInterface) { - $m = new \ReflectionMethod($extension, 'initRuntime'); - - $parentClass = $m->getDeclaringClass()->getName(); - if ('Twig_Extension' !== $parentClass && 'Twig\Extension\AbstractExtension' !== $parentClass) { - @trigger_error(sprintf('Defining the initRuntime() method in the "%s" extension is deprecated since version 1.23. Use the `needs_environment` option to get the \Twig_Environment instance in filters, functions, or tests; or explicitly implement Twig\Extension\InitRuntimeInterface if needed (not recommended).', $name), E_USER_DEPRECATED); - } - } - - $extension->initRuntime($this); - } - } - /** * Returns true if the given extension is registered. * @@ -874,22 +649,7 @@ public function initRuntime() */ public function hasExtension($class) { - $class = ltrim($class, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new \ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== \get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - return true; - } - - return isset($this->extensionsByClass[$class]); + return $this->extensionSet->hasExtension($class); } /** @@ -909,26 +669,7 @@ public function addRuntimeLoader(RuntimeLoaderInterface $loader) */ public function getExtension($class) { - $class = ltrim($class, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new \ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== \get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - return $this->extensions[$class]; - } - - if (!isset($this->extensionsByClass[$class])) { - throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class)); - } - - return $this->extensionsByClass[$class]; + return $this->extensionSet->getExtension($class); } /** @@ -957,57 +698,7 @@ public function getRuntime($class) public function addExtension(ExtensionInterface $extension) { - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); - } - - $class = \get_class($extension); - if ($class !== $extension->getName()) { - if (isset($this->extensions[$extension->getName()])) { - unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]); - @trigger_error(sprintf('The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.', $extension->getName()), E_USER_DEPRECATED); - } - } - - $this->lastModifiedExtension = 0; - $this->extensionsByClass[$class] = $extension; - $this->extensions[$extension->getName()] = $extension; - $this->updateOptionsHash(); - } - - /** - * Removes an extension by name. - * - * This method is deprecated and you should not use it. - * - * @param string $name The extension name - * - * @deprecated since 1.12 (to be removed in 2.0) - */ - public function removeExtension($name) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); - } - - $class = ltrim($name, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new \ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== \get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - unset($this->extensions[$class]); - } - - unset($this->extensions[$class]); + $this->extensionSet->addExtension($extension); $this->updateOptionsHash(); } @@ -1018,9 +709,8 @@ public function removeExtension($name) */ public function setExtensions(array $extensions) { - foreach ($extensions as $extension) { - $this->addExtension($extension); - } + $this->extensionSet->setExtensions($extensions); + $this->updateOptionsHash(); } /** @@ -1030,39 +720,29 @@ public function setExtensions(array $extensions) */ public function getExtensions() { - return $this->extensions; + return $this->extensionSet->getExtensions(); } public function addTokenParser(TokenParserInterface $parser) { - if ($this->extensionInitialized) { - throw new \LogicException('Unable to add a token parser as extensions have already been initialized.'); - } - - $this->staging->addTokenParser($parser); + $this->extensionSet->addTokenParser($parser); } /** * Gets the registered Token Parsers. * - * @return \Twig_TokenParserBrokerInterface + * @return TokenParserInterface[] * * @internal */ public function getTokenParsers() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->parsers; + return $this->extensionSet->getTokenParsers(); } /** * Gets registered tags. * - * Be warned that this method cannot return tags defined by \Twig_TokenParserBrokerInterface classes. - * * @return TokenParserInterface[] * * @internal @@ -1070,10 +750,8 @@ public function getTokenParsers() public function getTags() { $tags = []; - foreach ($this->getTokenParsers()->getParsers() as $parser) { - if ($parser instanceof TokenParserInterface) { - $tags[$parser->getTag()] = $parser; - } + foreach ($this->getTokenParsers() as $parser) { + $tags[$parser->getTag()] = $parser; } return $tags; @@ -1081,11 +759,7 @@ public function getTags() public function addNodeVisitor(NodeVisitorInterface $visitor) { - if ($this->extensionInitialized) { - throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.'); - } - - $this->staging->addNodeVisitor($visitor); + $this->extensionSet->addNodeVisitor($visitor); } /** @@ -1097,37 +771,12 @@ public function addNodeVisitor(NodeVisitorInterface $visitor) */ public function getNodeVisitors() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->visitors; + return $this->extensionSet->getNodeVisitors(); } - /** - * Registers a Filter. - * - * @param string|TwigFilter $name The filter name or a \Twig_SimpleFilter instance - * @param \Twig_FilterInterface|TwigFilter $filter - */ - public function addFilter($name, $filter = null) + public function addFilter(TwigFilter $filter) { - if (!$name instanceof TwigFilter && !($filter instanceof TwigFilter || $filter instanceof \Twig_FilterInterface)) { - throw new \LogicException('A filter must be an instance of \Twig_FilterInterface or \Twig_SimpleFilter.'); - } - - if ($name instanceof TwigFilter) { - $filter = $name; - $name = $filter->getName(); - } else { - @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFilter" instead when defining filter "%s".', __METHOD__, $name), E_USER_DEPRECATED); - } - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addFilter($name, $filter); + $this->extensionSet->addFilter($filter); } /** @@ -1138,45 +787,18 @@ public function addFilter($name, $filter = null) * * @param string $name The filter name * - * @return \Twig_Filter|false + * @return TwigFilter|false * * @internal */ public function getFilter($name) { - if (!$this->extensionInitialized) { - $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) { - if (preg_match('#^'.$pattern.'$#', $name, $matches)) { - array_shift($matches); - $filter->setArguments($matches); - - return $filter; - } - } - } - - foreach ($this->filterCallbacks as $callback) { - if (false !== $filter = \call_user_func($callback, $name)) { - return $filter; - } - } - - return false; + return $this->extensionSet->getFilter($name); } - public function registerUndefinedFilterCallback($callable) + public function registerUndefinedFilterCallback(callable $callable) { - $this->filterCallbacks[] = $callable; + $this->extensionSet->registerUndefinedFilterCallback($callable); } /** @@ -1184,7 +806,7 @@ public function registerUndefinedFilterCallback($callable) * * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback. * - * @return \Twig_FilterInterface[] + * @return TwigFilter[] * * @see registerUndefinedFilterCallback * @@ -1192,53 +814,24 @@ public function registerUndefinedFilterCallback($callable) */ public function getFilters() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->filters; + return $this->extensionSet->getFilters(); } - /** - * Registers a Test. - * - * @param string|TwigTest $name The test name or a \Twig_SimpleTest instance - * @param \Twig_TestInterface|TwigTest $test A \Twig_TestInterface instance or a \Twig_SimpleTest instance - */ - public function addTest($name, $test = null) + public function addTest(TwigTest $test) { - if (!$name instanceof TwigTest && !($test instanceof TwigTest || $test instanceof \Twig_TestInterface)) { - throw new \LogicException('A test must be an instance of \Twig_TestInterface or \Twig_SimpleTest.'); - } - - if ($name instanceof TwigTest) { - $test = $name; - $name = $test->getName(); - } else { - @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleTest" instead when defining test "%s".', __METHOD__, $name), E_USER_DEPRECATED); - } - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addTest($name, $test); + $this->extensionSet->addTest($test); } /** * Gets the registered Tests. * - * @return \Twig_TestInterface[] + * @return TwigTest[] * * @internal */ public function getTests() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->tests; + return $this->extensionSet->getTests(); } /** @@ -1246,60 +839,18 @@ public function getTests() * * @param string $name The test name * - * @return \Twig_Test|false + * @return TwigTest|false * * @internal */ public function getTest($name) { - if (!$this->extensionInitialized) { - $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 false; + return $this->extensionSet->getTest($name); } - /** - * Registers a Function. - * - * @param string|TwigFunction $name The function name or a \Twig_SimpleFunction instance - * @param \Twig_FunctionInterface|TwigFunction $function - */ - public function addFunction($name, $function = null) + public function addFunction(TwigFunction $function) { - if (!$name instanceof TwigFunction && !($function instanceof TwigFunction || $function instanceof \Twig_FunctionInterface)) { - throw new \LogicException('A function must be an instance of \Twig_FunctionInterface or \Twig_SimpleFunction.'); - } - - if ($name instanceof TwigFunction) { - $function = $name; - $name = $function->getName(); - } else { - @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFunction" instead when defining function "%s".', __METHOD__, $name), E_USER_DEPRECATED); - } - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addFunction($name, $function); + $this->extensionSet->addFunction($function); } /** @@ -1310,45 +861,18 @@ public function addFunction($name, $function = null) * * @param string $name function name * - * @return \Twig_Function|false + * @return TwigFunction|false * * @internal */ public function getFunction($name) { - if (!$this->extensionInitialized) { - $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) { - if (preg_match('#^'.$pattern.'$#', $name, $matches)) { - array_shift($matches); - $function->setArguments($matches); - - return $function; - } - } - } - - foreach ($this->functionCallbacks as $callback) { - if (false !== $function = \call_user_func($callback, $name)) { - return $function; - } - } - - return false; + return $this->extensionSet->getFunction($name); } - public function registerUndefinedFunctionCallback($callable) + public function registerUndefinedFunctionCallback(callable $callable) { - $this->functionCallbacks[] = $callable; + $this->extensionSet->registerUndefinedFunctionCallback($callable); } /** @@ -1356,7 +880,7 @@ public function registerUndefinedFunctionCallback($callable) * * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. * - * @return \Twig_FunctionInterface[] + * @return TwigFunction[] * * @see registerUndefinedFunctionCallback * @@ -1364,11 +888,7 @@ public function registerUndefinedFunctionCallback($callable) */ public function getFunctions() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->functions; + return $this->extensionSet->getFunctions(); } /** @@ -1382,23 +902,14 @@ public function getFunctions() */ public function addGlobal($name, $value) { - if ($this->extensionInitialized || $this->runtimeInitialized) { - if (null === $this->globals) { - $this->globals = $this->initGlobals(); - } - - if (!\array_key_exists($name, $this->globals)) { - // The deprecation notice must be turned into the following exception in Twig 2.0 - @trigger_error(sprintf('Registering global variable "%s" at runtime or when the extensions have already been initialized is deprecated since version 1.21.', $name), E_USER_DEPRECATED); - //throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); - } + if ($this->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 ($this->extensionInitialized || $this->runtimeInitialized) { - // update the value - $this->globals[$name] = $value; + if (null !== $this->resolvedGlobals) { + $this->resolvedGlobals[$name] = $value; } else { - $this->staging->addGlobal($name, $value); + $this->globals[$name] = $value; } } @@ -1411,15 +922,15 @@ public function addGlobal($name, $value) */ public function getGlobals() { - if (!$this->runtimeInitialized && !$this->extensionInitialized) { - return $this->initGlobals(); - } + if ($this->extensionSet->isInitialized()) { + if (null === $this->resolvedGlobals) { + $this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals); + } - if (null === $this->globals) { - $this->globals = $this->initGlobals(); + return $this->resolvedGlobals; } - return $this->globals; + return array_merge($this->extensionSet->getGlobals(), $this->globals); } /** @@ -1451,11 +962,7 @@ public function mergeGlobals(array $context) */ public function getUnaryOperators() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->unaryOperators; + return $this->extensionSet->getUnaryOperators(); } /** @@ -1467,171 +974,20 @@ public function getUnaryOperators() */ public function getBinaryOperators() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->binaryOperators; - } - - /** - * @deprecated since 1.23 (to be removed in 2.0) - */ - public function computeAlternatives($name, $items) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - return SyntaxError::computeAlternatives($name, $items); - } - - /** - * @internal - */ - protected function initGlobals() - { - $globals = []; - foreach ($this->extensions as $name => $extension) { - if (!$extension instanceof GlobalsInterface) { - $m = new \ReflectionMethod($extension, 'getGlobals'); - - $parentClass = $m->getDeclaringClass()->getName(); - if ('Twig_Extension' !== $parentClass && 'Twig\Extension\AbstractExtension' !== $parentClass) { - @trigger_error(sprintf('Defining the getGlobals() method in the "%s" extension without explicitly implementing Twig\Extension\GlobalsInterface is deprecated since version 1.23.', $name), E_USER_DEPRECATED); - } - } - - $extGlob = $extension->getGlobals(); - if (!\is_array($extGlob)) { - throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension))); - } - - $globals[] = $extGlob; - } - - $globals[] = $this->staging->getGlobals(); - - return \call_user_func_array('array_merge', $globals); - } - - /** - * @internal - */ - protected function initExtensions() - { - if ($this->extensionInitialized) { - return; - } - - $this->parsers = new \Twig_TokenParserBroker([], [], false); - $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->extensionInitialized = true; - } - - /** - * @internal - */ - protected function initExtension(ExtensionInterface $extension) - { - // filters - foreach ($extension->getFilters() as $name => $filter) { - if ($filter instanceof TwigFilter) { - $name = $filter->getName(); - } else { - @trigger_error(sprintf('Using an instance of "%s" for filter "%s" is deprecated since version 1.21. Use \Twig_SimpleFilter instead.', \get_class($filter), $name), E_USER_DEPRECATED); - } - - $this->filters[$name] = $filter; - } - - // functions - foreach ($extension->getFunctions() as $name => $function) { - if ($function instanceof TwigFunction) { - $name = $function->getName(); - } else { - @trigger_error(sprintf('Using an instance of "%s" for function "%s" is deprecated since version 1.21. Use \Twig_SimpleFunction instead.', \get_class($function), $name), E_USER_DEPRECATED); - } - - $this->functions[$name] = $function; - } - - // tests - foreach ($extension->getTests() as $name => $test) { - if ($test instanceof TwigTest) { - $name = $test->getName(); - } else { - @trigger_error(sprintf('Using an instance of "%s" for test "%s" is deprecated since version 1.21. Use \Twig_SimpleTest instead.', \get_class($test), $name), E_USER_DEPRECATED); - } - - $this->tests[$name] = $test; - } - - // token parsers - foreach ($extension->getTokenParsers() as $parser) { - if ($parser instanceof TokenParserInterface) { - $this->parsers->addTokenParser($parser); - } elseif ($parser instanceof \Twig_TokenParserBrokerInterface) { - @trigger_error('Registering a \Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.', E_USER_DEPRECATED); - - $this->parsers->addTokenParserBroker($parser); - } else { - throw new \LogicException('getTokenParsers() must return an array of \Twig_TokenParserInterface or \Twig_TokenParserBrokerInterface instances.'); - } - } - - // 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]); - } - } - - /** - * @deprecated since 1.22 (to be removed in 2.0) - */ - protected function writeCacheFile($file, $content) - { - $this->cache->write($file, $content); + return $this->extensionSet->getBinaryOperators(); } private function updateOptionsHash() { - $hashParts = array_merge( - array_keys($this->extensions), - [ - (int) \function_exists('twig_template_get_attributes'), - PHP_MAJOR_VERSION, - PHP_MINOR_VERSION, - self::VERSION, - (int) $this->debug, - $this->baseTemplateClass, - (int) $this->strictVariables, - ] - ); - $this->optionsHash = implode(':', $hashParts); + $this->optionsHash = implode(':', [ + $this->extensionSet->getSignature(), + \PHP_MAJOR_VERSION, + \PHP_MINOR_VERSION, + self::VERSION, + (int) $this->debug, + $this->baseTemplateClass, + (int) $this->strictVariables, + ]); } } diff --git a/system/libs/Twig/Error/Error.php b/system/libs/Twig/Error/Error.php index 2aa70f1538..13f6f745ce 100644 --- a/system/libs/Twig/Error/Error.php +++ b/system/libs/Twig/Error/Error.php @@ -38,11 +38,9 @@ */ class Error extends \Exception { - protected $lineno; - // to be renamed to name in 2.0 - protected $filename; - protected $rawMessage; - + private $lineno; + private $name; + private $rawMessage; private $sourcePath; private $sourceCode; @@ -57,22 +55,23 @@ class Error extends \Exception * @param Source|string|null $source The source context where the error occurred * @param \Exception $previous The previous exception */ - public function __construct($message, $lineno = -1, $source = null, \Exception $previous = null) + public function __construct(string $message, int $lineno = -1, $source = null, \Exception $previous = null) { + parent::__construct('', 0, $previous); + if (null === $source) { $name = null; - } elseif (!$source instanceof Source) { - // for compat with the Twig C ext., passing the template name as string is accepted + } elseif (!$source instanceof Source && !$source instanceof \Twig_Source) { + @trigger_error(sprintf('Passing a string as a source to %s is deprecated since Twig 2.6.1; pass a Twig\Source instance instead.', __CLASS__), \E_USER_DEPRECATED); $name = $source; } else { $name = $source->getName(); $this->sourceCode = $source->getCode(); $this->sourcePath = $source->getPath(); } - parent::__construct('', 0, $previous); $this->lineno = $lineno; - $this->filename = $name; + $this->name = $name; $this->rawMessage = $message; $this->updateRepr(); } @@ -87,67 +86,6 @@ public function getRawMessage() return $this->rawMessage; } - /** - * Gets the logical name where the error occurred. - * - * @return string The name - * - * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead. - */ - public function getTemplateFile() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->filename; - } - - /** - * Sets the logical name where the error occurred. - * - * @param string $name The name - * - * @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead. - */ - public function setTemplateFile($name) - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - $this->filename = $name; - - $this->updateRepr(); - } - - /** - * Gets the logical name where the error occurred. - * - * @return string The name - * - * @deprecated since 1.29 (to be removed in 2.0). Use getSourceContext() instead. - */ - public function getTemplateName() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->filename; - } - - /** - * Sets the logical name where the error occurred. - * - * @param string $name The name - * - * @deprecated since 1.29 (to be removed in 2.0). Use setSourceContext() instead. - */ - public function setTemplateName($name) - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - $this->filename = $name; - $this->sourceCode = $this->sourcePath = null; - - $this->updateRepr(); - } - /** * Gets the template line where the error occurred. * @@ -177,7 +115,7 @@ public function setTemplateLine($lineno) */ public function getSourceContext() { - return $this->filename ? new Source($this->sourceCode, $this->filename, $this->sourcePath) : null; + return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null; } /** @@ -186,10 +124,10 @@ public function getSourceContext() public function setSourceContext(Source $source = null) { if (null === $source) { - $this->sourceCode = $this->filename = $this->sourcePath = null; + $this->sourceCode = $this->name = $this->sourcePath = null; } else { $this->sourceCode = $source->getCode(); - $this->filename = $source->getName(); + $this->name = $source->getName(); $this->sourcePath = $source->getPath(); } @@ -208,10 +146,7 @@ public function appendMessage($rawMessage) $this->updateRepr(); } - /** - * @internal - */ - protected function updateRepr() + private function updateRepr() { $this->message = $this->rawMessage; @@ -234,11 +169,11 @@ protected function updateRepr() $questionMark = true; } - if ($this->filename) { - if (\is_string($this->filename) || (\is_object($this->filename) && method_exists($this->filename, '__toString'))) { - $name = sprintf('"%s"', $this->filename); + 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->filename); + $name = json_encode($this->name); } $this->message .= sprintf(' in %s', $name); } @@ -256,20 +191,17 @@ protected function updateRepr() } } - /** - * @internal - */ - protected function guessTemplateInfo() + private function guessTemplateInfo() { $template = null; $templateClass = null; - $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT); + $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT); foreach ($backtrace as $trace) { - if (isset($trace['object']) && $trace['object'] instanceof Template && 'Twig_Template' !== \get_class($trace['object'])) { + if (isset($trace['object']) && $trace['object'] instanceof Template && 'Twig\Template' !== \get_class($trace['object'])) { $currentClass = \get_class($trace['object']); - $isEmbedContainer = 0 === strpos($templateClass, $currentClass); - if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) { + $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']); } @@ -277,8 +209,8 @@ protected function guessTemplateInfo() } // update template name - if (null !== $template && null === $this->filename) { - $this->filename = $template->getTemplateName(); + if (null !== $template && null === $this->name) { + $this->name = $template->getTemplateName(); } // update template path if any @@ -296,7 +228,7 @@ protected function guessTemplateInfo() $file = $r->getFileName(); $exceptions = [$e = $this]; - while ($e instanceof self && $e = $e->getPrevious()) { + while ($e = $e->getPrevious()) { $exceptions[] = $e; } diff --git a/system/libs/Twig/Error/SyntaxError.php b/system/libs/Twig/Error/SyntaxError.php index 480e660621..efece9256c 100644 --- a/system/libs/Twig/Error/SyntaxError.php +++ b/system/libs/Twig/Error/SyntaxError.php @@ -26,20 +26,6 @@ class SyntaxError extends Error * @param array $items An array of possible items */ public function addSuggestions($name, array $items) - { - if (!$alternatives = self::computeAlternatives($name, $items)) { - return; - } - - $this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', $alternatives))); - } - - /** - * @internal - * - * To be merged with the addSuggestions() method in 2.0. - */ - public static function computeAlternatives($name, $items) { $alternatives = []; foreach ($items as $item) { @@ -48,9 +34,14 @@ public static function computeAlternatives($name, $items) $alternatives[$item] = $lev; } } + + if (!$alternatives) { + return; + } + asort($alternatives); - return array_keys($alternatives); + $this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives)))); } } diff --git a/system/libs/Twig/ExpressionParser.php b/system/libs/Twig/ExpressionParser.php index 9066ade169..b0bcf10809 100644 --- a/system/libs/Twig/ExpressionParser.php +++ b/system/libs/Twig/ExpressionParser.php @@ -13,6 +13,7 @@ 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; @@ -24,6 +25,7 @@ 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\NegUnary; use Twig\Node\Expression\Unary\NotUnary; use Twig\Node\Expression\Unary\PosUnary; @@ -43,30 +45,20 @@ */ class ExpressionParser { - const OPERATOR_LEFT = 1; - const OPERATOR_RIGHT = 2; - - protected $parser; - protected $unaryOperators; - protected $binaryOperators; + public const OPERATOR_LEFT = 1; + public const OPERATOR_RIGHT = 2; + private $parser; private $env; + private $unaryOperators; + private $binaryOperators; - public function __construct(Parser $parser, $env = null) + public function __construct(Parser $parser, Environment $env) { $this->parser = $parser; - - if ($env instanceof Environment) { - $this->env = $env; - $this->unaryOperators = $env->getUnaryOperators(); - $this->binaryOperators = $env->getBinaryOperators(); - } else { - @trigger_error('Passing the operators as constructor arguments to '.__METHOD__.' is deprecated since version 1.27. Pass the environment instead.', E_USER_DEPRECATED); - - $this->env = $parser->getEnvironment(); - $this->unaryOperators = func_get_arg(1); - $this->binaryOperators = func_get_arg(2); - } + $this->env = $env; + $this->unaryOperators = $env->getUnaryOperators(); + $this->binaryOperators = $env->getBinaryOperators(); } public function parseExpression($precedence = 0, $allowArrow = false) @@ -86,7 +78,7 @@ public function parseExpression($precedence = 0, $allowArrow = false) } elseif ('is' === $token->getValue()) { $expr = $this->parseTestExpression($expr); } elseif (isset($op['callable'])) { - $expr = \call_user_func($op['callable'], $this->parser, $expr); + $expr = $op['callable']($this->parser, $expr); } else { $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); $class = $op['class']; @@ -111,57 +103,57 @@ private function parseArrow() $stream = $this->parser->getStream(); // short array syntax (one argument, no parentheses)? - if ($stream->look(1)->test(Token::ARROW_TYPE)) { + if ($stream->look(1)->test(/* Token::ARROW_TYPE */ 12)) { $line = $stream->getCurrent()->getLine(); - $token = $stream->expect(Token::NAME_TYPE); + $token = $stream->expect(/* Token::NAME_TYPE */ 5); $names = [new AssignNameExpression($token->getValue(), $token->getLine())]; - $stream->expect(Token::ARROW_TYPE); + $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, '(')) { + 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, ',')) { + if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } ++$i; } - if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ')')) { + if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) { return null; } ++$i; - if (!$stream->look($i)->test(Token::ARROW_TYPE)) { + if (!$stream->look($i)->test(/* Token::ARROW_TYPE */ 12)) { return null; } // yes, let's parse it properly - $token = $stream->expect(Token::PUNCTUATION_TYPE, '('); + $token = $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '('); $line = $token->getLine(); $names = []; while (true) { - $token = $stream->expect(Token::NAME_TYPE); + $token = $stream->expect(/* Token::NAME_TYPE */ 5); $names[] = new AssignNameExpression($token->getValue(), $token->getLine()); - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } - $stream->expect(Token::PUNCTUATION_TYPE, ')'); - $stream->expect(Token::ARROW_TYPE); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')'); + $stream->expect(/* Token::ARROW_TYPE */ 12); return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line); } - protected function getPrimary() + private function getPrimary(): AbstractExpression { $token = $this->parser->getCurrentToken(); @@ -172,10 +164,10 @@ protected function getPrimary() $class = $operator['class']; return $this->parsePostfixExpression(new $class($expr, $token->getLine())); - } elseif ($token->test(Token::PUNCTUATION_TYPE, '(')) { + } elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $this->parser->getStream()->next(); $expr = $this->parseExpression(); - $this->parser->getStream()->expect(Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); + $this->parser->getStream()->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'An opened parenthesis is not properly closed'); return $this->parsePostfixExpression($expr); } @@ -183,12 +175,12 @@ protected function getPrimary() return $this->parsePrimaryExpression(); } - protected function parseConditionalExpression($expr) + private function parseConditionalExpression($expr): AbstractExpression { - while ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, '?')) { - if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) { + 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, ':')) { + if ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) { $expr3 = $this->parseExpression(); } else { $expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine()); @@ -204,21 +196,21 @@ protected function parseConditionalExpression($expr) return $expr; } - protected function isUnary(Token $token) + private function isUnary(Token $token): bool { - return $token->test(Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); + return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->unaryOperators[$token->getValue()]); } - protected function isBinary(Token $token) + private function isBinary(Token $token): bool { - return $token->test(Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); + 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: + case /* Token::NAME_TYPE */ 5: $this->parser->getStream()->next(); switch ($token->getValue()) { case 'true': @@ -247,17 +239,17 @@ public function parsePrimaryExpression() } break; - case Token::NUMBER_TYPE: + case /* Token::NUMBER_TYPE */ 6: $this->parser->getStream()->next(); $node = new ConstantExpression($token->getValue(), $token->getLine()); break; - case Token::STRING_TYPE: - case Token::INTERPOLATION_START_TYPE: + case /* Token::STRING_TYPE */ 7: + case /* Token::INTERPOLATION_START_TYPE */ 10: $node = $this->parseStringExpression(); break; - case Token::OPERATOR_TYPE: + 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(); @@ -267,10 +259,8 @@ public function parsePrimaryExpression() $class = $this->unaryOperators[$token->getValue()]['class']; $ref = new \ReflectionClass($class); - $negClass = 'Twig\Node\Expression\Unary\NegUnary'; - $posClass = 'Twig\Node\Expression\Unary\PosUnary'; - if (!(\in_array($ref->getName(), [$negClass, $posClass, 'Twig_Node_Expression_Unary_Neg', 'Twig_Node_Expression_Unary_Pos']) - || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass) + if (!(\in_array($ref->getName(), [NegUnary::class, PosUnary::class, 'Twig_Node_Expression_Unary_Neg', 'Twig_Node_Expression_Unary_Pos']) + || $ref->isSubclassOf(NegUnary::class) || $ref->isSubclassOf(PosUnary::class) || $ref->isSubclassOf('Twig_Node_Expression_Unary_Neg') || $ref->isSubclassOf('Twig_Node_Expression_Unary_Pos')) ) { throw new SyntaxError(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); @@ -285,11 +275,11 @@ public function parsePrimaryExpression() // no break default: - if ($token->test(Token::PUNCTUATION_TYPE, '[')) { + if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) { $node = $this->parseArrayExpression(); - } elseif ($token->test(Token::PUNCTUATION_TYPE, '{')) { + } elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) { $node = $this->parseHashExpression(); - } elseif ($token->test(Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) { + } 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()); @@ -307,12 +297,12 @@ public function parseStringExpression() // a string cannot be followed by another string in a single expression $nextCanBeString = true; while (true) { - if ($nextCanBeString && $token = $stream->nextIf(Token::STRING_TYPE)) { + 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)) { + } elseif ($stream->nextIf(/* Token::INTERPOLATION_START_TYPE */ 10)) { $nodes[] = $this->parseExpression(); - $stream->expect(Token::INTERPOLATION_END_TYPE); + $stream->expect(/* Token::INTERPOLATION_END_TYPE */ 11); $nextCanBeString = true; } else { break; @@ -330,16 +320,16 @@ public function parseStringExpression() public function parseArrayExpression() { $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '[', 'An array element was expected'); + $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, ']')) { + while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { if (!$first) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma'); // trailing ,? - if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { break; } } @@ -347,7 +337,7 @@ public function parseArrayExpression() $node->addElement($this->parseExpression()); } - $stream->expect(Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed'); return $node; } @@ -355,16 +345,16 @@ public function parseArrayExpression() public function parseHashExpression() { $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); + $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, '}')) { + while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) { if (!$first) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma'); // trailing ,? - if ($stream->test(Token::PUNCTUATION_TYPE, '}')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) { break; } } @@ -376,9 +366,18 @@ public function parseHashExpression() // * 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::STRING_TYPE)) || ($token = $stream->nextIf(Token::NAME_TYPE)) || $token = $stream->nextIf(Token::NUMBER_TYPE)) { + if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) { $key = new ConstantExpression($token->getValue(), $token->getLine()); - } elseif ($stream->test(Token::PUNCTUATION_TYPE, '(')) { + + // {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(); @@ -386,12 +385,12 @@ public function parseHashExpression() 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, ':', 'A hash key must be followed by a colon (:)'); + $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, '}', 'An opened hash is not properly closed'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed'); return $node; } @@ -400,7 +399,7 @@ public function parsePostfixExpression($node) { while (true) { $token = $this->parser->getCurrentToken(); - if (Token::PUNCTUATION_TYPE == $token->getType()) { + if (/* Token::PUNCTUATION_TYPE */ 9 == $token->getType()) { if ('.' == $token->getValue() || '[' == $token->getValue()) { $node = $this->parseSubscriptExpression($node); } elseif ('|' == $token->getValue()) { @@ -474,22 +473,22 @@ public function parseSubscriptExpression($node) if ('.' == $token->getValue()) { $token = $stream->next(); if ( - Token::NAME_TYPE == $token->getType() + /* Token::NAME_TYPE */ 5 == $token->getType() || - Token::NUMBER_TYPE == $token->getType() + /* Token::NUMBER_TYPE */ 6 == $token->getType() || - (Token::OPERATOR_TYPE == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue())) + (/* 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, '(')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $type = Template::METHOD_CALL; foreach ($this->parseArguments() as $n) { $arguments->addElement($n); } } } else { - throw new SyntaxError('Expected name or number.', $lineno, $stream->getSourceContext()); + 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'))) { @@ -499,11 +498,7 @@ public function parseSubscriptExpression($node) $name = $arg->getAttribute('value'); - if ($this->parser->isReservedMacroName($name)) { - throw new SyntaxError(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()); - } - - $node = new MethodCallExpression($node, 'get'.$name, $arguments, $lineno); + $node = new MethodCallExpression($node, 'macro_'.$name, $arguments, $lineno); $node->setAttribute('safe', true); return $node; @@ -513,19 +508,19 @@ public function parseSubscriptExpression($node) // slice? $slice = false; - if ($stream->test(Token::PUNCTUATION_TYPE, ':')) { + 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, ':')) { + if ($stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) { $slice = true; } if ($slice) { - if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { $length = new ConstantExpression(null, $token->getLine()); } else { $length = $this->parseExpression(); @@ -535,12 +530,12 @@ public function parseSubscriptExpression($node) $arguments = new Node([$arg, $length]); $filter = new $class($node, new ConstantExpression('slice', $token->getLine()), $arguments, $token->getLine()); - $stream->expect(Token::PUNCTUATION_TYPE, ']'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']'); return $filter; } - $stream->expect(Token::PUNCTUATION_TYPE, ']'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']'); } return new GetAttrExpression($node, $arg, $arguments, $type, $lineno); @@ -556,10 +551,10 @@ public function parseFilterExpression($node) public function parseFilterExpressionRaw($node, $tag = null) { while (true) { - $token = $this->parser->getStream()->expect(Token::NAME_TYPE); + $token = $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5); $name = new ConstantExpression($token->getValue(), $token->getLine()); - if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '(')) { + if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $arguments = new Node(); } else { $arguments = $this->parseArguments(true, false, true); @@ -569,7 +564,7 @@ public function parseFilterExpressionRaw($node, $tag = null) $node = new $class($node, $name, $arguments, $token->getLine(), $tag); - if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '|')) { + if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '|')) { break; } @@ -594,21 +589,26 @@ public function parseArguments($namedArguments = false, $definition = false, $al $args = []; $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); - while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) { + $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, ',', 'Arguments must be separated by a comma'); + $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, null, 'An argument must be a name'); + $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, '=')) { + 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()); } @@ -618,7 +618,7 @@ public function parseArguments($namedArguments = false, $definition = false, $al $value = $this->parsePrimaryExpression(); if (!$this->checkConstantExpression($value)) { - throw new SyntaxError(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $stream->getSourceContext()); + 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); @@ -639,7 +639,7 @@ public function parseArguments($namedArguments = false, $definition = false, $al } } } - $stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'A list of arguments must be closed by a parenthesis'); return new Node($args); } @@ -650,19 +650,19 @@ public function parseAssignmentExpression() $targets = []; while (true) { $token = $this->parser->getCurrentToken(); - if ($stream->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue())) { + 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, null, 'Only variables can be assigned to'); + $stream->expect(/* Token::NAME_TYPE */ 5, null, 'Only variables can be assigned to'); } $value = $token->getValue(); - if (\in_array(strtolower($value), ['true', 'false', 'none', 'null'])) { + 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, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } @@ -675,7 +675,7 @@ public function parseMultitargetExpression() $targets = []; while (true) { $targets[] = $this->parseExpression(); - if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } @@ -683,35 +683,42 @@ public function parseMultitargetExpression() return new Node($targets); } - private function parseNotTestExpression(\Twig_NodeInterface $node) + private function parseNotTestExpression(Node $node): NotUnary { return new NotUnary($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine()); } - private function parseTestExpression(\Twig_NodeInterface $node) + 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, '(')) { + 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($line) + private function getTest(int $line): array { $stream = $this->parser->getStream(); - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); if ($test = $this->env->getTest($name)) { return [$name, $test]; } - if ($stream->test(Token::NAME_TYPE)) { + if ($stream->test(/* Token::NAME_TYPE */ 5)) { // try 2-words tests $name = $name.' '.$this->parser->getCurrentToken()->getValue(); @@ -728,11 +735,12 @@ private function getTest($line) throw $e; } - private function getTestNodeClass($test) + private function getTestNodeClass(TwigTest $test): string { - if ($test instanceof TwigTest && $test->isDeprecated()) { + if ($test->isDeprecated()) { $stream = $this->parser->getStream(); $message = sprintf('Twig Test "%s" is deprecated', $test->getName()); + if (!\is_bool($test->getDeprecatedVersion())) { $message .= sprintf(' since version %s', $test->getDeprecatedVersion()); } @@ -740,19 +748,15 @@ private function getTestNodeClass($test) $message .= sprintf('. Use "%s" instead', $test->getAlternative()); } $src = $stream->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine()); + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine()); - @trigger_error($message, E_USER_DEPRECATED); + @trigger_error($message, \E_USER_DEPRECATED); } - if ($test instanceof TwigTest) { - return $test->getNodeClass(); - } - - return $test instanceof \Twig_Test_Node ? $test->getClass() : 'Twig\Node\Expression\TestExpression'; + return $test->getNodeClass(); } - protected function getFunctionNodeClass($name, $line) + private function getFunctionNodeClass(string $name, int $line): string { if (false === $function = $this->env->getFunction($name)) { $e = new SyntaxError(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext()); @@ -761,7 +765,7 @@ protected function getFunctionNodeClass($name, $line) throw $e; } - if ($function instanceof TwigFunction && $function->isDeprecated()) { + if ($function->isDeprecated()) { $message = sprintf('Twig Function "%s" is deprecated', $function->getName()); if (!\is_bool($function->getDeprecatedVersion())) { $message .= sprintf(' since version %s', $function->getDeprecatedVersion()); @@ -770,19 +774,15 @@ protected function getFunctionNodeClass($name, $line) $message .= sprintf('. Use "%s" instead', $function->getAlternative()); } $src = $this->parser->getStream()->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line); - - @trigger_error($message, E_USER_DEPRECATED); - } + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line); - if ($function instanceof TwigFunction) { - return $function->getNodeClass(); + @trigger_error($message, \E_USER_DEPRECATED); } - return $function instanceof \Twig_Function_Node ? $function->getClass() : 'Twig\Node\Expression\FunctionExpression'; + return $function->getNodeClass(); } - protected function getFilterNodeClass($name, $line) + private function getFilterNodeClass(string $name, int $line): string { if (false === $filter = $this->env->getFilter($name)) { $e = new SyntaxError(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext()); @@ -791,7 +791,7 @@ protected function getFilterNodeClass($name, $line) throw $e; } - if ($filter instanceof TwigFilter && $filter->isDeprecated()) { + if ($filter->isDeprecated()) { $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName()); if (!\is_bool($filter->getDeprecatedVersion())) { $message .= sprintf(' since version %s', $filter->getDeprecatedVersion()); @@ -800,20 +800,16 @@ protected function getFilterNodeClass($name, $line) $message .= sprintf('. Use "%s" instead', $filter->getAlternative()); } $src = $this->parser->getStream()->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line); - - @trigger_error($message, E_USER_DEPRECATED); - } + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line); - if ($filter instanceof TwigFilter) { - return $filter->getNodeClass(); + @trigger_error($message, \E_USER_DEPRECATED); } - return $filter instanceof \Twig_Filter_Node ? $filter->getClass() : 'Twig\Node\Expression\FilterExpression'; + return $filter->getNodeClass(); } // checks that the node only contains "constant" elements - protected function checkConstantExpression(\Twig_NodeInterface $node) + private function checkConstantExpression(Node $node): bool { if (!($node instanceof ConstantExpression || $node instanceof ArrayExpression || $node instanceof NegUnary || $node instanceof PosUnary diff --git a/system/libs/Twig/Extension/AbstractExtension.php b/system/libs/Twig/Extension/AbstractExtension.php index fa3245b298..0c012b3e96 100644 --- a/system/libs/Twig/Extension/AbstractExtension.php +++ b/system/libs/Twig/Extension/AbstractExtension.php @@ -11,17 +11,8 @@ namespace Twig\Extension; -use Twig\Environment; - abstract class AbstractExtension implements ExtensionInterface { - /** - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_InitRuntimeInterface instead - */ - public function initRuntime(Environment $environment) - { - } - public function getTokenParsers() { return []; @@ -51,22 +42,6 @@ public function getOperators() { return []; } - - /** - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_GlobalsInterface instead - */ - public function getGlobals() - { - return []; - } - - /** - * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally - */ - public function getName() - { - return \get_class($this); - } } class_alias('Twig\Extension\AbstractExtension', 'Twig_Extension'); diff --git a/system/libs/Twig/Extension/CoreExtension.php b/system/libs/Twig/Extension/CoreExtension.php index 5f3cc24a19..5c4087ec21 100644 --- a/system/libs/Twig/Extension/CoreExtension.php +++ b/system/libs/Twig/Extension/CoreExtension.php @@ -11,6 +11,45 @@ namespace Twig\Extension { use Twig\ExpressionParser; +use Twig\Node\Expression\Binary\AddBinary; +use Twig\Node\Expression\Binary\AndBinary; +use Twig\Node\Expression\Binary\BitwiseAndBinary; +use Twig\Node\Expression\Binary\BitwiseOrBinary; +use Twig\Node\Expression\Binary\BitwiseXorBinary; +use Twig\Node\Expression\Binary\ConcatBinary; +use Twig\Node\Expression\Binary\DivBinary; +use Twig\Node\Expression\Binary\EndsWithBinary; +use Twig\Node\Expression\Binary\EqualBinary; +use Twig\Node\Expression\Binary\FloorDivBinary; +use Twig\Node\Expression\Binary\GreaterBinary; +use Twig\Node\Expression\Binary\GreaterEqualBinary; +use Twig\Node\Expression\Binary\InBinary; +use Twig\Node\Expression\Binary\LessBinary; +use Twig\Node\Expression\Binary\LessEqualBinary; +use Twig\Node\Expression\Binary\MatchesBinary; +use Twig\Node\Expression\Binary\ModBinary; +use Twig\Node\Expression\Binary\MulBinary; +use Twig\Node\Expression\Binary\NotEqualBinary; +use Twig\Node\Expression\Binary\NotInBinary; +use Twig\Node\Expression\Binary\OrBinary; +use Twig\Node\Expression\Binary\PowerBinary; +use Twig\Node\Expression\Binary\RangeBinary; +use Twig\Node\Expression\Binary\SpaceshipBinary; +use Twig\Node\Expression\Binary\StartsWithBinary; +use Twig\Node\Expression\Binary\SubBinary; +use Twig\Node\Expression\Filter\DefaultFilter; +use Twig\Node\Expression\NullCoalesceExpression; +use Twig\Node\Expression\Test\ConstantTest; +use Twig\Node\Expression\Test\DefinedTest; +use Twig\Node\Expression\Test\DivisiblebyTest; +use Twig\Node\Expression\Test\EvenTest; +use Twig\Node\Expression\Test\NullTest; +use Twig\Node\Expression\Test\OddTest; +use Twig\Node\Expression\Test\SameasTest; +use Twig\Node\Expression\Unary\NegUnary; +use Twig\Node\Expression\Unary\NotUnary; +use Twig\Node\Expression\Unary\PosUnary; +use Twig\NodeVisitor\MacroAutoImportNodeVisitor; use Twig\TokenParser\ApplyTokenParser; use Twig\TokenParser\BlockTokenParser; use Twig\TokenParser\DeprecatedTokenParser; @@ -33,34 +72,41 @@ use Twig\TwigFunction; use Twig\TwigTest; -/** - * @final - */ -class CoreExtension extends AbstractExtension +final class CoreExtension extends AbstractExtension { - protected $dateFormats = ['F j, Y H:i', '%d days']; - protected $numberFormat = [0, '.', ',']; - protected $timezone = null; - protected $escapers = []; + private $dateFormats = ['F j, Y H:i', '%d days']; + private $numberFormat = [0, '.', ',']; + private $timezone = null; + private $escapers = []; /** * 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 + * + * @deprecated since Twig 2.11, to be removed in 3.0; use the same method on EscaperExtension instead */ - public function setEscaper($strategy, $callable) + public function setEscaper($strategy, callable $callable) { + @trigger_error(sprintf('The "%s" method is deprecated since Twig 2.11; use "%s::setEscaper" instead.', __METHOD__, EscaperExtension::class), \E_USER_DEPRECATED); + $this->escapers[$strategy] = $callable; } /** * Gets all defined escapers. * - * @return array An array of escapers + * @return callable[] An array of escapers + * + * @deprecated since Twig 2.11, to be removed in 3.0; use the same method on EscaperExtension instead */ - public function getEscapers() + public function getEscapers(/* $triggerDeprecation = true */) { + if (0 === \func_num_args() || \func_get_arg(0)) { + @trigger_error(sprintf('The "%s" method is deprecated since Twig 2.11; use "%s::getEscapers" instead.', __METHOD__, EscaperExtension::class), \E_USER_DEPRECATED); + } + return $this->escapers; } @@ -163,11 +209,11 @@ public function getTokenParsers() public function getFilters() { - $filters = [ + return [ // formatting filters new TwigFilter('date', 'twig_date_format_filter', ['needs_environment' => true]), new TwigFilter('date_modify', 'twig_date_modify_filter', ['needs_environment' => true]), - new TwigFilter('format', 'sprintf'), + new TwigFilter('format', 'twig_sprintf'), new TwigFilter('replace', 'twig_replace_filter'), new TwigFilter('number_format', 'twig_number_format_filter', ['needs_environment' => true]), new TwigFilter('abs', 'abs'), @@ -175,28 +221,29 @@ public function getFilters() // encoding new TwigFilter('url_encode', 'twig_urlencode_filter'), - new TwigFilter('json_encode', 'twig_jsonencode_filter'), + new TwigFilter('json_encode', 'json_encode'), new TwigFilter('convert_encoding', 'twig_convert_encoding'), // string filters new TwigFilter('title', 'twig_title_string_filter', ['needs_environment' => true]), new TwigFilter('capitalize', 'twig_capitalize_string_filter', ['needs_environment' => true]), - new TwigFilter('upper', 'strtoupper'), - new TwigFilter('lower', 'strtolower'), - new TwigFilter('striptags', 'strip_tags'), + new TwigFilter('upper', 'twig_upper_filter', ['needs_environment' => true]), + new TwigFilter('lower', 'twig_lower_filter', ['needs_environment' => true]), + new TwigFilter('striptags', 'twig_striptags'), new TwigFilter('trim', 'twig_trim_filter'), - new TwigFilter('nl2br', 'nl2br', ['pre_escape' => 'html', 'is_safe' => ['html']]), + new TwigFilter('nl2br', 'twig_nl2br', ['pre_escape' => 'html', 'is_safe' => ['html']]), new TwigFilter('spaceless', 'twig_spaceless', ['is_safe' => ['html']]), // array helpers new TwigFilter('join', 'twig_join_filter'), new TwigFilter('split', 'twig_split_filter', ['needs_environment' => true]), - new TwigFilter('sort', 'twig_sort_filter'), + new TwigFilter('sort', 'twig_sort_filter', ['needs_environment' => true]), new TwigFilter('merge', 'twig_array_merge'), new TwigFilter('batch', 'twig_array_batch'), - new TwigFilter('filter', 'twig_array_filter'), - new TwigFilter('map', 'twig_array_map'), - new TwigFilter('reduce', 'twig_array_reduce'), + new TwigFilter('column', 'twig_array_column'), + new TwigFilter('filter', 'twig_array_filter', ['needs_environment' => true]), + new TwigFilter('map', 'twig_array_map', ['needs_environment' => true]), + new TwigFilter('reduce', 'twig_array_reduce', ['needs_environment' => true]), // string/array filters new TwigFilter('reverse', 'twig_reverse_filter', ['needs_environment' => true]), @@ -206,20 +253,9 @@ public function getFilters() new TwigFilter('last', 'twig_last', ['needs_environment' => true]), // iteration and runtime - new TwigFilter('default', '_twig_default_filter', ['node_class' => '\Twig\Node\Expression\Filter\DefaultFilter']), + new TwigFilter('default', '_twig_default_filter', ['node_class' => DefaultFilter::class]), new TwigFilter('keys', 'twig_get_array_keys_filter'), - - // escaping - 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']), ]; - - if (\function_exists('mb_get_info')) { - $filters[] = new TwigFilter('upper', 'twig_upper_filter', ['needs_environment' => true]); - $filters[] = new TwigFilter('lower', 'twig_lower_filter', ['needs_environment' => true]); - } - - return $filters; } public function getFunctions() @@ -240,79 +276,80 @@ public function getFunctions() public function getTests() { return [ - new TwigTest('even', null, ['node_class' => '\Twig\Node\Expression\Test\EvenTest']), - new TwigTest('odd', null, ['node_class' => '\Twig\Node\Expression\Test\OddTest']), - new TwigTest('defined', null, ['node_class' => '\Twig\Node\Expression\Test\DefinedTest']), - new TwigTest('sameas', null, ['node_class' => '\Twig\Node\Expression\Test\SameasTest', 'deprecated' => '1.21', 'alternative' => 'same as']), - new TwigTest('same as', null, ['node_class' => '\Twig\Node\Expression\Test\SameasTest']), - new TwigTest('none', null, ['node_class' => '\Twig\Node\Expression\Test\NullTest']), - new TwigTest('null', null, ['node_class' => '\Twig\Node\Expression\Test\NullTest']), - new TwigTest('divisibleby', null, ['node_class' => '\Twig\Node\Expression\Test\DivisiblebyTest', 'deprecated' => '1.21', 'alternative' => 'divisible by']), - new TwigTest('divisible by', null, ['node_class' => '\Twig\Node\Expression\Test\DivisiblebyTest']), - new TwigTest('constant', null, ['node_class' => '\Twig\Node\Expression\Test\ConstantTest']), + new TwigTest('even', null, ['node_class' => EvenTest::class]), + new TwigTest('odd', null, ['node_class' => OddTest::class]), + new TwigTest('defined', null, ['node_class' => DefinedTest::class]), + new TwigTest('same as', null, ['node_class' => SameasTest::class, 'one_mandatory_argument' => true]), + new TwigTest('none', null, ['node_class' => NullTest::class]), + new TwigTest('null', null, ['node_class' => NullTest::class]), + new TwigTest('divisible by', null, ['node_class' => DivisiblebyTest::class, 'one_mandatory_argument' => true]), + new TwigTest('constant', null, ['node_class' => ConstantTest::class]), new TwigTest('empty', 'twig_test_empty'), new TwigTest('iterable', 'twig_test_iterable'), ]; } + public function getNodeVisitors() + { + return [new MacroAutoImportNodeVisitor()]; + } + public function getOperators() { return [ [ - 'not' => ['precedence' => 50, 'class' => '\Twig\Node\Expression\Unary\NotUnary'], - '-' => ['precedence' => 500, 'class' => '\Twig\Node\Expression\Unary\NegUnary'], - '+' => ['precedence' => 500, 'class' => '\Twig\Node\Expression\Unary\PosUnary'], + 'not' => ['precedence' => 50, 'class' => NotUnary::class], + '-' => ['precedence' => 500, 'class' => NegUnary::class], + '+' => ['precedence' => 500, 'class' => PosUnary::class], ], [ - 'or' => ['precedence' => 10, 'class' => '\Twig\Node\Expression\Binary\OrBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'and' => ['precedence' => 15, 'class' => '\Twig\Node\Expression\Binary\AndBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-or' => ['precedence' => 16, 'class' => '\Twig\Node\Expression\Binary\BitwiseOrBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-xor' => ['precedence' => 17, 'class' => '\Twig\Node\Expression\Binary\BitwiseXorBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-and' => ['precedence' => 18, 'class' => '\Twig\Node\Expression\Binary\BitwiseAndBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '==' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\EqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '!=' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\NotEqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '<' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\LessBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '>' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\GreaterBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '>=' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\GreaterEqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '<=' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\LessEqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'not in' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\NotInBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'in' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\InBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'matches' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\MatchesBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'starts with' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\StartsWithBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'ends with' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\EndsWithBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '..' => ['precedence' => 25, 'class' => '\Twig\Node\Expression\Binary\RangeBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '+' => ['precedence' => 30, 'class' => '\Twig\Node\Expression\Binary\AddBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '-' => ['precedence' => 30, 'class' => '\Twig\Node\Expression\Binary\SubBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '~' => ['precedence' => 40, 'class' => '\Twig\Node\Expression\Binary\ConcatBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '*' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\MulBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '/' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\DivBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '//' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\FloorDivBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '%' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\ModBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'or' => ['precedence' => 10, 'class' => OrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'and' => ['precedence' => 15, 'class' => AndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'b-or' => ['precedence' => 16, 'class' => BitwiseOrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'b-xor' => ['precedence' => 17, 'class' => BitwiseXorBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'b-and' => ['precedence' => 18, 'class' => BitwiseAndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '==' => ['precedence' => 20, 'class' => EqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '!=' => ['precedence' => 20, 'class' => NotEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '<=>' => ['precedence' => 20, 'class' => SpaceshipBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '<' => ['precedence' => 20, 'class' => LessBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '>' => ['precedence' => 20, 'class' => GreaterBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '>=' => ['precedence' => 20, 'class' => GreaterEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '<=' => ['precedence' => 20, 'class' => LessEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'not in' => ['precedence' => 20, 'class' => NotInBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'in' => ['precedence' => 20, 'class' => InBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'matches' => ['precedence' => 20, 'class' => MatchesBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'starts with' => ['precedence' => 20, 'class' => StartsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'ends with' => ['precedence' => 20, 'class' => EndsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '..' => ['precedence' => 25, 'class' => RangeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '+' => ['precedence' => 30, 'class' => AddBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '-' => ['precedence' => 30, 'class' => SubBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '~' => ['precedence' => 40, 'class' => ConcatBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '*' => ['precedence' => 60, 'class' => MulBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '/' => ['precedence' => 60, 'class' => DivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '//' => ['precedence' => 60, 'class' => FloorDivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '%' => ['precedence' => 60, 'class' => ModBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], 'is' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT], 'is not' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '**' => ['precedence' => 200, 'class' => '\Twig\Node\Expression\Binary\PowerBinary', 'associativity' => ExpressionParser::OPERATOR_RIGHT], - '??' => ['precedence' => 300, 'class' => '\Twig\Node\Expression\NullCoalesceExpression', 'associativity' => ExpressionParser::OPERATOR_RIGHT], + '**' => ['precedence' => 200, 'class' => PowerBinary::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], + '??' => ['precedence' => 300, 'class' => NullCoalesceExpression::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], ], ]; } - - public function getName() - { - return 'core'; - } } class_alias('Twig\Extension\CoreExtension', 'Twig_Extension_Core'); } namespace { -use Twig\Environment; -use Twig\Error\LoaderError; -use Twig\Error\RuntimeError; -use Twig\Loader\SourceContextLoaderInterface; -use Twig\Markup; -use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Node; + use Twig\Environment; + use Twig\Error\LoaderError; + use Twig\Error\RuntimeError; + use Twig\Extension\CoreExtension; + use Twig\Extension\SandboxExtension; + use Twig\Markup; + use Twig\Source; + use Twig\Template; + use Twig\TemplateWrapper; /** * Cycles over a value. @@ -347,7 +384,7 @@ function twig_cycle($values, $position) function twig_random(Environment $env, $values = null, $max = null) { if (null === $values) { - return null === $max ? mt_rand() : mt_rand(0, $max); + return null === $max ? mt_rand() : mt_rand(0, (int) $max); } if (\is_int($values) || \is_float($values)) { @@ -364,29 +401,28 @@ function twig_random(Environment $env, $values = null, $max = null) $max = $max; } - return mt_rand($min, $max); + return mt_rand((int) $min, (int) $max); } if (\is_string($values)) { if ('' === $values) { return ''; } - if (null !== $charset = $env->getCharset()) { - if ('UTF-8' !== $charset) { - $values = twig_convert_encoding($values, 'UTF-8', $charset); - } - // unicode version of str_split() - // split at all positions, but not after the start and not before the end - $values = preg_split('/(?getCharset(); - if ('UTF-8' !== $charset) { - foreach ($values as $i => $value) { - $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); - } + if ('UTF-8' !== $charset) { + $values = twig_convert_encoding($values, 'UTF-8', $charset); + } + + // unicode version of str_split() + // split at all positions, but not after the start and not before the end + $values = preg_split('/(? $value) { + $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); } - } else { - return $values[mt_rand(0, \strlen($values) - 1)]; } } @@ -408,16 +444,16 @@ function twig_random(Environment $env, $values = null, $max = null) * * {{ post.published_at|date("m/d/Y") }} * - * @param \DateTime|\DateTimeInterface|\DateInterval|string $date A date - * @param string|null $format The target format, null to use the default - * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged + * @param \DateTimeInterface|\DateInterval|string $date A date + * @param string|null $format The target format, null to use the default + * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged * * @return string The formatted date */ function twig_date_format_filter(Environment $env, $date, $format = null, $timezone = null) { if (null === $format) { - $formats = $env->getExtension('\Twig\Extension\CoreExtension')->getDateFormat(); + $formats = $env->getExtension(CoreExtension::class)->getDateFormat(); $format = $date instanceof \DateInterval ? $formats[1] : $formats[0]; } @@ -433,20 +469,29 @@ function twig_date_format_filter(Environment $env, $date, $format = null, $timez * * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }} * - * @param \DateTime|string $date A date - * @param string $modifier A modifier string + * @param \DateTimeInterface|string $date A date + * @param string $modifier A modifier string * - * @return \DateTime + * @return \DateTimeInterface */ function twig_date_modify_filter(Environment $env, $date, $modifier) { $date = twig_date_converter($env, $date, false); - $resultDate = $date->modify($modifier); - // This is a hack to ensure PHP 5.2 support and support for \DateTimeImmutable - // \DateTime::modify does not return the modified \DateTime object < 5.3.0 - // and \DateTimeImmutable does not modify $date. - return null === $resultDate ? $date : $resultDate; + return $date->modify($modifier); +} + +/** + * Returns a formatted string. + * + * @param string|null $format + * @param ...$values + * + * @return string + */ +function twig_sprintf($format, ...$values) +{ + return sprintf($format ?? '', ...$values); } /** @@ -456,17 +501,17 @@ function twig_date_modify_filter(Environment $env, $date, $modifier) * {# do something #} * {% endif %} * - * @param \DateTime|\DateTimeInterface|string|null $date A date - * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged + * @param \DateTimeInterface|string|null $date A date or null to use the current time + * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged * - * @return \DateTime + * @return \DateTimeInterface */ function twig_date_converter(Environment $env, $date = null, $timezone = null) { // determine the timezone if (false !== $timezone) { if (null === $timezone) { - $timezone = $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone(); + $timezone = $env->getExtension(CoreExtension::class)->getTimezone(); } elseif (!$timezone instanceof \DateTimeZone) { $timezone = new \DateTimeZone($timezone); } @@ -477,7 +522,7 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null) return false !== $timezone ? $date->setTimezone($timezone) : $date; } - if ($date instanceof \DateTime || $date instanceof \DateTimeInterface) { + if ($date instanceof \DateTimeInterface) { $date = clone $date; if (false !== $timezone) { $date->setTimezone($timezone); @@ -487,14 +532,18 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null) } if (null === $date || 'now' === $date) { - return new \DateTime($date, false !== $timezone ? $timezone : $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone()); + if (null === $date) { + $date = 'now'; + } + + return new \DateTime($date, false !== $timezone ? $timezone : $env->getExtension(CoreExtension::class)->getTimezone()); } $asString = (string) $date; if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { $date = new \DateTime('@'.$date); } else { - $date = new \DateTime($date, $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone()); + $date = new \DateTime($date, $env->getExtension(CoreExtension::class)->getTimezone()); } if (false !== $timezone) { @@ -507,54 +556,49 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null) /** * Replaces strings within a string. * - * @param string $str String to replace in + * @param string|null $str String to replace in * @param array|\Traversable $from Replace values - * @param string|null $to Replace to, deprecated (@see https://secure.php.net/manual/en/function.strtr.php) * * @return string */ -function twig_replace_filter($str, $from, $to = null) +function twig_replace_filter($str, $from) { - if (\is_string($from) && \is_string($to)) { - @trigger_error('Using "replace" with character by character replacement is deprecated since version 1.22 and will be removed in Twig 2.0', E_USER_DEPRECATED); - - return strtr($str, $from, $to); - } - if (!twig_test_iterable($from)) { throw new RuntimeError(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from))); } - return strtr($str, twig_to_array($from)); + return strtr($str ?? '', twig_to_array($from)); } /** * Rounds a number. * - * @param int|float $value The value to round - * @param int|float $precision The rounding precision - * @param string $method The method to use for rounding + * @param int|float|string|null $value The value to round + * @param int|float $precision The rounding precision + * @param string $method The method to use for rounding * * @return int|float The rounded number */ function twig_round($value, $precision = 0, $method = 'common') { - if ('common' == $method) { + $value = (float) $value; + + if ('common' === $method) { return round($value, $precision); } - if ('ceil' != $method && 'floor' != $method) { + if ('ceil' !== $method && 'floor' !== $method) { throw new RuntimeError('The round filter only supports the "common", "ceil", and "floor" methods.'); } - return $method($value * pow(10, $precision)) / pow(10, $precision); + return $method($value * 10 ** $precision) / 10 ** $precision; } /** * Number format filter. * * All of the formatting options can be left null, in that case the defaults will - * be used. Supplying any of the parameters will override the defaults set in the + * be used. Supplying any of the parameters will override the defaults set in the * environment object. * * @param mixed $number A float/int/string of the number to format @@ -566,7 +610,7 @@ function twig_round($value, $precision = 0, $method = 'common') */ function twig_number_format_filter(Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null) { - $defaults = $env->getExtension('\Twig\Extension\CoreExtension')->getNumberFormat(); + $defaults = $env->getExtension(CoreExtension::class)->getNumberFormat(); if (null === $decimal) { $decimal = $defaults[0]; } @@ -585,47 +629,17 @@ function twig_number_format_filter(Environment $env, $number, $decimal = null, $ /** * URL encodes (RFC 3986) a string as a path segment or an array as a query string. * - * @param string|array $url A URL or an array of query parameters + * @param string|array|null $url A URL or an array of query parameters * * @return string The URL encoded value */ function twig_urlencode_filter($url) { if (\is_array($url)) { - if (\defined('PHP_QUERY_RFC3986')) { - return http_build_query($url, '', '&', PHP_QUERY_RFC3986); - } - - return http_build_query($url, '', '&'); + return http_build_query($url, '', '&', \PHP_QUERY_RFC3986); } - return rawurlencode($url); -} - -/** - * JSON encodes a variable. - * - * @param mixed $value the value to encode - * @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT - * - * @return mixed The JSON encoded value - */ -function twig_jsonencode_filter($value, $options = 0) -{ - if ($value instanceof Markup) { - $value = (string) $value; - } elseif (\is_array($value)) { - array_walk_recursive($value, '_twig_markup2string'); - } - - return json_encode($value, $options); -} - -function _twig_markup2string(&$value) -{ - if ($value instanceof Markup) { - $value = (string) $value; - } + return rawurlencode($url ?? ''); } /** @@ -687,13 +701,7 @@ function twig_slice(Environment $env, $item, $start, $length = null, $preserveKe return \array_slice($item, $start, $length, $preserveKeys); } - $item = (string) $item; - - if (\function_exists('mb_get_info') && null !== $charset = $env->getCharset()) { - return (string) mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset); - } - - return (string) (null === $length ? substr($item, $start) : substr($item, $start, $length)); + return (string) mb_substr((string) $item, $start, $length, $env->getCharset()); } /** @@ -782,34 +790,32 @@ function twig_join_filter($value, $glue = '', $and = null) * {{ "aabbcc"|split('', 2) }} * {# returns [aa, bb, cc] #} * - * @param string $value A string - * @param string $delimiter The delimiter - * @param int $limit The limit + * @param string|null $value A string + * @param string $delimiter The delimiter + * @param int $limit The limit * * @return array The split string as an array */ function twig_split_filter(Environment $env, $value, $delimiter, $limit = null) { + $value = $value ?? ''; + if (\strlen($delimiter) > 0) { return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit); } - if (!\function_exists('mb_get_info') || null === $charset = $env->getCharset()) { - return str_split($value, null === $limit ? 1 : $limit); - } - if ($limit <= 1) { return preg_split('/(?getCharset()); if ($length < $limit) { return [$value]; } $r = []; for ($i = 0; $i < $length; $i += $limit) { - $r[] = mb_substr($value, $i, $limit, $charset); + $r[] = mb_substr($value, $i, $limit, $env->getCharset()); } return $r; @@ -879,8 +885,8 @@ function twig_get_array_keys_filter($array) /** * Reverses a variable. * - * @param array|\Traversable|string $item An array, a \Traversable instance, or a string - * @param bool $preserveKeys Whether to preserve key or not + * @param array|\Traversable|string|null $item An array, a \Traversable instance, or a string + * @param bool $preserveKeys Whether to preserve key or not * * @return mixed The reversed input */ @@ -894,25 +900,23 @@ function twig_reverse_filter(Environment $env, $item, $preserveKeys = false) return array_reverse($item, $preserveKeys); } - if (null !== $charset = $env->getCharset()) { - $string = (string) $item; + $string = (string) $item; - if ('UTF-8' !== $charset) { - $item = twig_convert_encoding($string, 'UTF-8', $charset); - } + $charset = $env->getCharset(); - preg_match_all('/./us', $item, $matches); + if ('UTF-8' !== $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); + } - $string = implode('', array_reverse($matches[0])); + preg_match_all('/./us', $string, $matches); - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } + $string = implode('', array_reverse($matches[0])); - return $string; + if ('UTF-8' !== $charset) { + $string = twig_convert_encoding($string, $charset, 'UTF-8'); } - return strrev((string) $item); + return $string; } /** @@ -922,7 +926,7 @@ function twig_reverse_filter(Environment $env, $item, $preserveKeys = false) * * @return array */ -function twig_sort_filter($array) +function twig_sort_filter(Environment $env, $array, $arrow = null) { if ($array instanceof \Traversable) { $array = iterator_to_array($array); @@ -930,7 +934,13 @@ function twig_sort_filter($array) throw new RuntimeError(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array))); } - asort($array); + if (null !== $arrow) { + twig_check_arrow_in_sandbox($env, $arrow, 'sort', 'filter'); + + uasort($array, $arrow); + } else { + asort($array); + } return $array; } @@ -975,6 +985,10 @@ function twig_in_filter($value, $compare) /** * Returns a trimmed string. * + * @param string|null $string + * @param string|null $characterMask + * @param string $side + * * @return string * * @throws RuntimeError When an invalid trimming side is used (not a string or not 'left', 'right', or 'both') @@ -987,478 +1001,172 @@ function twig_trim_filter($string, $characterMask = null, $side = 'both') switch ($side) { case 'both': - return trim($string, $characterMask); + return trim($string ?? '', $characterMask); case 'left': - return ltrim($string, $characterMask); + return ltrim($string ?? '', $characterMask); case 'right': - return rtrim($string, $characterMask); + return rtrim($string ?? '', $characterMask); default: throw new RuntimeError('Trimming side must be "left", "right" or "both".'); } } /** - * Removes whitespaces between HTML tags. + * Inserts HTML line breaks before all newlines in a string. + * + * @param string|null $string * * @return string */ -function twig_spaceless($content) +function twig_nl2br($string) { - return trim(preg_replace('/>\s+<', $content)); + return nl2br($string ?? ''); } /** - * Escapes a string. + * Removes whitespaces between HTML tags. * - * @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) + * @param string|null $string * * @return string */ -function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) +function twig_spaceless($content) { - if ($autoescape && $string instanceof Markup) { - return $string; - } - - if (!\is_string($string)) { - if (\is_object($string) && method_exists($string, '__toString')) { - $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://secure.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 twig_convert_encoding($string, $charset, 'UTF-8'); - - 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', '_twig_escape_js_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - 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', '_twig_escape_css_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - 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', '_twig_escape_html_attr_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - - case 'url': - return rawurlencode($string); - - default: - static $escapers; - - if (null === $escapers) { - $escapers = $env->getExtension('\Twig\Extension\CoreExtension')->getEscapers(); - } - - if (isset($escapers[$strategy])) { - return \call_user_func($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)); - } + return trim(preg_replace('/>\s+<', $content ?? '')); } /** - * @internal + * @param string|null $string + * @param string $to + * @param string $from + * + * @return string */ -function twig_escape_filter_is_safe(Node $filterArgs) +function twig_convert_encoding($string, $to, $from) { - foreach ($filterArgs as $arg) { - if ($arg instanceof ConstantExpression) { - return [$arg->getAttribute('value')]; - } - - return []; + if (!\function_exists('iconv')) { + throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); } - return ['html']; + return iconv($from, $to, $string ?? ''); } -if (\function_exists('mb_convert_encoding')) { - function twig_convert_encoding($string, $to, $from) - { - return mb_convert_encoding($string, $to, $from); - } -} elseif (\function_exists('iconv')) { - function twig_convert_encoding($string, $to, $from) - { - return iconv($from, $to, $string); - } -} else { - function twig_convert_encoding($string, $to, $from) - { - throw new RuntimeError('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); +/** + * Returns the length of a variable. + * + * @param mixed $thing A variable + * + * @return int The length of the value + */ +function twig_length_filter(Environment $env, $thing) +{ + if (null === $thing) { + return 0; } -} -if (\function_exists('mb_ord')) { - function twig_ord($string) - { - return mb_ord($string, 'UTF-8'); + if (is_scalar($thing)) { + return mb_strlen($thing, $env->getCharset()); } -} else { - function twig_ord($string) - { - $code = ($string = unpack('C*', substr($string, 0, 4))) ? $string[1] : 0; - if (0xF0 <= $code) { - return (($code - 0xF0) << 18) + (($string[2] - 0x80) << 12) + (($string[3] - 0x80) << 6) + $string[4] - 0x80; - } - if (0xE0 <= $code) { - return (($code - 0xE0) << 12) + (($string[2] - 0x80) << 6) + $string[3] - 0x80; - } - if (0xC0 <= $code) { - return (($code - 0xC0) << 6) + $string[2] - 0x80; - } - return $code; + if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) { + return \count($thing); } -} -function _twig_escape_js_callback($matches) -{ - $char = $matches[0]; - - /* - * A few characters have short escape sequences in JSON and JavaScript. - * Escape sequences supported only by JavaScript, not JSON, are ommitted. - * \" 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]; + if ($thing instanceof \Traversable) { + return iterator_count($thing); } - // \uHHHH - $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); - $char = strtoupper(bin2hex($char)); - - if (4 >= \strlen($char)) { - return sprintf('\u%04s', $char); + if (method_exists($thing, '__toString') && !$thing instanceof \Countable) { + return mb_strlen((string) $thing, $env->getCharset()); } - return sprintf('\u%04s\u%04s', substr($char, 0, -4), substr($char, -4)); + return 1; } -function _twig_escape_css_callback($matches) +/** + * Converts a string to uppercase. + * + * @param string|null $string A string + * + * @return string The uppercased string + */ +function twig_upper_filter(Environment $env, $string) { - $char = $matches[0]; - - return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : twig_ord($char)); + return mb_strtoupper($string ?? '', $env->getCharset()); } /** - * This function is adapted from code coming from Zend Framework. + * Converts a string to lowercase. + * + * @param string|null $string A string * - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com) - * @license https://framework.zend.com/license/new-bsd New BSD License + * @return string The lowercased string */ -function _twig_escape_html_attr_callback($matches) +function twig_lower_filter(Environment $env, $string) { - $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 '�'; - } - - /* - * 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 => '"', /* quotation mark */ - 38 => '&', /* ampersand */ - 60 => '<', /* less-than sign */ - 62 => '>', /* 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;', twig_ord($chr)); + return mb_strtolower($string ?? '', $env->getCharset()); } -// add multibyte extensions if possible -if (\function_exists('mb_get_info')) { - /** - * Returns the length of a variable. - * - * @param mixed $thing A variable - * - * @return int The length of the value - */ - function twig_length_filter(Environment $env, $thing) - { - if (null === $thing) { - return 0; - } - - if (is_scalar($thing)) { - return mb_strlen($thing, $env->getCharset()); - } - - if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) { - return \count($thing); - } - - if ($thing instanceof \Traversable) { - return iterator_count($thing); - } - - if (\is_object($thing) && method_exists($thing, '__toString')) { - return mb_strlen((string) $thing, $env->getCharset()); - } - - return 1; - } - - /** - * Converts a string to uppercase. - * - * @param string $string A string - * - * @return string The uppercased string - */ - function twig_upper_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtoupper($string, $charset); - } - - return strtoupper($string); - } - - /** - * Converts a string to lowercase. - * - * @param string $string A string - * - * @return string The lowercased string - */ - function twig_lower_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtolower($string, $charset); - } - - return strtolower($string); - } - - /** - * Returns a titlecased string. - * - * @param string $string A string - * - * @return string The titlecased string - */ - function twig_title_string_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_convert_case($string, MB_CASE_TITLE, $charset); - } +/** + * Strips HTML and PHP tags from a string. + * + * @param string|null $string + * @param string[]|string|null $string + * + * @return string + */ +function twig_striptags($string, $allowable_tags = null) +{ + return strip_tags($string ?? '', $allowable_tags); +} - return ucwords(strtolower($string)); +/** + * Returns a titlecased string. + * + * @param string|null $string A string + * + * @return string The titlecased string + */ +function twig_title_string_filter(Environment $env, $string) +{ + if (null !== $charset = $env->getCharset()) { + return mb_convert_case($string ?? '', \MB_CASE_TITLE, $charset); } - /** - * Returns a capitalized string. - * - * @param string $string A string - * - * @return string The capitalized string - */ - function twig_capitalize_string_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset); - } - - return ucfirst(strtolower($string)); - } + return ucwords(strtolower($string ?? '')); } -// and byte fallback -else { - /** - * Returns the length of a variable. - * - * @param mixed $thing A variable - * - * @return int The length of the value - */ - function twig_length_filter(Environment $env, $thing) - { - if (null === $thing) { - return 0; - } - if (is_scalar($thing)) { - return \strlen($thing); - } - - if ($thing instanceof \SimpleXMLElement) { - return \count($thing); - } - - if (\is_object($thing) && method_exists($thing, '__toString') && !$thing instanceof \Countable) { - return \strlen((string) $thing); - } +/** + * Returns a capitalized string. + * + * @param string|null $string A string + * + * @return string The capitalized string + */ +function twig_capitalize_string_filter(Environment $env, $string) +{ + $charset = $env->getCharset(); - if ($thing instanceof \Countable || \is_array($thing)) { - return \count($thing); - } + return mb_strtoupper(mb_substr($string ?? '', 0, 1, $charset), $charset).mb_strtolower(mb_substr($string ?? '', 1, null, $charset), $charset); +} - if ($thing instanceof \IteratorAggregate) { - return iterator_count($thing); +/** + * @internal + */ +function twig_call_macro(Template $template, string $method, array $args, int $lineno, array $context, Source $source) +{ + if (!method_exists($template, $method)) { + $parent = $template; + while ($parent = $parent->getParent($context)) { + if (method_exists($parent, $method)) { + return $parent->$method(...$args); + } } - return 1; + throw new RuntimeError(sprintf('Macro "%s" is not defined in template "%s".', substr($method, \strlen('macro_')), $template->getTemplateName()), $lineno, $source); } - /** - * Returns a titlecased string. - * - * @param string $string A string - * - * @return string The titlecased string - */ - function twig_title_string_filter(Environment $env, $string) - { - return ucwords(strtolower($string)); - } - - /** - * Returns a capitalized string. - * - * @param string $string A string - * - * @return string The capitalized string - */ - function twig_capitalize_string_filter(Environment $env, $string) - { - return ucfirst(strtolower($string)); - } + return $template->$method(...$args); } /** @@ -1504,7 +1212,7 @@ function twig_to_array($seq, $preserveKeys = true) function twig_test_empty($value) { if ($value instanceof \Countable) { - return 0 == \count($value); + return 0 === \count($value); } if ($value instanceof \Traversable) { @@ -1555,53 +1263,36 @@ function twig_include(Environment $env, $context, $template, $variables = [], $w $variables = array_merge($context, $variables); } - if ($isSandboxed = $sandboxed && $env->hasExtension('\Twig\Extension\SandboxExtension')) { - $sandbox = $env->getExtension('\Twig\Extension\SandboxExtension'); + if ($isSandboxed = $sandboxed && $env->hasExtension(SandboxExtension::class)) { + $sandbox = $env->getExtension(SandboxExtension::class); if (!$alreadySandboxed = $sandbox->isSandboxed()) { $sandbox->enableSandbox(); } - } - $loaded = null; - try { - $loaded = $env->resolveTemplate($template); - } catch (LoaderError $e) { - if (!$ignoreMissing) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); + foreach ((\is_array($template) ? $template : [$template]) as $name) { + // if a Template instance is passed, it might have been instantiated outside of a sandbox, check security + if ($name instanceof TemplateWrapper || $name instanceof Template) { + $name->unwrap()->checkSecurity(); } - - throw $e; - } - } catch (\Throwable $e) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - throw $e; - } catch (\Exception $e) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); } - - throw $e; } try { - $ret = $loaded ? $loaded->render($variables) : ''; - } catch (\Exception $e) { + $loaded = null; + try { + $loaded = $env->resolveTemplate($template); + } catch (LoaderError $e) { + if (!$ignoreMissing) { + throw $e; + } + } + + return $loaded ? $loaded->render($variables) : ''; + } finally { if ($isSandboxed && !$alreadySandboxed) { $sandbox->disableSandbox(); } - - throw $e; - } - - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); } - - return $ret; } /** @@ -1616,11 +1307,7 @@ function twig_source(Environment $env, $name, $ignoreMissing = false) { $loader = $env->getLoader(); try { - if (!$loader instanceof SourceContextLoaderInterface) { - return $loader->getSource($name); - } else { - return $loader->getSourceContext($name)->getCode(); - } + return $loader->getSourceContext($name)->getCode(); } catch (LoaderError $e) { if (!$ignoreMissing) { throw $e; @@ -1642,6 +1329,10 @@ function twig_constant($constant, $object = null) $constant = \get_class($object).'::'.$constant; } + if (!\defined($constant)) { + throw new RuntimeError(sprintf('Constant "%s" is undefined.', $constant)); + } + return \constant($constant); } @@ -1693,22 +1384,248 @@ function twig_array_batch($items, $size, $fill = null, $preserveKeys = true) return $result; } -function twig_array_filter($array, $arrow) +/** + * Returns the attribute value for a given array/object. + * + * @param mixed $object The object or array from where to get the item + * @param mixed $item The item to get from the array or object + * @param array $arguments An array of arguments to pass if the item is an object method + * @param string $type The type of attribute (@see \Twig\Template constants) + * @param bool $isDefinedTest Whether this is only a defined check + * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not + * @param int $lineno The template line where the attribute was called + * + * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true + * + * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false + * + * @internal + */ +function twig_get_attribute(Environment $env, Source $source, $object, $item, array $arguments = [], $type = /* Template::ANY_CALL */ 'any', $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false, int $lineno = -1) { - if (\is_array($array)) { - if (\PHP_VERSION_ID >= 50600) { - return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); + // array + if (/* Template::METHOD_CALL */ 'method' !== $type) { + $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item; + + if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object))) + || ($object instanceof ArrayAccess && isset($object[$arrayItem])) + ) { + if ($isDefinedTest) { + return true; + } + + return $object[$arrayItem]; + } + + if (/* Template::ARRAY_CALL */ 'array' === $type || !\is_object($object)) { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$env->isStrictVariables()) { + return; + } + + if ($object instanceof ArrayAccess) { + $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object)); + } elseif (\is_object($object)) { + $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object)); + } elseif (\is_array($object)) { + if (empty($object)) { + $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem); + } else { + $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); + } + } elseif (/* Template::ARRAY_CALL */ 'array' === $type) { + if (null === $object) { + $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item); + } else { + $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); + } + } elseif (null === $object) { + $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item); + } else { + $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); + } + + throw new RuntimeError($message, $lineno, $source); + } + } + + if (!\is_object($object)) { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$env->isStrictVariables()) { + return; + } + + if (null === $object) { + $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); + } elseif (\is_array($object)) { + $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item); + } else { + $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); + } + + throw new RuntimeError($message, $lineno, $source); + } + + if ($object instanceof Template) { + throw new RuntimeError('Accessing \Twig\Template attributes is forbidden.', $lineno, $source); + } + + // object property + if (/* Template::METHOD_CALL */ 'method' !== $type) { + if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) { + if ($isDefinedTest) { + return true; + } + + if ($sandboxed) { + $env->getExtension(SandboxExtension::class)->checkPropertyAllowed($object, $item, $lineno, $source); + } + + return $object->$item; + } + } + + static $cache = []; + + $class = \get_class($object); + + // object method + // precedence: getXxx() > isXxx() > hasXxx() + if (!isset($cache[$class])) { + $methods = get_class_methods($object); + sort($methods); + $lcMethods = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, $methods); + $classCache = []; + foreach ($methods as $i => $method) { + $classCache[$method] = $method; + $classCache[$lcName = $lcMethods[$i]] = $method; + + if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) { + $name = substr($method, 3); + $lcName = substr($lcName, 3); + } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) { + $name = substr($method, 2); + $lcName = substr($lcName, 2); + } elseif ('h' === $lcName[0] && 0 === strpos($lcName, 'has')) { + $name = substr($method, 3); + $lcName = substr($lcName, 3); + if (\in_array('is'.$lcName, $lcMethods)) { + continue; + } + } else { + continue; + } + + // skip get() and is() methods (in which case, $name is empty) + if ($name) { + if (!isset($classCache[$name])) { + $classCache[$name] = $method; + } + + if (!isset($classCache[$lcName])) { + $classCache[$lcName] = $method; + } + } + } + $cache[$class] = $classCache; + } + + $call = false; + if (isset($cache[$class][$item])) { + $method = $cache[$class][$item]; + } elseif (isset($cache[$class][$lcItem = strtr($item, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')])) { + $method = $cache[$class][$lcItem]; + } elseif (isset($cache[$class]['__call'])) { + $method = $item; + $call = true; + } else { + if ($isDefinedTest) { + return false; } - return array_filter($array, $arrow); + if ($ignoreStrictCheck || !$env->isStrictVariables()) { + return; + } + + throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source); + } + + if ($isDefinedTest) { + return true; + } + + if ($sandboxed) { + $env->getExtension(SandboxExtension::class)->checkMethodAllowed($object, $method, $lineno, $source); + } + + // Some objects throw exceptions when they have __call, and the method we try + // to call is not supported. If ignoreStrictCheck is true, we should return null. + try { + $ret = $object->$method(...$arguments); + } catch (\BadMethodCallException $e) { + if ($call && ($ignoreStrictCheck || !$env->isStrictVariables())) { + return; + } + throw $e; + } + + return $ret; +} + +/** + * Returns the values from a single column in the input array. + * + *
    + *  {% set items = [{ 'fruit' : 'apple'}, {'fruit' : 'orange' }] %}
    + *
    + *  {% set fruits = items|column('fruit') %}
    + *
    + *  {# fruits now contains ['apple', 'orange'] #}
    + * 
    + * + * @param array|Traversable $array An array + * @param mixed $name The column name + * @param mixed $index The column to use as the index/keys for the returned array + * + * @return array The array of values + */ +function twig_array_column($array, $name, $index = null): array +{ + if ($array instanceof Traversable) { + $array = iterator_to_array($array); + } elseif (!\is_array($array)) { + throw new RuntimeError(sprintf('The column filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array))); + } + + return array_column($array, $name, $index); +} + +function twig_array_filter(Environment $env, $array, $arrow) +{ + if (!twig_test_iterable($array)) { + throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array))); + } + + twig_check_arrow_in_sandbox($env, $arrow, 'filter', 'filter'); + + if (\is_array($array)) { + return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); } // the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow); } -function twig_array_map($array, $arrow) +function twig_array_map(Environment $env, $array, $arrow) { + twig_check_arrow_in_sandbox($env, $arrow, 'map', 'filter'); + $r = []; foreach ($array as $k => $v) { $r[$k] = $arrow($v, $k); @@ -1717,12 +1634,25 @@ function twig_array_map($array, $arrow) return $r; } -function twig_array_reduce($array, $arrow, $initial = null) +function twig_array_reduce(Environment $env, $array, $arrow, $initial = null) { + twig_check_arrow_in_sandbox($env, $arrow, 'reduce', 'filter'); + if (!\is_array($array)) { + if (!$array instanceof \Traversable) { + throw new RuntimeError(sprintf('The "reduce" filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array))); + } + $array = iterator_to_array($array); } return array_reduce($array, $arrow, $initial); } + +function twig_check_arrow_in_sandbox(Environment $env, $arrow, $thing, $type) +{ + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError(sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type)); + } +} } diff --git a/system/libs/Twig/Extension/DebugExtension.php b/system/libs/Twig/Extension/DebugExtension.php index 09b0223e2f..2e8510dfb1 100644 --- a/system/libs/Twig/Extension/DebugExtension.php +++ b/system/libs/Twig/Extension/DebugExtension.php @@ -12,10 +12,7 @@ namespace Twig\Extension { use Twig\TwigFunction; -/** - * @final - */ -class DebugExtension extends AbstractExtension +final class DebugExtension extends AbstractExtension { public function getFunctions() { @@ -33,11 +30,6 @@ public function getFunctions() new TwigFunction('dump', 'twig_var_dump', ['is_safe' => $isDumpOutputHtmlSafe ? ['html'] : [], 'needs_context' => true, 'needs_environment' => true, 'is_variadic' => true]), ]; } - - public function getName() - { - return 'debug'; - } } class_alias('Twig\Extension\DebugExtension', 'Twig_Extension_Debug'); @@ -48,7 +40,7 @@ class_alias('Twig\Extension\DebugExtension', 'Twig_Extension_Debug'); use Twig\Template; use Twig\TemplateWrapper; -function twig_var_dump(Environment $env, $context, array $vars = []) +function twig_var_dump(Environment $env, $context, ...$vars) { if (!$env->isDebug()) { return; @@ -66,9 +58,7 @@ function twig_var_dump(Environment $env, $context, array $vars = []) var_dump($vars); } else { - foreach ($vars as $var) { - var_dump($var); - } + var_dump(...$vars); } return ob_get_clean(); diff --git a/system/libs/Twig/Extension/EscaperExtension.php b/system/libs/Twig/Extension/EscaperExtension.php index fc7f6dfeea..19dfd7d100 100644 --- a/system/libs/Twig/Extension/EscaperExtension.php +++ b/system/libs/Twig/Extension/EscaperExtension.php @@ -10,16 +10,21 @@ */ namespace Twig\Extension { +use Twig\FileExtensionEscapingStrategy; use Twig\NodeVisitor\EscaperNodeVisitor; use Twig\TokenParser\AutoEscapeTokenParser; use Twig\TwigFilter; -/** - * @final - */ -class EscaperExtension extends AbstractExtension +final class EscaperExtension extends AbstractExtension { - protected $defaultStrategy; + private $defaultStrategy; + private $escapers = []; + + /** @internal */ + public $safeClasses = []; + + /** @internal */ + public $safeLookup = []; /** * @param string|false|callable $defaultStrategy An escaping strategy @@ -44,6 +49,8 @@ public function getNodeVisitors() public function getFilters() { 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']]), ]; } @@ -58,21 +65,8 @@ public function getFilters() */ public function setDefaultStrategy($defaultStrategy) { - // for BC - if (true === $defaultStrategy) { - @trigger_error('Using "true" as the default strategy is deprecated since version 1.21. Use "html" instead.', E_USER_DEPRECATED); - - $defaultStrategy = 'html'; - } - - if ('filename' === $defaultStrategy) { - @trigger_error('Using "filename" as the default strategy is deprecated since version 1.27. Use "name" instead.', E_USER_DEPRECATED); - - $defaultStrategy = 'name'; - } - if ('name' === $defaultStrategy) { - $defaultStrategy = ['\Twig\FileExtensionEscapingStrategy', 'guess']; + $defaultStrategy = [FileExtensionEscapingStrategy::class, 'guess']; } $this->defaultStrategy = $defaultStrategy; @@ -96,9 +90,47 @@ public function getDefaultStrategy($name) return $this->defaultStrategy; } - public function getName() + /** + * 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) { - return 'escaper'; + $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; + } } } @@ -106,6 +138,14 @@ class_alias('Twig\Extension\EscaperExtension', 'Twig_Extension_Escaper'); } namespace { +use Twig\Environment; +use Twig\Error\RuntimeError; +use Twig\Extension\CoreExtension; +use Twig\Extension\EscaperExtension; +use Twig\Markup; +use Twig\Node\Expression\ConstantExpression; +use Twig\Node\Node; + /** * Marks a variable as being safe. * @@ -117,4 +157,272 @@ 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 '�'; + } + + /* + * 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 => '"', /* quotation mark */ + 38 => '&', /* ampersand */ + 60 => '<', /* less-than sign */ + 62 => '>', /* 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: + // check the ones set on CoreExtension for BC (to be removed in 3.0) + $legacyEscapers = $env->getExtension(CoreExtension::class)->getEscapers(false); + if (array_key_exists($strategy, $legacyEscapers)) { + return $legacyEscapers[$strategy]($env, $string, $charset); + } + + $escapers = $env->getExtension(EscaperExtension::class)->getEscapers(); + if (array_key_exists($strategy, $escapers)) { + return $escapers[$strategy]($env, $string, $charset); + } + + $escapers = array_merge($legacyEscapers, $escapers); + $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']; +} } diff --git a/system/libs/Twig/Extension/ExtensionInterface.php b/system/libs/Twig/Extension/ExtensionInterface.php index 72b31e9d1a..a083211258 100644 --- a/system/libs/Twig/Extension/ExtensionInterface.php +++ b/system/libs/Twig/Extension/ExtensionInterface.php @@ -11,7 +11,6 @@ namespace Twig\Extension; -use Twig\Environment; use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; use Twig\TwigFilter; @@ -25,15 +24,6 @@ */ interface ExtensionInterface { - /** - * Initializes the runtime environment. - * - * This is where you can load some file that contains filter functions for instance. - * - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_InitRuntimeInterface instead - */ - public function initRuntime(Environment $environment); - /** * Returns the token parser instances to add to the existing list. * @@ -75,24 +65,6 @@ public function getFunctions(); * @return array First array of unary operators, second array of binary operators */ public function getOperators(); - - /** - * Returns a list of global variables to add to the existing list. - * - * @return array An array of global variables - * - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_GlobalsInterface instead - */ - public function getGlobals(); - - /** - * Returns the name of the extension. - * - * @return string The extension name - * - * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally - */ - public function getName(); } class_alias('Twig\Extension\ExtensionInterface', 'Twig_ExtensionInterface'); diff --git a/system/libs/Twig/Extension/GlobalsInterface.php b/system/libs/Twig/Extension/GlobalsInterface.php index 1f54e25724..4421271b10 100644 --- a/system/libs/Twig/Extension/GlobalsInterface.php +++ b/system/libs/Twig/Extension/GlobalsInterface.php @@ -21,6 +21,12 @@ */ interface GlobalsInterface { + /** + * Returns a list of global variables to add to the existing list. + * + * @return array An array of global variables + */ + public function getGlobals(); } class_alias('Twig\Extension\GlobalsInterface', 'Twig_Extension_GlobalsInterface'); diff --git a/system/libs/Twig/Extension/InitRuntimeInterface.php b/system/libs/Twig/Extension/InitRuntimeInterface.php index f71d9cb51d..d64d3cd1b8 100644 --- a/system/libs/Twig/Extension/InitRuntimeInterface.php +++ b/system/libs/Twig/Extension/InitRuntimeInterface.php @@ -11,6 +11,8 @@ namespace Twig\Extension; +use Twig\Environment; + /** * Enables usage of the deprecated Twig\Extension\AbstractExtension::initRuntime() method. * @@ -18,9 +20,17 @@ * deprecated initRuntime() method in your extensions. * * @author Fabien Potencier + * + * @deprecated since Twig 2.7, to be removed in 3.0 */ interface InitRuntimeInterface { + /** + * Initializes the runtime environment. + * + * This is where you can load some file that contains filter functions for instance. + */ + public function initRuntime(Environment $environment); } class_alias('Twig\Extension\InitRuntimeInterface', 'Twig_Extension_InitRuntimeInterface'); diff --git a/system/libs/Twig/Extension/OptimizerExtension.php b/system/libs/Twig/Extension/OptimizerExtension.php index 3e137409e2..9552b35898 100644 --- a/system/libs/Twig/Extension/OptimizerExtension.php +++ b/system/libs/Twig/Extension/OptimizerExtension.php @@ -13,12 +13,9 @@ use Twig\NodeVisitor\OptimizerNodeVisitor; -/** - * @final - */ -class OptimizerExtension extends AbstractExtension +final class OptimizerExtension extends AbstractExtension { - protected $optimizers; + private $optimizers; public function __construct($optimizers = -1) { @@ -29,11 +26,6 @@ public function getNodeVisitors() { return [new OptimizerNodeVisitor($this->optimizers)]; } - - public function getName() - { - return 'optimizer'; - } } class_alias('Twig\Extension\OptimizerExtension', 'Twig_Extension_Optimizer'); diff --git a/system/libs/Twig/Extension/ProfilerExtension.php b/system/libs/Twig/Extension/ProfilerExtension.php index 7b21b9fa55..9e87c05a03 100644 --- a/system/libs/Twig/Extension/ProfilerExtension.php +++ b/system/libs/Twig/Extension/ProfilerExtension.php @@ -41,12 +41,7 @@ public function leave(Profile $profile) public function getNodeVisitors() { - return [new ProfilerNodeVisitor(\get_class($this))]; - } - - public function getName() - { - return 'profiler'; + return [new ProfilerNodeVisitor(static::class)]; } } diff --git a/system/libs/Twig/Extension/SandboxExtension.php b/system/libs/Twig/Extension/SandboxExtension.php index 818c8c94c8..dca3262a43 100644 --- a/system/libs/Twig/Extension/SandboxExtension.php +++ b/system/libs/Twig/Extension/SandboxExtension.php @@ -12,17 +12,17 @@ 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 +final class SandboxExtension extends AbstractExtension { - protected $sandboxedGlobally; - protected $sandboxed; - protected $policy; + private $sandboxedGlobally; + private $sandboxed; + private $policy; public function __construct(SecurityPolicyInterface $policy, $sandboxed = false) { @@ -77,33 +77,49 @@ public function checkSecurity($tags, $filters, $functions) } } - public function checkMethodAllowed($obj, $method) + public function checkMethodAllowed($obj, $method, int $lineno = -1, Source $source = null) { if ($this->isSandboxed()) { - $this->policy->checkMethodAllowed($obj, $method); + try { + $this->policy->checkMethodAllowed($obj, $method); + } catch (SecurityNotAllowedMethodError $e) { + $e->setSourceContext($source); + $e->setTemplateLine($lineno); + + throw $e; + } } } - public function checkPropertyAllowed($obj, $method) + public function checkPropertyAllowed($obj, $property, int $lineno = -1, Source $source = null) { if ($this->isSandboxed()) { - $this->policy->checkPropertyAllowed($obj, $method); + try { + $this->policy->checkPropertyAllowed($obj, $property); + } catch (SecurityNotAllowedPropertyError $e) { + $e->setSourceContext($source); + $e->setTemplateLine($lineno); + + throw $e; + } } } - public function ensureToStringAllowed($obj) + public function ensureToStringAllowed($obj, int $lineno = -1, Source $source = null) { if ($this->isSandboxed() && \is_object($obj) && method_exists($obj, '__toString')) { - $this->policy->checkMethodAllowed($obj, '__toString'); + try { + $this->policy->checkMethodAllowed($obj, '__toString'); + } catch (SecurityNotAllowedMethodError $e) { + $e->setSourceContext($source); + $e->setTemplateLine($lineno); + + throw $e; + } } return $obj; } - - public function getName() - { - return 'sandbox'; - } } class_alias('Twig\Extension\SandboxExtension', 'Twig_Extension_Sandbox'); diff --git a/system/libs/Twig/Extension/StagingExtension.php b/system/libs/Twig/Extension/StagingExtension.php index 049c5c7977..7c0c26c862 100644 --- a/system/libs/Twig/Extension/StagingExtension.php +++ b/system/libs/Twig/Extension/StagingExtension.php @@ -13,32 +13,32 @@ use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; +use Twig\TwigFilter; +use Twig\TwigFunction; +use Twig\TwigTest; /** - * Internal class. - * - * This class is used by \Twig\Environment as a staging area and must not be used directly. + * Used by \Twig\Environment as a staging area. * * @author Fabien Potencier * * @internal */ -class StagingExtension extends AbstractExtension +final class StagingExtension extends AbstractExtension { - protected $functions = []; - protected $filters = []; - protected $visitors = []; - protected $tokenParsers = []; - protected $globals = []; - protected $tests = []; - - public function addFunction($name, $function) + private $functions = []; + private $filters = []; + private $visitors = []; + private $tokenParsers = []; + private $tests = []; + + public function addFunction(TwigFunction $function) { - if (isset($this->functions[$name])) { - @trigger_error(sprintf('Overriding function "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); + if (isset($this->functions[$function->getName()])) { + throw new \LogicException(sprintf('Function "%s" is already registered.', $function->getName())); } - $this->functions[$name] = $function; + $this->functions[$function->getName()] = $function; } public function getFunctions() @@ -46,13 +46,13 @@ public function getFunctions() return $this->functions; } - public function addFilter($name, $filter) + public function addFilter(TwigFilter $filter) { - if (isset($this->filters[$name])) { - @trigger_error(sprintf('Overriding filter "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); + if (isset($this->filters[$filter->getName()])) { + throw new \LogicException(sprintf('Filter "%s" is already registered.', $filter->getName())); } - $this->filters[$name] = $filter; + $this->filters[$filter->getName()] = $filter; } public function getFilters() @@ -73,7 +73,7 @@ public function getNodeVisitors() public function addTokenParser(TokenParserInterface $parser) { if (isset($this->tokenParsers[$parser->getTag()])) { - @trigger_error(sprintf('Overriding tag "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED); + throw new \LogicException(sprintf('Tag "%s" is already registered.', $parser->getTag())); } $this->tokenParsers[$parser->getTag()] = $parser; @@ -84,34 +84,19 @@ public function getTokenParsers() return $this->tokenParsers; } - public function addGlobal($name, $value) - { - $this->globals[$name] = $value; - } - - public function getGlobals() + public function addTest(TwigTest $test) { - return $this->globals; - } - - public function addTest($name, $test) - { - if (isset($this->tests[$name])) { - @trigger_error(sprintf('Overriding test "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); + if (isset($this->tests[$test->getName()])) { + throw new \LogicException(sprintf('Test "%s" is already registered.', $test->getName())); } - $this->tests[$name] = $test; + $this->tests[$test->getName()] = $test; } public function getTests() { return $this->tests; } - - public function getName() - { - return 'staging'; - } } class_alias('Twig\Extension\StagingExtension', 'Twig_Extension_Staging'); diff --git a/system/libs/Twig/Extension/StringLoaderExtension.php b/system/libs/Twig/Extension/StringLoaderExtension.php index 93ac834ac2..d6718620e7 100644 --- a/system/libs/Twig/Extension/StringLoaderExtension.php +++ b/system/libs/Twig/Extension/StringLoaderExtension.php @@ -12,10 +12,7 @@ namespace Twig\Extension { use Twig\TwigFunction; -/** - * @final - */ -class StringLoaderExtension extends AbstractExtension +final class StringLoaderExtension extends AbstractExtension { public function getFunctions() { @@ -23,11 +20,6 @@ public function getFunctions() new TwigFunction('template_from_string', 'twig_template_from_string', ['needs_environment' => true]), ]; } - - public function getName() - { - return 'string_loader'; - } } class_alias('Twig\Extension\StringLoaderExtension', 'Twig_Extension_StringLoader'); @@ -47,7 +39,7 @@ class_alias('Twig\Extension\StringLoaderExtension', 'Twig_Extension_StringLoader * * @return TemplateWrapper */ -function twig_template_from_string(Environment $env, $template, $name = null) +function twig_template_from_string(Environment $env, $template, string $name = null) { return $env->createTemplate((string) $template, $name); } diff --git a/system/libs/Twig/ExtensionSet.php b/system/libs/Twig/ExtensionSet.php new file mode 100644 index 0000000000..deba573fbb --- /dev/null +++ b/system/libs/Twig/ExtensionSet.php @@ -0,0 +1,475 @@ + + * + * @internal + */ +final class ExtensionSet +{ + private $extensions; + private $initialized = false; + private $runtimeInitialized = false; + private $staging; + private $parsers; + private $visitors; + private $filters; + private $tests; + private $functions; + private $unaryOperators; + private $binaryOperators; + private $globals; + private $functionCallbacks = []; + private $filterCallbacks = []; + private $lastModified = 0; + + public function __construct() + { + $this->staging = new StagingExtension(); + } + + /** + * Initializes the runtime environment. + * + * @deprecated since Twig 2.7 + */ + public function initRuntime(Environment $env) + { + if ($this->runtimeInitialized) { + return; + } + + $this->runtimeInitialized = true; + + foreach ($this->extensions as $extension) { + if ($extension instanceof InitRuntimeInterface) { + $extension->initRuntime($env); + } + } + } + + public function hasExtension(string $class): bool + { + $class = ltrim($class, '\\'); + if (!isset($this->extensions[$class]) && class_exists($class, false)) { + // For BC/FC with namespaced aliases + $class = (new \ReflectionClass($class))->name; + } + + return isset($this->extensions[$class]); + } + + public function getExtension(string $class): ExtensionInterface + { + $class = ltrim($class, '\\'); + if (!isset($this->extensions[$class]) && class_exists($class, false)) { + // For BC/FC with namespaced aliases + $class = (new \ReflectionClass($class))->name; + } + + 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) + { + 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 (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModified) { + $this->lastModified = $extensionTime; + } + } + + return $this->lastModified; + } + + public function addExtension(ExtensionInterface $extension) + { + $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) + { + 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; + } + + /** + * @return TwigFunction|false + */ + public function getFunction(string $name) + { + 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 false; + } + + public function registerUndefinedFunctionCallback(callable $callable) + { + $this->functionCallbacks[] = $callable; + } + + public function addFilter(TwigFilter $filter) + { + 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; + } + + /** + * @return TwigFilter|false + */ + public function getFilter(string $name) + { + 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 false; + } + + public function registerUndefinedFilterCallback(callable $callable) + { + $this->filterCallbacks[] = $callable; + } + + public function addNodeVisitor(NodeVisitorInterface $visitor) + { + 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) + { + 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 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) + { + 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; + } + + /** + * @return TwigTest|false + */ + public function getTest(string $name) + { + 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 false; + } + + public function getUnaryOperators(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->unaryOperators; + } + + public function getBinaryOperators(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->binaryOperators; + } + + private function initExtensions() + { + $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) + { + // 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; + } + + // 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]); + } + } +} + +class_alias('Twig\ExtensionSet', 'Twig_ExtensionSet'); diff --git a/system/libs/Twig/FileExtensionEscapingStrategy.php b/system/libs/Twig/FileExtensionEscapingStrategy.php index bc95f33435..d79106c314 100644 --- a/system/libs/Twig/FileExtensionEscapingStrategy.php +++ b/system/libs/Twig/FileExtensionEscapingStrategy.php @@ -41,7 +41,7 @@ public static function guess($name) $name = substr($name, 0, -5); } - $extension = pathinfo($name, PATHINFO_EXTENSION); + $extension = pathinfo($name, \PATHINFO_EXTENSION); switch ($extension) { case 'js': diff --git a/system/libs/Twig/Lexer.php b/system/libs/Twig/Lexer.php index 697a6cfa1d..edde9a7a0c 100644 --- a/system/libs/Twig/Lexer.php +++ b/system/libs/Twig/Lexer.php @@ -19,39 +19,36 @@ * * @author Fabien Potencier */ -class Lexer implements \Twig_LexerInterface +class Lexer { - protected $tokens; - protected $code; - protected $cursor; - protected $lineno; - protected $end; - protected $state; - protected $states; - protected $brackets; - protected $env; - // to be renamed to $name in 2.0 (where it is private) - protected $filename; - protected $options; - protected $regexes; - protected $position; - protected $positions; - protected $currentVarBlockLine; - + private $tokens; + private $code; + private $cursor; + private $lineno; + private $end; + private $state; + private $states; + private $brackets; + private $env; private $source; - - const STATE_DATA = 0; - const STATE_BLOCK = 1; - const STATE_VAR = 2; - const STATE_STRING = 3; - const STATE_INTERPOLATION = 4; - - const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'; - const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?([Ee][\+\-][0-9]+)?/A'; - const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; - const REGEX_DQ_STRING_DELIM = '/"/A'; - const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; - const PUNCTUATION = '()[]{}?:.,|'; + 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 = []) { @@ -100,9 +97,7 @@ public function __construct(Environment $env, array $options = []) $this->options['whitespace_trim']. // - '|'. $this->options['whitespace_line_trim']. // ~ - ')?\s*'. - '(?:end%s)'. // endraw or endverbatim - '\s*'. + ')?\s*endverbatim\s*'. '(?:'. preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '#').'\s*'. // -%} '|'. @@ -117,7 +112,7 @@ public function __construct(Environment $env, array $options = []) // #} 'lex_comment' => '{ (?:'. - preg_quote($this->options['whitespace_trim']).preg_quote($this->options['tag_comment'][1], '#').'\s*\n?'. // -#}\s*\n? + 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]* '|'. @@ -127,9 +122,7 @@ public function __construct(Environment $env, array $options = []) // verbatim %} 'lex_block_raw' => '{ - \s* - (raw|verbatim) - \s* + \s*verbatim\s* (?:'. preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '#').'\s*'. // -%}\s* '|'. @@ -160,28 +153,10 @@ public function __construct(Environment $env, array $options = []) ]; } - public function tokenize($code, $name = null) + public function tokenize(Source $source) { - if (!$code instanceof Source) { - @trigger_error(sprintf('Passing a string as the $code argument of %s() is deprecated since version 1.27 and will be removed in 2.0. Pass a \Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $this->source = new Source($code, $name); - } else { - $this->source = $code; - } - - if (((int) ini_get('mbstring.func_overload')) & 2) { - @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED); - } - - if (\function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { - $mbEncoding = mb_internal_encoding(); - mb_internal_encoding('ASCII'); - } else { - $mbEncoding = null; - } - - $this->code = str_replace(["\r\n", "\r"], "\n", $this->source->getCode()); - $this->filename = $this->source->getName(); + $this->source = $source; + $this->code = str_replace(["\r\n", "\r"], "\n", $source->getCode()); $this->cursor = 0; $this->lineno = 1; $this->end = \strlen($this->code); @@ -192,7 +167,7 @@ public function tokenize($code, $name = null) $this->position = -1; // find all token starts in one go - preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE); + preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, \PREG_OFFSET_CAPTURE); $this->positions = $matches; while ($this->cursor < $this->end) { @@ -221,25 +196,21 @@ public function tokenize($code, $name = null) } } - $this->pushToken(Token::EOF_TYPE); + $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); } - if ($mbEncoding) { - mb_internal_encoding($mbEncoding); - } - return new TokenStream($this->tokens, $this->source); } - protected function lexData() + private function lexData() { // if no matches are left we return the rest of the template as simple text token if ($this->position == \count($this->positions[0]) - 1) { - $this->pushToken(Token::TEXT_TYPE, substr($this->code, $this->cursor)); + $this->pushToken(/* Token::TEXT_TYPE */ 0, substr($this->code, $this->cursor)); $this->cursor = $this->end; return; @@ -268,7 +239,7 @@ protected function lexData() $text = rtrim($text, " \t\0\x0B"); } } - $this->pushToken(Token::TEXT_TYPE, $text); + $this->pushToken(/* Token::TEXT_TYPE */ 0, $text); $this->moveCursor($textContent.$position[0]); switch ($this->positions[1][$this->position][0]) { @@ -280,30 +251,30 @@ protected function lexData() // raw data? if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, 0, $this->cursor)) { $this->moveCursor($match[0]); - $this->lexRawData($match[1]); + $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); + $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); + $this->pushToken(/* Token::VAR_START_TYPE */ 2); $this->pushState(self::STATE_VAR); $this->currentVarBlockLine = $this->lineno; break; } } - protected function lexBlock() + private function lexBlock() { if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::BLOCK_END_TYPE); + $this->pushToken(/* Token::BLOCK_END_TYPE */ 3); $this->moveCursor($match[0]); $this->popState(); } else { @@ -311,10 +282,10 @@ protected function lexBlock() } } - protected function lexVar() + private function lexVar() { if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::VAR_END_TYPE); + $this->pushToken(/* Token::VAR_END_TYPE */ 4); $this->moveCursor($match[0]); $this->popState(); } else { @@ -322,7 +293,7 @@ protected function lexVar() } } - protected function lexExpression() + private function lexExpression() { // whitespace if (preg_match('/\s+/A', $this->code, $match, 0, $this->cursor)) { @@ -340,21 +311,21 @@ protected function lexExpression() } // operators elseif (preg_match($this->regexes['operator'], $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0])); + $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, $match[0]); + $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) { + if (ctype_digit($match[0]) && $number <= \PHP_INT_MAX) { $number = (int) $match[0]; // integers lower than the maximum } - $this->pushToken(Token::NUMBER_TYPE, $number); + $this->pushToken(/* Token::NUMBER_TYPE */ 6, $number); $this->moveCursor($match[0]); } // punctuation @@ -375,12 +346,12 @@ protected function lexExpression() } } - $this->pushToken(Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); + $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, stripcslashes(substr($match[0], 1, -1))); + $this->pushToken(/* Token::STRING_TYPE */ 7, stripcslashes(substr($match[0], 1, -1))); $this->moveCursor($match[0]); } // opening double quoted string @@ -395,14 +366,10 @@ protected function lexExpression() } } - protected function lexRawData($tag) + private function lexRawData() { - if ('raw' === $tag) { - @trigger_error(sprintf('Twig Tag "raw" is deprecated since version 1.21. Use "verbatim" instead in %s at line %d.', $this->filename, $this->lineno), E_USER_DEPRECATED); - } - - if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { - throw new SyntaxError(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->source); + 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); @@ -420,27 +387,27 @@ protected function lexRawData($tag) } } - $this->pushToken(Token::TEXT_TYPE, $text); + $this->pushToken(/* Token::TEXT_TYPE */ 0, $text); } - protected function lexComment() + private function lexComment() { - if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { + 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]); } - protected function lexString() + private function lexString() { 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); + $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, stripcslashes($match[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); @@ -456,12 +423,12 @@ protected function lexString() } } - protected function lexInterpolation() + private function lexInterpolation() { $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); + $this->pushToken(/* Token::INTERPOLATION_END_TYPE */ 11); $this->moveCursor($match[0]); $this->popState(); } else { @@ -469,23 +436,23 @@ protected function lexInterpolation() } } - protected function pushToken($type, $value = '') + private function pushToken($type, $value = '') { // do not push empty text tokens - if (Token::TEXT_TYPE === $type && '' === $value) { + if (/* Token::TEXT_TYPE */ 0 === $type && '' === $value) { return; } $this->tokens[] = new Token($type, $value, $this->lineno); } - protected function moveCursor($text) + private function moveCursor($text) { $this->cursor += \strlen($text); $this->lineno += substr_count($text, "\n"); } - protected function getOperatorRegex() + private function getOperatorRegex() { $operators = array_merge( ['='], @@ -499,11 +466,15 @@ protected function getOperatorRegex() $regex = []; foreach ($operators as $operator => $length) { // an operator that ends with a character must be followed by - // a whitespace or a parenthesis + // a whitespace, a parenthesis, an opening map [ or sequence { + $r = preg_quote($operator, '/'); if (ctype_alpha($operator[$length - 1])) { - $r = preg_quote($operator, '/').'(?=[\s()])'; - } else { - $r = preg_quote($operator, '/'); + $r .= '(?=[\s()\[{])'; + } + + // an operator that begins with a character must not have a dot or pipe before + if (ctype_alpha($operator[0])) { + $r = '(?states[] = $this->state; $this->state = $state; } - protected function popState() + private function popState() { if (0 === \count($this->states)) { throw new \LogicException('Cannot pop state without a previous state.'); diff --git a/system/libs/Twig/Loader/ArrayLoader.php b/system/libs/Twig/Loader/ArrayLoader.php index 6bc430f50e..b03170b232 100644 --- a/system/libs/Twig/Loader/ArrayLoader.php +++ b/system/libs/Twig/Loader/ArrayLoader.php @@ -24,13 +24,11 @@ * * This loader should only be used for unit testing. * - * @final - * * @author Fabien Potencier */ -class ArrayLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface +final class ArrayLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface { - protected $templates = []; + private $templates = []; /** * @param array $templates An array of templates (keys are the names, and values are the source code) @@ -48,19 +46,7 @@ public function __construct(array $templates = []) */ public function setTemplate($name, $template) { - $this->templates[(string) $name] = $template; - } - - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); - - $name = (string) $name; - if (!isset($this->templates[$name])) { - throw new LoaderError(sprintf('Template "%s" is not defined.', $name)); - } - - return $this->templates[$name]; + $this->templates[$name] = $template; } public function getSourceContext($name) @@ -75,12 +61,11 @@ public function getSourceContext($name) public function exists($name) { - return isset($this->templates[(string) $name]); + return isset($this->templates[$name]); } public function getCacheKey($name) { - $name = (string) $name; if (!isset($this->templates[$name])) { throw new LoaderError(sprintf('Template "%s" is not defined.', $name)); } @@ -90,7 +75,6 @@ public function getCacheKey($name) public function isFresh($name, $time) { - $name = (string) $name; if (!isset($this->templates[$name])) { throw new LoaderError(sprintf('Template "%s" is not defined.', $name)); } diff --git a/system/libs/Twig/Loader/ChainLoader.php b/system/libs/Twig/Loader/ChainLoader.php index 25ac55a335..edb9df8ca1 100644 --- a/system/libs/Twig/Loader/ChainLoader.php +++ b/system/libs/Twig/Loader/ChainLoader.php @@ -12,19 +12,16 @@ namespace Twig\Loader; use Twig\Error\LoaderError; -use Twig\Source; /** * Loads templates from other loaders. * - * @final - * * @author Fabien Potencier */ -class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface +final class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface { private $hasSourceCache = []; - protected $loaders = []; + private $loaders = []; /** * @param LoaderInterface[] $loaders @@ -50,40 +47,16 @@ public function getLoaders() return $this->loaders; } - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); - - $exceptions = []; - foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { - continue; - } - - try { - return $loader->getSource($name); - } catch (LoaderError $e) { - $exceptions[] = $e->getMessage(); - } - } - - throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); - } - public function getSourceContext($name) { $exceptions = []; foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { + if (!$loader->exists($name)) { continue; } try { - if ($loader instanceof SourceContextLoaderInterface) { - return $loader->getSourceContext($name); - } - - return new Source($loader->getSource($name), $name); + return $loader->getSourceContext($name); } catch (LoaderError $e) { $exceptions[] = $e->getMessage(); } @@ -94,30 +67,13 @@ public function getSourceContext($name) public function exists($name) { - $name = (string) $name; - if (isset($this->hasSourceCache[$name])) { return $this->hasSourceCache[$name]; } foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface) { - if ($loader->exists($name)) { - return $this->hasSourceCache[$name] = true; - } - - continue; - } - - try { - if ($loader instanceof SourceContextLoaderInterface) { - $loader->getSourceContext($name); - } else { - $loader->getSource($name); - } - + if ($loader->exists($name)) { return $this->hasSourceCache[$name] = true; - } catch (LoaderError $e) { } } @@ -128,7 +84,7 @@ public function getCacheKey($name) { $exceptions = []; foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { + if (!$loader->exists($name)) { continue; } @@ -146,7 +102,7 @@ public function isFresh($name, $time) { $exceptions = []; foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { + if (!$loader->exists($name)) { continue; } diff --git a/system/libs/Twig/Loader/ExistsLoaderInterface.php b/system/libs/Twig/Loader/ExistsLoaderInterface.php index 940d87618c..aab8bd8619 100644 --- a/system/libs/Twig/Loader/ExistsLoaderInterface.php +++ b/system/libs/Twig/Loader/ExistsLoaderInterface.php @@ -12,22 +12,12 @@ namespace Twig\Loader; /** - * Adds an exists() method for loaders. + * Empty interface for Twig 1.x compatibility. * - * @author Florin Patan - * - * @deprecated since 1.12 (to be removed in 3.0) + * @deprecated since Twig 2.7, to be removed in 3.0 */ -interface ExistsLoaderInterface +interface ExistsLoaderInterface extends LoaderInterface { - /** - * Check if we have the source code of a template, given its name. - * - * @param string $name The name of the template to check if we can load - * - * @return bool If the template source code is handled by this loader or not - */ - public function exists($name); } class_alias('Twig\Loader\ExistsLoaderInterface', 'Twig_ExistsLoaderInterface'); diff --git a/system/libs/Twig/Loader/FilesystemLoader.php b/system/libs/Twig/Loader/FilesystemLoader.php index 19b43a2954..8cac30bed6 100644 --- a/system/libs/Twig/Loader/FilesystemLoader.php +++ b/system/libs/Twig/Loader/FilesystemLoader.php @@ -22,7 +22,7 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface { /** Identifier of the main namespace. */ - const MAIN_NAMESPACE = '__main__'; + public const MAIN_NAMESPACE = '__main__'; protected $paths = []; protected $cache = []; @@ -34,10 +34,10 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source * @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 = [], $rootPath = null) + public function __construct($paths = [], string $rootPath = null) { $this->rootPath = (null === $rootPath ? getcwd() : $rootPath).\DIRECTORY_SEPARATOR; - if (false !== $realPath = realpath($rootPath)) { + if (null !== $rootPath && false !== ($realPath = realpath($rootPath))) { $this->rootPath = $realPath.\DIRECTORY_SEPARATOR; } @@ -136,17 +136,6 @@ public function prependPath($path, $namespace = self::MAIN_NAMESPACE) } } - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); - - if (null === ($path = $this->findTemplate($name)) || false === $path) { - return ''; - } - - return file_get_contents($path); - } - public function getSourceContext($name) { if (null === ($path = $this->findTemplate($name)) || false === $path) { @@ -177,13 +166,7 @@ public function exists($name) return true; } - try { - return null !== ($path = $this->findTemplate($name, false)) && false !== $path; - } catch (LoaderError $e) { - @trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', \get_class($this)), E_USER_DEPRECATED); - - return false; - } + return null !== ($path = $this->findTemplate($name, false)) && false !== $path; } public function isFresh($name, $time) @@ -199,13 +182,15 @@ public function isFresh($name, $time) /** * Checks if the template can be found. * - * @param string $name The template name + * In Twig 3.0, findTemplate must return a string or null (returning false won't work anymore). + * + * @param string $name The template name + * @param bool $throw Whether to throw an exception when an error occurs * * @return string|false|null The template name or false/null */ - protected function findTemplate($name) + protected function findTemplate($name, $throw = true) { - $throw = \func_num_args() > 1 ? func_get_arg(1) : true; $name = $this->normalizeName($name); if (isset($this->cache[$name])) { @@ -221,9 +206,9 @@ protected function findTemplate($name) } try { - $this->validateName($name); - list($namespace, $shortname) = $this->parseName($name); + + $this->validateName($shortname); } catch (LoaderError $e) { if (!$throw) { return false; @@ -265,7 +250,12 @@ protected function findTemplate($name) throw new LoaderError($this->errorCache[$name]); } - protected function parseName($name, $default = self::MAIN_NAMESPACE) + private function normalizeName($name) + { + return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); + } + + private function parseName($name, $default = self::MAIN_NAMESPACE) { if (isset($name[0]) && '@' == $name[0]) { if (false === $pos = strpos($name, '/')) { @@ -281,12 +271,7 @@ protected function parseName($name, $default = self::MAIN_NAMESPACE) return [$default, $name]; } - protected function normalizeName($name) - { - return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); - } - - protected function validateName($name) + private function validateName($name) { if (false !== strpos($name, "\0")) { throw new LoaderError('A template name cannot contain NUL bytes.'); @@ -312,10 +297,10 @@ private function isAbsolutePath($file) { return strspn($file, '/\\', 0, 1) || (\strlen($file) > 3 && ctype_alpha($file[0]) - && ':' === substr($file, 1, 1) + && ':' === $file[1] && strspn($file, '/\\', 2, 1) ) - || null !== parse_url($file, PHP_URL_SCHEME) + || null !== parse_url($file, \PHP_URL_SCHEME) ; } } diff --git a/system/libs/Twig/Loader/LoaderInterface.php b/system/libs/Twig/Loader/LoaderInterface.php index 15be7a88cd..5ccd2c785b 100644 --- a/system/libs/Twig/Loader/LoaderInterface.php +++ b/system/libs/Twig/Loader/LoaderInterface.php @@ -12,6 +12,7 @@ namespace Twig\Loader; use Twig\Error\LoaderError; +use Twig\Source; /** * Interface all loaders must implement. @@ -21,17 +22,15 @@ interface LoaderInterface { /** - * Gets the source code of a template, given its name. + * Returns the source context for a given template logical name. * - * @param string $name The name of the template to load + * @param string $name The template logical name * - * @return string The template source code + * @return Source * * @throws LoaderError When $name is not found - * - * @deprecated since 1.27 (to be removed in 2.0), implement Twig\Loader\SourceContextLoaderInterface */ - public function getSource($name); + public function getSourceContext($name); /** * Gets the cache key to use for the cache for a given template name. @@ -56,6 +55,15 @@ public function getCacheKey($name); * @throws LoaderError When $name is not found */ public function isFresh($name, $time); + + /** + * Check if we have the source code of a template, given its name. + * + * @param string $name The name of the template to check if we can load + * + * @return bool If the template source code is handled by this loader or not + */ + public function exists($name); } class_alias('Twig\Loader\LoaderInterface', 'Twig_LoaderInterface'); diff --git a/system/libs/Twig/Loader/SourceContextLoaderInterface.php b/system/libs/Twig/Loader/SourceContextLoaderInterface.php index 78b1fcd40e..4fdb17ea5c 100644 --- a/system/libs/Twig/Loader/SourceContextLoaderInterface.php +++ b/system/libs/Twig/Loader/SourceContextLoaderInterface.php @@ -11,28 +11,11 @@ namespace Twig\Loader; -use Twig\Error\LoaderError; -use Twig\Source; - /** - * Adds a getSourceContext() method for loaders. - * - * @author Fabien Potencier - * - * @deprecated since 1.27 (to be removed in 3.0) + * Empty interface for Twig 1.x compatibility. */ -interface SourceContextLoaderInterface +interface SourceContextLoaderInterface extends LoaderInterface { - /** - * Returns the source context for a given template logical name. - * - * @param string $name The template logical name - * - * @return Source - * - * @throws LoaderError When $name is not found - */ - public function getSourceContext($name); } class_alias('Twig\Loader\SourceContextLoaderInterface', 'Twig_SourceContextLoaderInterface'); diff --git a/system/libs/Twig/Markup.php b/system/libs/Twig/Markup.php index 107941cdf7..0cc45bef13 100644 --- a/system/libs/Twig/Markup.php +++ b/system/libs/Twig/Markup.php @@ -16,10 +16,10 @@ * * @author Fabien Potencier */ -class Markup implements \Countable +class Markup implements \Countable, \JsonSerializable { - protected $content; - protected $charset; + private $content; + private $charset; public function __construct($content, $charset) { @@ -32,9 +32,22 @@ public function __toString() return $this->content; } + /** + * @return int + */ + #[\ReturnTypeWillChange] public function count() { - return \function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : \strlen($this->content); + return mb_strlen($this->content, $this->charset); + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return $this->content; } } diff --git a/system/libs/Twig/Node/AutoEscapeNode.php b/system/libs/Twig/Node/AutoEscapeNode.php index a9403066ae..0bd5ae1fdf 100644 --- a/system/libs/Twig/Node/AutoEscapeNode.php +++ b/system/libs/Twig/Node/AutoEscapeNode.php @@ -26,7 +26,7 @@ */ class AutoEscapeNode extends Node { - public function __construct($value, \Twig_NodeInterface $body, $lineno, $tag = 'autoescape') + public function __construct($value, Node $body, int $lineno, string $tag = 'autoescape') { parent::__construct(['body' => $body], ['value' => $value], $lineno, $tag); } diff --git a/system/libs/Twig/Node/BlockNode.php b/system/libs/Twig/Node/BlockNode.php index 1ffc8ca78a..4da6e6ff77 100644 --- a/system/libs/Twig/Node/BlockNode.php +++ b/system/libs/Twig/Node/BlockNode.php @@ -21,7 +21,7 @@ */ class BlockNode extends Node { - public function __construct($name, \Twig_NodeInterface $body, $lineno, $tag = null) + public function __construct(string $name, Node $body, int $lineno, string $tag = null) { parent::__construct(['body' => $body], ['name' => $name], $lineno, $tag); } @@ -32,6 +32,7 @@ public function compile(Compiler $compiler) ->addDebugInfo($this) ->write(sprintf("public function block_%s(\$context, array \$blocks = [])\n", $this->getAttribute('name')), "{\n") ->indent() + ->write("\$macros = \$this->macros;\n") ; $compiler diff --git a/system/libs/Twig/Node/BlockReferenceNode.php b/system/libs/Twig/Node/BlockReferenceNode.php index de069093f6..c46d8b3e32 100644 --- a/system/libs/Twig/Node/BlockReferenceNode.php +++ b/system/libs/Twig/Node/BlockReferenceNode.php @@ -21,7 +21,7 @@ */ class BlockReferenceNode extends Node implements NodeOutputInterface { - public function __construct($name, $lineno, $tag = null) + public function __construct(string $name, int $lineno, string $tag = null) { parent::__construct([], ['name' => $name], $lineno, $tag); } diff --git a/system/libs/Twig/Node/CheckSecurityCallNode.php b/system/libs/Twig/Node/CheckSecurityCallNode.php new file mode 100644 index 0000000000..a78a38d80b --- /dev/null +++ b/system/libs/Twig/Node/CheckSecurityCallNode.php @@ -0,0 +1,28 @@ + + */ +class CheckSecurityCallNode extends Node +{ + public function compile(Compiler $compiler) + { + $compiler + ->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n") + ->write("\$this->checkSecurity();\n") + ; + } +} diff --git a/system/libs/Twig/Node/CheckSecurityNode.php b/system/libs/Twig/Node/CheckSecurityNode.php index cf0a7a13d8..489a3652dd 100644 --- a/system/libs/Twig/Node/CheckSecurityNode.php +++ b/system/libs/Twig/Node/CheckSecurityNode.php @@ -18,9 +18,9 @@ */ class CheckSecurityNode extends Node { - protected $usedFilters; - protected $usedTags; - protected $usedFunctions; + private $usedFilters; + private $usedTags; + private $usedFunctions; public function __construct(array $usedFilters, array $usedTags, array $usedFunctions) { @@ -45,10 +45,13 @@ public function compile(Compiler $compiler) } $compiler - ->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n") - ->write('$tags = ')->repr(array_filter($tags))->raw(";\n") - ->write('$filters = ')->repr(array_filter($filters))->raw(";\n") - ->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n") + ->write("\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") @@ -61,7 +64,7 @@ public function compile(Compiler $compiler) ->outdent() ->write("} catch (SecurityError \$e) {\n") ->indent() - ->write("\$e->setSourceContext(\$this->getSourceContext());\n\n") + ->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") @@ -78,6 +81,8 @@ public function compile(Compiler $compiler) ->write("throw \$e;\n") ->outdent() ->write("}\n\n") + ->outdent() + ->write("}\n") ; } } diff --git a/system/libs/Twig/Node/CheckToStringNode.php b/system/libs/Twig/Node/CheckToStringNode.php index 5d67467916..02b42fcdbc 100644 --- a/system/libs/Twig/Node/CheckToStringNode.php +++ b/system/libs/Twig/Node/CheckToStringNode.php @@ -33,10 +33,13 @@ public function __construct(AbstractExpression $expr) public function compile(Compiler $compiler) { + $expr = $this->getNode('expr'); $compiler ->raw('$this->sandbox->ensureToStringAllowed(') - ->subcompile($this->getNode('expr')) - ->raw(')') + ->subcompile($expr) + ->raw(', ') + ->repr($expr->getTemplateLine()) + ->raw(', $this->source)') ; } } diff --git a/system/libs/Twig/Node/DeprecatedNode.php b/system/libs/Twig/Node/DeprecatedNode.php index 62c0dd4ba5..accd768047 100644 --- a/system/libs/Twig/Node/DeprecatedNode.php +++ b/system/libs/Twig/Node/DeprecatedNode.php @@ -22,7 +22,7 @@ */ class DeprecatedNode extends Node { - public function __construct(AbstractExpression $expr, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, int $lineno, string $tag = null) { parent::__construct(['expr' => $expr], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/DoNode.php b/system/libs/Twig/Node/DoNode.php index 80c4cea79e..d74804c5d0 100644 --- a/system/libs/Twig/Node/DoNode.php +++ b/system/libs/Twig/Node/DoNode.php @@ -21,7 +21,7 @@ */ class DoNode extends Node { - public function __construct(AbstractExpression $expr, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, int $lineno, string $tag = null) { parent::__construct(['expr' => $expr], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/EmbedNode.php b/system/libs/Twig/Node/EmbedNode.php index 05051ecec8..016c17f878 100644 --- a/system/libs/Twig/Node/EmbedNode.php +++ b/system/libs/Twig/Node/EmbedNode.php @@ -23,13 +23,11 @@ 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($name, $index, AbstractExpression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) + 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); - // to be removed in 2.0, used name instead - $this->setAttribute('filename', $name); $this->setAttribute('index', $index); } diff --git a/system/libs/Twig/Node/Expression/ArrayExpression.php b/system/libs/Twig/Node/Expression/ArrayExpression.php index cd63f934e4..917675d91e 100644 --- a/system/libs/Twig/Node/Expression/ArrayExpression.php +++ b/system/libs/Twig/Node/Expression/ArrayExpression.php @@ -15,9 +15,9 @@ class ArrayExpression extends AbstractExpression { - protected $index; + private $index; - public function __construct(array $elements, $lineno) + public function __construct(array $elements, int $lineno) { parent::__construct($elements, [], $lineno); diff --git a/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php b/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php index 36b77da86f..b5b720eddf 100644 --- a/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php +++ b/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php @@ -44,7 +44,7 @@ public function compile(Compiler $compiler) ; } $compiler - ->raw(') use ($context) { ') + ->raw(') use ($context, $macros) { ') ; foreach ($this->getNode('names') as $name) { $compiler diff --git a/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php b/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php index 0600aeedbb..67c388aea1 100644 --- a/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php +++ b/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php @@ -14,10 +14,11 @@ use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; +use Twig\Node\Node; abstract class AbstractBinary extends AbstractExpression { - public function __construct(\Twig_NodeInterface $left, \Twig_NodeInterface $right, $lineno) + public function __construct(Node $left, Node $right, int $lineno) { parent::__construct(['left' => $left, 'right' => $right], [], $lineno); } diff --git a/system/libs/Twig/Node/Expression/Binary/PowerBinary.php b/system/libs/Twig/Node/Expression/Binary/PowerBinary.php index 10a8d94cfe..32d0214fd7 100644 --- a/system/libs/Twig/Node/Expression/Binary/PowerBinary.php +++ b/system/libs/Twig/Node/Expression/Binary/PowerBinary.php @@ -15,21 +15,6 @@ class PowerBinary extends AbstractBinary { - public function compile(Compiler $compiler) - { - if (\PHP_VERSION_ID >= 50600) { - return parent::compile($compiler); - } - - $compiler - ->raw('pow(') - ->subcompile($this->getNode('left')) - ->raw(', ') - ->subcompile($this->getNode('right')) - ->raw(')') - ; - } - public function operator(Compiler $compiler) { return $compiler->raw('**'); diff --git a/system/libs/Twig/Node/Expression/Binary/SpaceshipBinary.php b/system/libs/Twig/Node/Expression/Binary/SpaceshipBinary.php new file mode 100644 index 0000000000..5245e4051c --- /dev/null +++ b/system/libs/Twig/Node/Expression/Binary/SpaceshipBinary.php @@ -0,0 +1,22 @@ +raw('<=>'); + } +} diff --git a/system/libs/Twig/Node/Expression/BlockReferenceExpression.php b/system/libs/Twig/Node/Expression/BlockReferenceExpression.php index 0a56849c7a..8a6db4d002 100644 --- a/system/libs/Twig/Node/Expression/BlockReferenceExpression.php +++ b/system/libs/Twig/Node/Expression/BlockReferenceExpression.php @@ -22,17 +22,8 @@ */ class BlockReferenceExpression extends AbstractExpression { - /** - * @param Node|null $template - */ - public function __construct(\Twig_NodeInterface $name, $template = null, $lineno, $tag = null) + public function __construct(Node $name, ?Node $template, int $lineno, string $tag = null) { - if (\is_bool($template)) { - @trigger_error(sprintf('The %s method "$asString" argument is deprecated since version 1.28 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); - - $template = null; - } - $nodes = ['name' => $name]; if (null !== $template) { $nodes['template'] = $template; @@ -58,7 +49,7 @@ public function compile(Compiler $compiler) } } - private function compileTemplateCall(Compiler $compiler, $method) + private function compileTemplateCall(Compiler $compiler, string $method): Compiler { if (!$this->hasNode('template')) { $compiler->write('$this'); @@ -75,12 +66,11 @@ private function compileTemplateCall(Compiler $compiler, $method) } $compiler->raw(sprintf('->%s', $method)); - $this->compileBlockArguments($compiler); - return $compiler; + return $this->compileBlockArguments($compiler); } - private function compileBlockArguments(Compiler $compiler) + private function compileBlockArguments(Compiler $compiler): Compiler { $compiler ->raw('(') diff --git a/system/libs/Twig/Node/Expression/CallExpression.php b/system/libs/Twig/Node/Expression/CallExpression.php index d202a73953..aeb38c42f8 100644 --- a/system/libs/Twig/Node/Expression/CallExpression.php +++ b/system/libs/Twig/Node/Expression/CallExpression.php @@ -22,37 +22,37 @@ abstract class CallExpression extends AbstractExpression protected function compileCallable(Compiler $compiler) { - $closingParenthesis = false; - $isArray = false; - if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) { - if (\is_string($callable) && false === strpos($callable, '::')) { + $callable = $this->getAttribute('callable'); + + if (\is_string($callable) && false === strpos($callable, '::')) { + $compiler->raw($callable); + } else { + [$r, $callable] = $this->reflectCallable($callable); + + if (\is_string($callable)) { $compiler->raw($callable); - } else { - list($r, $callable) = $this->reflectCallable($callable); - if ($r instanceof \ReflectionMethod && \is_string($callable[0])) { - if ($r->isStatic()) { - $compiler->raw(sprintf('%s::%s', $callable[0], $callable[1])); - } else { - $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1])); - } - } elseif ($r instanceof \ReflectionMethod && $callable[0] instanceof ExtensionInterface) { - $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', \get_class($callable[0]), $callable[1])); + } elseif (\is_array($callable) && \is_string($callable[0])) { + if (!$r instanceof \ReflectionMethod || $r->isStatic()) { + $compiler->raw(sprintf('%s::%s', $callable[0], $callable[1])); } else { - $type = ucfirst($this->getAttribute('type')); - $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), ', $type, $this->getAttribute('name'))); - $closingParenthesis = true; - $isArray = true; + $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1])); } + } elseif (\is_array($callable) && $callable[0] instanceof ExtensionInterface) { + $class = \get_class($callable[0]); + if (!$compiler->getEnvironment()->hasExtension($class)) { + // Compile a non-optimized call to trigger a \Twig\Error\RuntimeError, which cannot be a compile-time error + $compiler->raw(sprintf('$this->env->getExtension(\'%s\')', $class)); + } else { + $compiler->raw(sprintf('$this->extensions[\'%s\']', ltrim($class, '\\'))); + } + + $compiler->raw(sprintf('->%s', $callable[1])); + } else { + $compiler->raw(sprintf('$this->env->get%s(\'%s\')->getCallable()', ucfirst($this->getAttribute('type')), $this->getAttribute('name'))); } - } else { - $compiler->raw($this->getAttribute('thing')->compile()); } - $this->compileArguments($compiler, $isArray); - - if ($closingParenthesis) { - $compiler->raw(')'); - } + $this->compileArguments($compiler); } protected function compileArguments(Compiler $compiler, $isArray = false) @@ -93,10 +93,8 @@ protected function compileArguments(Compiler $compiler, $isArray = false) } if ($this->hasNode('arguments')) { - $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; - + $callable = $this->getAttribute('callable'); $arguments = $this->getArguments($callable, $this->getNode('arguments')); - foreach ($arguments as $node) { if (!$first) { $compiler->raw(', '); @@ -142,14 +140,23 @@ protected function getArguments($callable, $arguments) throw new \LogicException($message); } - $callableParameters = $this->getCallableParameters($callable, $isVariadic); + list($callableParameters, $isPhpVariadic) = $this->getCallableParameters($callable, $isVariadic); $arguments = []; $names = []; $missingArguments = []; $optionalArguments = []; $pos = 0; foreach ($callableParameters as $callableParameter) { - $names[] = $name = $this->normalizeName($callableParameter->name); + $name = $this->normalizeName($callableParameter->name); + if (\PHP_VERSION_ID >= 80000 && 'range' === $callable) { + if ('start' === $name) { + $name = 'low'; + } elseif ('end' === $name) { + $name = 'high'; + } + } + + $names[] = $name; if (\array_key_exists($name, $parameters)) { if (\array_key_exists($pos, $parameters)) { @@ -187,7 +194,7 @@ protected function getArguments($callable, $arguments) } if ($isVariadic) { - $arbitraryArguments = new ArrayExpression([], -1); + $arbitraryArguments = $isPhpVariadic ? new VariadicExpression([], -1) : new ArrayExpression([], -1); foreach ($parameters as $key => $value) { if (\is_int($key)) { $arbitraryArguments->addElement($value); @@ -230,12 +237,9 @@ protected function normalizeName($name) return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], $name)); } - private function getCallableParameters($callable, $isVariadic) + private function getCallableParameters($callable, bool $isVariadic): array { - list($r) = $this->reflectCallable($callable); - if (null === $r) { - return []; - } + [$r, , $callableName] = $this->reflectCallable($callable); $parameters = $r->getParameters(); if ($this->hasNode('node')) { @@ -252,21 +256,21 @@ private function getCallableParameters($callable, $isVariadic) array_shift($parameters); } } + $isPhpVariadic = false; if ($isVariadic) { $argument = end($parameters); - if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && [] === $argument->getDefaultValue()) { + $isArray = $argument && $argument->hasType() && 'array' === $argument->getType()->getName(); + if ($isArray && $argument->isDefaultValueAvailable() && [] === $argument->getDefaultValue()) { array_pop($parameters); + } elseif ($argument && $argument->isVariadic()) { + array_pop($parameters); + $isPhpVariadic = true; } else { - $callableName = $r->name; - if ($r instanceof \ReflectionMethod) { - $callableName = $r->getDeclaringClass()->name.'::'.$callableName; - } - throw new \LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = []".', $callableName, $this->getAttribute('type'), $this->getAttribute('name'))); } } - return $parameters; + return [$parameters, $isPhpVariadic]; } private function reflectCallable($callable) @@ -275,30 +279,44 @@ private function reflectCallable($callable) return $this->reflector; } - if (\is_array($callable)) { - if (!method_exists($callable[0], $callable[1])) { - // __call() - return [null, []]; - } + if (\is_string($callable) && false !== $pos = strpos($callable, '::')) { + $callable = [substr($callable, 0, $pos), substr($callable, 2 + $pos)]; + } + + if (\is_array($callable) && method_exists($callable[0], $callable[1])) { $r = new \ReflectionMethod($callable[0], $callable[1]); - } elseif (\is_object($callable) && !$callable instanceof \Closure) { - $r = new \ReflectionObject($callable); - $r = $r->getMethod('__invoke'); - $callable = [$callable, '__invoke']; - } elseif (\is_string($callable) && false !== $pos = strpos($callable, '::')) { - $class = substr($callable, 0, $pos); - $method = substr($callable, $pos + 2); - if (!method_exists($class, $method)) { - // __staticCall() - return [null, []]; - } - $r = new \ReflectionMethod($callable); - $callable = [$class, $method]; + + return $this->reflector = [$r, $callable, $r->class.'::'.$r->name]; + } + + $checkVisibility = $callable instanceof \Closure; + try { + $closure = \Closure::fromCallable($callable); + } catch (\TypeError $e) { + throw new \LogicException(sprintf('Callback for %s "%s" is not callable in the current scope.', $this->getAttribute('type'), $this->getAttribute('name')), 0, $e); + } + $r = new \ReflectionFunction($closure); + + if (false !== strpos($r->name, '{closure}')) { + return $this->reflector = [$r, $callable, 'Closure']; + } + + if ($object = $r->getClosureThis()) { + $callable = [$object, $r->name]; + $callableName = (\function_exists('get_debug_type') ? get_debug_type($object) : \get_class($object)).'::'.$r->name; + } elseif (\PHP_VERSION_ID >= 80111 && $class = $r->getClosureCalledClass()) { + $callableName = $class->name.'::'.$r->name; + } elseif (\PHP_VERSION_ID < 80111 && $class = $r->getClosureScopeClass()) { + $callableName = (\is_array($callable) ? $callable[0] : $class->name).'::'.$r->name; } else { - $r = new \ReflectionFunction($callable); + $callable = $callableName = $r->name; + } + + if ($checkVisibility && \is_array($callable) && method_exists(...$callable) && !(new \ReflectionMethod(...$callable))->isPublic()) { + $callable = $r->getClosure(); } - return $this->reflector = [$r, $callable]; + return $this->reflector = [$r, $callable, $callableName]; } } diff --git a/system/libs/Twig/Node/Expression/ConditionalExpression.php b/system/libs/Twig/Node/Expression/ConditionalExpression.php index b611218d31..8c367d3579 100644 --- a/system/libs/Twig/Node/Expression/ConditionalExpression.php +++ b/system/libs/Twig/Node/Expression/ConditionalExpression.php @@ -16,7 +16,7 @@ class ConditionalExpression extends AbstractExpression { - public function __construct(AbstractExpression $expr1, AbstractExpression $expr2, AbstractExpression $expr3, $lineno) + public function __construct(AbstractExpression $expr1, AbstractExpression $expr2, AbstractExpression $expr3, int $lineno) { parent::__construct(['expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3], [], $lineno); } diff --git a/system/libs/Twig/Node/Expression/ConstantExpression.php b/system/libs/Twig/Node/Expression/ConstantExpression.php index fd58264dca..46e0ac39c6 100644 --- a/system/libs/Twig/Node/Expression/ConstantExpression.php +++ b/system/libs/Twig/Node/Expression/ConstantExpression.php @@ -16,7 +16,7 @@ class ConstantExpression extends AbstractExpression { - public function __construct($value, $lineno) + public function __construct($value, int $lineno) { parent::__construct([], ['value' => $value], $lineno); } diff --git a/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php b/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php index 7c5e2d20aa..0dacae839f 100644 --- a/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php +++ b/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php @@ -29,7 +29,7 @@ */ class DefaultFilter extends FilterExpression { - public function __construct(\Twig_NodeInterface $node, ConstantExpression $filterName, \Twig_NodeInterface $arguments, $lineno, $tag = null) + public function __construct(Node $node, ConstantExpression $filterName, Node $arguments, int $lineno, string $tag = null) { $default = new FilterExpression($node, new ConstantExpression('default', $node->getTemplateLine()), $arguments, $node->getTemplateLine()); diff --git a/system/libs/Twig/Node/Expression/FilterExpression.php b/system/libs/Twig/Node/Expression/FilterExpression.php index 6131c2fd40..41b07341c5 100644 --- a/system/libs/Twig/Node/Expression/FilterExpression.php +++ b/system/libs/Twig/Node/Expression/FilterExpression.php @@ -13,11 +13,11 @@ namespace Twig\Node\Expression; use Twig\Compiler; -use Twig\TwigFilter; +use Twig\Node\Node; class FilterExpression extends CallExpression { - public function __construct(\Twig_NodeInterface $node, ConstantExpression $filterName, \Twig_NodeInterface $arguments, $lineno, $tag = null) + public function __construct(Node $node, ConstantExpression $filterName, Node $arguments, int $lineno, string $tag = null) { parent::__construct(['node' => $node, 'filter' => $filterName, 'arguments' => $arguments], [], $lineno, $tag); } @@ -29,16 +29,11 @@ public function compile(Compiler $compiler) $this->setAttribute('name', $name); $this->setAttribute('type', 'filter'); - $this->setAttribute('thing', $filter); $this->setAttribute('needs_environment', $filter->needsEnvironment()); $this->setAttribute('needs_context', $filter->needsContext()); $this->setAttribute('arguments', $filter->getArguments()); - if ($filter instanceof \Twig_FilterCallableInterface || $filter instanceof TwigFilter) { - $this->setAttribute('callable', $filter->getCallable()); - } - if ($filter instanceof TwigFilter) { - $this->setAttribute('is_variadic', $filter->isVariadic()); - } + $this->setAttribute('callable', $filter->getCallable()); + $this->setAttribute('is_variadic', $filter->isVariadic()); $this->compileCallable($compiler); } diff --git a/system/libs/Twig/Node/Expression/FunctionExpression.php b/system/libs/Twig/Node/Expression/FunctionExpression.php index cf2c72b635..429dbb9245 100644 --- a/system/libs/Twig/Node/Expression/FunctionExpression.php +++ b/system/libs/Twig/Node/Expression/FunctionExpression.php @@ -12,11 +12,11 @@ namespace Twig\Node\Expression; use Twig\Compiler; -use Twig\TwigFunction; +use Twig\Node\Node; class FunctionExpression extends CallExpression { - public function __construct($name, \Twig_NodeInterface $arguments, $lineno) + public function __construct(string $name, Node $arguments, int $lineno) { parent::__construct(['arguments' => $arguments], ['name' => $name, 'is_defined_test' => false], $lineno); } @@ -28,21 +28,15 @@ public function compile(Compiler $compiler) $this->setAttribute('name', $name); $this->setAttribute('type', 'function'); - $this->setAttribute('thing', $function); $this->setAttribute('needs_environment', $function->needsEnvironment()); $this->setAttribute('needs_context', $function->needsContext()); $this->setAttribute('arguments', $function->getArguments()); - if ($function instanceof \Twig_FunctionCallableInterface || $function instanceof TwigFunction) { - $callable = $function->getCallable(); - if ('constant' === $name && $this->getAttribute('is_defined_test')) { - $callable = 'twig_constant_is_defined'; - } - - $this->setAttribute('callable', $callable); - } - if ($function instanceof TwigFunction) { - $this->setAttribute('is_variadic', $function->isVariadic()); + $callable = $function->getCallable(); + if ('constant' === $name && $this->getAttribute('is_defined_test')) { + $callable = 'twig_constant_is_defined'; } + $this->setAttribute('callable', $callable); + $this->setAttribute('is_variadic', $function->isVariadic()); $this->compileCallable($compiler); } diff --git a/system/libs/Twig/Node/Expression/GetAttrExpression.php b/system/libs/Twig/Node/Expression/GetAttrExpression.php index b790bf7af7..de76845a74 100644 --- a/system/libs/Twig/Node/Expression/GetAttrExpression.php +++ b/system/libs/Twig/Node/Expression/GetAttrExpression.php @@ -13,67 +13,76 @@ namespace Twig\Node\Expression; use Twig\Compiler; +use Twig\Extension\SandboxExtension; use Twig\Template; class GetAttrExpression extends AbstractExpression { - public function __construct(AbstractExpression $node, AbstractExpression $attribute, AbstractExpression $arguments = null, $type, $lineno) + public function __construct(AbstractExpression $node, AbstractExpression $attribute, ?AbstractExpression $arguments, string $type, int $lineno) { $nodes = ['node' => $node, 'attribute' => $attribute]; if (null !== $arguments) { $nodes['arguments'] = $arguments; } - parent::__construct($nodes, ['type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false], $lineno); + parent::__construct($nodes, ['type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'optimizable' => true], $lineno); } public function compile(Compiler $compiler) { - if ($this->getAttribute('disable_c_ext')) { - @trigger_error(sprintf('Using the "disable_c_ext" attribute on %s is deprecated since version 1.30 and will be removed in 2.0.', __CLASS__), E_USER_DEPRECATED); + $env = $compiler->getEnvironment(); + + // optimize array calls + if ( + $this->getAttribute('optimizable') + && (!$env->isStrictVariables() || $this->getAttribute('ignore_strict_check')) + && !$this->getAttribute('is_defined_test') + && Template::ARRAY_CALL === $this->getAttribute('type') + ) { + $var = '$'.$compiler->getVarName(); + $compiler + ->raw('(('.$var.' = ') + ->subcompile($this->getNode('node')) + ->raw(') && is_array(') + ->raw($var) + ->raw(') || ') + ->raw($var) + ->raw(' instanceof ArrayAccess ? (') + ->raw($var) + ->raw('[') + ->subcompile($this->getNode('attribute')) + ->raw('] ?? null) : null)') + ; + + return; } - if (\function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) { - $compiler->raw('twig_template_get_attributes($this, '); - } else { - $compiler->raw('$this->getAttribute('); - } + $compiler->raw('twig_get_attribute($this->env, $this->source, '); if ($this->getAttribute('ignore_strict_check')) { $this->getNode('node')->setAttribute('ignore_strict_check', true); } - $compiler->subcompile($this->getNode('node')); - - $compiler->raw(', ')->subcompile($this->getNode('attribute')); - - // only generate optional arguments when needed (to make generated code more readable) - $needFourth = $this->getAttribute('ignore_strict_check'); - $needThird = $needFourth || $this->getAttribute('is_defined_test'); - $needSecond = $needThird || Template::ANY_CALL !== $this->getAttribute('type'); - $needFirst = $needSecond || $this->hasNode('arguments'); - - if ($needFirst) { - if ($this->hasNode('arguments')) { - $compiler->raw(', ')->subcompile($this->getNode('arguments')); - } else { - $compiler->raw(', []'); - } - } + $compiler + ->subcompile($this->getNode('node')) + ->raw(', ') + ->subcompile($this->getNode('attribute')) + ; - if ($needSecond) { - $compiler->raw(', ')->repr($this->getAttribute('type')); - } - - if ($needThird) { - $compiler->raw(', ')->repr($this->getAttribute('is_defined_test')); - } - - if ($needFourth) { - $compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check')); + if ($this->hasNode('arguments')) { + $compiler->raw(', ')->subcompile($this->getNode('arguments')); + } else { + $compiler->raw(', []'); } - $compiler->raw(')'); + $compiler->raw(', ') + ->repr($this->getAttribute('type')) + ->raw(', ')->repr($this->getAttribute('is_defined_test')) + ->raw(', ')->repr($this->getAttribute('ignore_strict_check')) + ->raw(', ')->repr($env->hasExtension(SandboxExtension::class)) + ->raw(', ')->repr($this->getNode('node')->getTemplateLine()) + ->raw(')') + ; } } diff --git a/system/libs/Twig/Node/Expression/MethodCallExpression.php b/system/libs/Twig/Node/Expression/MethodCallExpression.php index f6311249de..d5287f85f3 100644 --- a/system/libs/Twig/Node/Expression/MethodCallExpression.php +++ b/system/libs/Twig/Node/Expression/MethodCallExpression.php @@ -15,9 +15,9 @@ class MethodCallExpression extends AbstractExpression { - public function __construct(AbstractExpression $node, $method, ArrayExpression $arguments, $lineno) + public function __construct(AbstractExpression $node, string $method, ArrayExpression $arguments, int $lineno) { - parent::__construct(['node' => $node, 'arguments' => $arguments], ['method' => $method, 'safe' => false], $lineno); + parent::__construct(['node' => $node, 'arguments' => $arguments], ['method' => $method, 'safe' => false, 'is_defined_test' => false], $lineno); if ($node instanceof NameExpression) { $node->setAttribute('always_defined', true); @@ -26,11 +26,24 @@ public function __construct(AbstractExpression $node, $method, ArrayExpression $ public function compile(Compiler $compiler) { + if ($this->getAttribute('is_defined_test')) { + $compiler + ->raw('method_exists($macros[') + ->repr($this->getNode('node')->getAttribute('name')) + ->raw('], ') + ->repr($this->getAttribute('method')) + ->raw(')') + ; + + return; + } + $compiler - ->subcompile($this->getNode('node')) - ->raw('->') - ->raw($this->getAttribute('method')) - ->raw('(') + ->raw('twig_call_macro($macros[') + ->repr($this->getNode('node')->getAttribute('name')) + ->raw('], ') + ->repr($this->getAttribute('method')) + ->raw(', [') ; $first = true; foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { @@ -41,7 +54,10 @@ public function compile(Compiler $compiler) $compiler->subcompile($pair['value']); } - $compiler->raw(')'); + $compiler + ->raw('], ') + ->repr($this->getTemplateLine()) + ->raw(', $context, $this->getSourceContext())'); } } diff --git a/system/libs/Twig/Node/Expression/NameExpression.php b/system/libs/Twig/Node/Expression/NameExpression.php index d3f7d107fb..f8426bcc1f 100644 --- a/system/libs/Twig/Node/Expression/NameExpression.php +++ b/system/libs/Twig/Node/Expression/NameExpression.php @@ -16,13 +16,13 @@ class NameExpression extends AbstractExpression { - protected $specialVars = [ - '_self' => '$this', + private $specialVars = [ + '_self' => '$this->getTemplateName()', '_context' => '$context', '_charset' => '$this->env->getCharset()', ]; - public function __construct($name, $lineno) + public function __construct(string $name, int $lineno) { parent::__construct([], ['name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false], $lineno); } @@ -36,7 +36,7 @@ public function compile(Compiler $compiler) if ($this->getAttribute('is_defined_test')) { if ($this->isSpecial()) { $compiler->repr(true); - } elseif (\PHP_VERSION_ID >= 700400) { + } elseif (\PHP_VERSION_ID >= 70400) { $compiler ->raw('array_key_exists(') ->string($name) @@ -60,45 +60,25 @@ public function compile(Compiler $compiler) ->raw(']') ; } else { - if (\PHP_VERSION_ID >= 70000) { - // use PHP 7 null coalescing operator + if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { $compiler ->raw('($context[') ->string($name) - ->raw('] ?? ') + ->raw('] ?? null)') ; - - if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { - $compiler->raw('null)'); - } else { - $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); - } - } elseif (\PHP_VERSION_ID >= 50400) { - // PHP 5.4 ternary operator performance was optimized + } else { $compiler ->raw('(isset($context[') ->string($name) - ->raw(']) ? $context[') + ->raw(']) || array_key_exists(') ->string($name) - ->raw('] : ') - ; - - if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { - $compiler->raw('null)'); - } else { - $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); - } - } else { - $compiler - ->raw('$this->getContext($context, ') + ->raw(', $context) ? $context[') ->string($name) - ; - - if ($this->getAttribute('ignore_strict_check')) { - $compiler->raw(', true'); - } - - $compiler + ->raw('] : (function () { throw new RuntimeError(\'Variable ') + ->string($name) + ->raw(' does not exist.\', ') + ->repr($this->lineno) + ->raw(', $this->source); })()') ->raw(')') ; } diff --git a/system/libs/Twig/Node/Expression/NullCoalesceExpression.php b/system/libs/Twig/Node/Expression/NullCoalesceExpression.php index 917d31a3b2..de03ff2202 100644 --- a/system/libs/Twig/Node/Expression/NullCoalesceExpression.php +++ b/system/libs/Twig/Node/Expression/NullCoalesceExpression.php @@ -20,7 +20,7 @@ class NullCoalesceExpression extends ConditionalExpression { - public function __construct(\Twig_NodeInterface $left, \Twig_NodeInterface $right, $lineno) + public function __construct(Node $left, Node $right, int $lineno) { $test = new DefinedTest(clone $left, 'defined', new Node(), $left->getTemplateLine()); // for "block()", we don't need the null test as the return value is always a string @@ -44,7 +44,7 @@ public function compile(Compiler $compiler) * cases might be implemented as an optimizer node visitor, but has not been done * as benefits are probably not worth the added complexity. */ - if (\PHP_VERSION_ID >= 70000 && $this->getNode('expr2') instanceof NameExpression) { + if ($this->getNode('expr2') instanceof NameExpression) { $this->getNode('expr2')->setAttribute('always_defined', true); $compiler ->raw('((') diff --git a/system/libs/Twig/Node/Expression/ParentExpression.php b/system/libs/Twig/Node/Expression/ParentExpression.php index 1247283036..294ab398ec 100644 --- a/system/libs/Twig/Node/Expression/ParentExpression.php +++ b/system/libs/Twig/Node/Expression/ParentExpression.php @@ -21,7 +21,7 @@ */ class ParentExpression extends AbstractExpression { - public function __construct($name, $lineno, $tag = null) + public function __construct(string $name, int $lineno, string $tag = null) { parent::__construct([], ['output' => false, 'name' => $name], $lineno, $tag); } diff --git a/system/libs/Twig/Node/Expression/TempNameExpression.php b/system/libs/Twig/Node/Expression/TempNameExpression.php index ce0a158981..e7a1a890d2 100644 --- a/system/libs/Twig/Node/Expression/TempNameExpression.php +++ b/system/libs/Twig/Node/Expression/TempNameExpression.php @@ -15,7 +15,7 @@ class TempNameExpression extends AbstractExpression { - public function __construct($name, $lineno) + public function __construct(string $name, int $lineno) { parent::__construct([], ['name' => $name], $lineno); } diff --git a/system/libs/Twig/Node/Expression/Test/DefinedTest.php b/system/libs/Twig/Node/Expression/Test/DefinedTest.php index 2222e11cfd..d748e86f0d 100644 --- a/system/libs/Twig/Node/Expression/Test/DefinedTest.php +++ b/system/libs/Twig/Node/Expression/Test/DefinedTest.php @@ -18,8 +18,10 @@ use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FunctionExpression; use Twig\Node\Expression\GetAttrExpression; +use Twig\Node\Expression\MethodCallExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\TestExpression; +use Twig\Node\Node; /** * Checks if a variable is defined in the current context. @@ -33,7 +35,7 @@ */ class DefinedTest extends TestExpression { - public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterface $arguments = null, $lineno) + public function __construct(Node $node, string $name, ?Node $arguments, int $lineno) { if ($node instanceof NameExpression) { $node->setAttribute('is_defined_test', true); @@ -46,6 +48,8 @@ public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterfac $node->setAttribute('is_defined_test', true); } elseif ($node instanceof ConstantExpression || $node instanceof ArrayExpression) { $node = new ConstantExpression(true, $node->getTemplateLine()); + } elseif ($node instanceof MethodCallExpression) { + $node->setAttribute('is_defined_test', true); } else { throw new SyntaxError('The "defined" test only works with simple variables.', $lineno); } @@ -53,8 +57,9 @@ public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterfac parent::__construct($node, $name, $arguments, $lineno); } - protected function changeIgnoreStrictCheck(GetAttrExpression $node) + private function changeIgnoreStrictCheck(GetAttrExpression $node) { + $node->setAttribute('optimizable', false); $node->setAttribute('ignore_strict_check', true); if ($node->getNode('node') instanceof GetAttrExpression) { diff --git a/system/libs/Twig/Node/Expression/Test/OddTest.php b/system/libs/Twig/Node/Expression/Test/OddTest.php index 2dc693a9ae..189e51e761 100644 --- a/system/libs/Twig/Node/Expression/Test/OddTest.php +++ b/system/libs/Twig/Node/Expression/Test/OddTest.php @@ -28,7 +28,7 @@ public function compile(Compiler $compiler) $compiler ->raw('(') ->subcompile($this->getNode('node')) - ->raw(' % 2 == 1') + ->raw(' % 2 != 0') ->raw(')') ; } diff --git a/system/libs/Twig/Node/Expression/TestExpression.php b/system/libs/Twig/Node/Expression/TestExpression.php index 8fc31d3aad..24aa3903c3 100644 --- a/system/libs/Twig/Node/Expression/TestExpression.php +++ b/system/libs/Twig/Node/Expression/TestExpression.php @@ -12,11 +12,11 @@ namespace Twig\Node\Expression; use Twig\Compiler; -use Twig\TwigTest; +use Twig\Node\Node; class TestExpression extends CallExpression { - public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterface $arguments = null, $lineno) + public function __construct(Node $node, string $name, ?Node $arguments, int $lineno) { $nodes = ['node' => $node]; if (null !== $arguments) { @@ -33,16 +33,9 @@ public function compile(Compiler $compiler) $this->setAttribute('name', $name); $this->setAttribute('type', 'test'); - $this->setAttribute('thing', $test); - if ($test instanceof TwigTest) { - $this->setAttribute('arguments', $test->getArguments()); - } - if ($test instanceof \Twig_TestCallableInterface || $test instanceof TwigTest) { - $this->setAttribute('callable', $test->getCallable()); - } - if ($test instanceof TwigTest) { - $this->setAttribute('is_variadic', $test->isVariadic()); - } + $this->setAttribute('arguments', $test->getArguments()); + $this->setAttribute('callable', $test->getCallable()); + $this->setAttribute('is_variadic', $test->isVariadic()); $this->compileCallable($compiler); } diff --git a/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php b/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php index 415c3d407e..4896280f10 100644 --- a/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php +++ b/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php @@ -14,10 +14,11 @@ use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; +use Twig\Node\Node; abstract class AbstractUnary extends AbstractExpression { - public function __construct(\Twig_NodeInterface $node, $lineno) + public function __construct(Node $node, int $lineno) { parent::__construct(['node' => $node], [], $lineno); } diff --git a/system/libs/Twig/Node/Expression/VariadicExpression.php b/system/libs/Twig/Node/Expression/VariadicExpression.php new file mode 100644 index 0000000000..3351e1a676 --- /dev/null +++ b/system/libs/Twig/Node/Expression/VariadicExpression.php @@ -0,0 +1,24 @@ +raw('...'); + + parent::compile($compiler); + } +} diff --git a/system/libs/Twig/Node/FlushNode.php b/system/libs/Twig/Node/FlushNode.php index 6cbc489a62..b88f3409b9 100644 --- a/system/libs/Twig/Node/FlushNode.php +++ b/system/libs/Twig/Node/FlushNode.php @@ -20,7 +20,7 @@ */ class FlushNode extends Node { - public function __construct($lineno, $tag) + public function __construct(int $lineno, string $tag) { parent::__construct([], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/ForLoopNode.php b/system/libs/Twig/Node/ForLoopNode.php index 3902093556..42aedd7ba6 100644 --- a/system/libs/Twig/Node/ForLoopNode.php +++ b/system/libs/Twig/Node/ForLoopNode.php @@ -20,7 +20,7 @@ */ class ForLoopNode extends Node { - public function __construct($lineno, $tag = null) + public function __construct(int $lineno, string $tag = null) { parent::__construct([], ['with_loop' => false, 'ifexpr' => false, 'else' => false], $lineno, $tag); } diff --git a/system/libs/Twig/Node/ForNode.php b/system/libs/Twig/Node/ForNode.php index 49409a39b1..d5c34e617c 100644 --- a/system/libs/Twig/Node/ForNode.php +++ b/system/libs/Twig/Node/ForNode.php @@ -23,9 +23,9 @@ */ class ForNode extends Node { - protected $loop; + private $loop; - public function __construct(AssignNameExpression $keyTarget, AssignNameExpression $valueTarget, AbstractExpression $seq, AbstractExpression $ifexpr = null, \Twig_NodeInterface $body, \Twig_NodeInterface $else = null, $lineno, $tag = null) + public function __construct(AssignNameExpression $keyTarget, AssignNameExpression $valueTarget, AbstractExpression $seq, ?AbstractExpression $ifexpr, Node $body, ?Node $else, int $lineno, string $tag = null) { $body = new Node([$body, $this->loop = new ForLoopNode($lineno, $tag)]); diff --git a/system/libs/Twig/Node/IfNode.php b/system/libs/Twig/Node/IfNode.php index 4836d91f08..e74ca523b0 100644 --- a/system/libs/Twig/Node/IfNode.php +++ b/system/libs/Twig/Node/IfNode.php @@ -21,7 +21,7 @@ */ class IfNode extends Node { - public function __construct(\Twig_NodeInterface $tests, \Twig_NodeInterface $else = null, $lineno, $tag = null) + public function __construct(Node $tests, ?Node $else, int $lineno, string $tag = null) { $nodes = ['tests' => $tests]; if (null !== $else) { @@ -50,8 +50,11 @@ public function compile(Compiler $compiler) ->subcompile($this->getNode('tests')->getNode($i)) ->raw(") {\n") ->indent() - ->subcompile($this->getNode('tests')->getNode($i + 1)) ; + // The node might not exists if the content is empty + if ($this->getNode('tests')->hasNode($i + 1)) { + $compiler->subcompile($this->getNode('tests')->getNode($i + 1)); + } } if ($this->hasNode('else')) { diff --git a/system/libs/Twig/Node/ImportNode.php b/system/libs/Twig/Node/ImportNode.php index 236db8900e..b661f4313a 100644 --- a/system/libs/Twig/Node/ImportNode.php +++ b/system/libs/Twig/Node/ImportNode.php @@ -22,20 +22,28 @@ */ class ImportNode extends Node { - public function __construct(AbstractExpression $expr, AbstractExpression $var, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, AbstractExpression $var, int $lineno, string $tag = null, bool $global = true) { - parent::__construct(['expr' => $expr, 'var' => $var], [], $lineno, $tag); + parent::__construct(['expr' => $expr, 'var' => $var], ['global' => $global], $lineno, $tag); } public function compile(Compiler $compiler) { $compiler ->addDebugInfo($this) - ->write('') - ->subcompile($this->getNode('var')) - ->raw(' = ') + ->write('$macros[') + ->repr($this->getNode('var')->getAttribute('name')) + ->raw('] = ') ; + if ($this->getAttribute('global')) { + $compiler + ->raw('$this->macros[') + ->repr($this->getNode('var')->getAttribute('name')) + ->raw('] = ') + ; + } + if ($this->getNode('expr') instanceof NameExpression && '_self' === $this->getNode('expr')->getAttribute('name')) { $compiler->raw('$this'); } else { diff --git a/system/libs/Twig/Node/IncludeNode.php b/system/libs/Twig/Node/IncludeNode.php index 544db81eaf..3bc91295b0 100644 --- a/system/libs/Twig/Node/IncludeNode.php +++ b/system/libs/Twig/Node/IncludeNode.php @@ -22,7 +22,7 @@ */ class IncludeNode extends Node implements NodeOutputInterface { - public function __construct(AbstractExpression $expr, AbstractExpression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno, string $tag = null) { $nodes = ['expr' => $expr]; if (null !== $variables) { diff --git a/system/libs/Twig/Node/MacroNode.php b/system/libs/Twig/Node/MacroNode.php index 6eb67955f4..ca4686ce95 100644 --- a/system/libs/Twig/Node/MacroNode.php +++ b/system/libs/Twig/Node/MacroNode.php @@ -21,9 +21,9 @@ */ class MacroNode extends Node { - const VARARGS_NAME = 'varargs'; + public const VARARGS_NAME = 'varargs'; - public function __construct($name, \Twig_NodeInterface $body, \Twig_NodeInterface $arguments, $lineno, $tag = null) + public function __construct(string $name, Node $body, Node $arguments, int $lineno, string $tag = null) { foreach ($arguments as $argumentName => $argument) { if (self::VARARGS_NAME === $argumentName) { @@ -38,7 +38,7 @@ public function compile(Compiler $compiler) { $compiler ->addDebugInfo($this) - ->write(sprintf('public function get%s(', $this->getAttribute('name'))) + ->write(sprintf('public function macro_%s(', $this->getAttribute('name'))) ; $count = \count($this->getNode('arguments')); @@ -54,21 +54,16 @@ public function compile(Compiler $compiler) } } - if (\PHP_VERSION_ID >= 50600) { - if ($count) { - $compiler->raw(', '); - } - - $compiler->raw('...$__varargs__'); + if ($count) { + $compiler->raw(', '); } $compiler + ->raw('...$__varargs__') ->raw(")\n") ->write("{\n") ->indent() - ; - - $compiler + ->write("\$macros = \$this->macros;\n") ->write("\$context = \$this->env->mergeGlobals([\n") ->indent() ; @@ -88,19 +83,8 @@ public function compile(Compiler $compiler) ->raw(' => ') ; - if (\PHP_VERSION_ID >= 50600) { - $compiler->raw("\$__varargs__,\n"); - } else { - $compiler - ->raw('func_num_args() > ') - ->repr($count) - ->raw(' ? array_slice(func_get_args(), ') - ->repr($count) - ->raw(") : [],\n") - ; - } - $compiler + ->raw("\$__varargs__,\n") ->outdent() ->write("]);\n\n") ->write("\$blocks = [];\n\n") @@ -114,19 +98,14 @@ public function compile(Compiler $compiler) ->write("try {\n") ->indent() ->subcompile($this->getNode('body')) + ->raw("\n") + ->write("return ('' === \$tmp = ob_get_contents()) ? '' : new Markup(\$tmp, \$this->env->getCharset());\n") ->outdent() - ->write("} catch (\Exception \$e) {\n") + ->write("} finally {\n") ->indent() - ->write("ob_end_clean();\n\n") - ->write("throw \$e;\n") + ->write("ob_end_clean();\n") ->outdent() - ->write("} catch (\Throwable \$e) {\n") - ->indent() - ->write("ob_end_clean();\n\n") - ->write("throw \$e;\n") - ->outdent() - ->write("}\n\n") - ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Markup(\$tmp, \$this->env->getCharset());\n") + ->write("}\n") ->outdent() ->write("}\n\n") ; diff --git a/system/libs/Twig/Node/ModuleNode.php b/system/libs/Twig/Node/ModuleNode.php index aab2aa33f2..29af67706d 100644 --- a/system/libs/Twig/Node/ModuleNode.php +++ b/system/libs/Twig/Node/ModuleNode.php @@ -25,16 +25,15 @@ * display_end, constructor_start, constructor_end, and class_end. * * @author Fabien Potencier + * + * @final since Twig 2.4.0 */ class ModuleNode extends Node { - public function __construct(\Twig_NodeInterface $body, AbstractExpression $parent = null, \Twig_NodeInterface $blocks, \Twig_NodeInterface $macros, \Twig_NodeInterface $traits, $embeddedTemplates, $name, $source = '') + public function __construct(Node $body, ?AbstractExpression $parent, Node $blocks, Node $macros, Node $traits, $embeddedTemplates, Source $source) { - if (!$name instanceof Source) { - @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a \Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Source($source, $name); - } else { - $source = $name; + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); } $nodes = [ @@ -54,16 +53,11 @@ public function __construct(\Twig_NodeInterface $body, AbstractExpression $paren // embedded templates are set as attributes so that they are only visited once by the visitors parent::__construct($nodes, [ - // source to be remove in 2.0 - 'source' => $source->getCode(), - // filename to be remove in 2.0 (use getTemplateName() instead) - 'filename' => $source->getName(), 'index' => null, 'embedded_templates' => $embeddedTemplates, ], 1); // populate the template name of all node children - $this->setTemplateName($source->getName()); $this->setSourceContext($source); } @@ -89,16 +83,7 @@ protected function compileTemplate(Compiler $compiler) $this->compileClassHeader($compiler); - if ( - \count($this->getNode('blocks')) - || \count($this->getNode('traits')) - || !$this->hasNode('parent') - || $this->getNode('parent') instanceof ConstantExpression - || \count($this->getNode('constructor_start')) - || \count($this->getNode('constructor_end')) - ) { - $this->compileConstructor($compiler); - } + $this->compileConstructor($compiler); $this->compileGetParent($compiler); @@ -114,8 +99,6 @@ protected function compileTemplate(Compiler $compiler) $this->compileDebugInfo($compiler); - $this->compileGetSource($compiler); - $this->compileGetSourceContext($compiler); $this->compileClassFooter($compiler); @@ -166,6 +149,7 @@ protected function compileClassHeader(Compiler $compiler) ->write("use Twig\Environment;\n") ->write("use Twig\Error\LoaderError;\n") ->write("use Twig\Error\RuntimeError;\n") + ->write("use Twig\Extension\SandboxExtension;\n") ->write("use Twig\Markup;\n") ->write("use Twig\Sandbox\SecurityError;\n") ->write("use Twig\Sandbox\SecurityNotAllowedTagError;\n") @@ -179,9 +163,11 @@ protected function compileClassHeader(Compiler $compiler) // if the template name contains */, add a blank to avoid a PHP parse error ->write('/* '.str_replace('*/', '* /', $this->getSourceContext()->getName())." */\n") ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getSourceContext()->getName(), $this->getAttribute('index'))) - ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) + ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass(false))) ->write("{\n") ->indent() + ->write("private \$source;\n") + ->write("private \$macros = [];\n\n") ; } @@ -192,6 +178,7 @@ protected function compileConstructor(Compiler $compiler) ->indent() ->subcompile($this->getNode('constructor_start')) ->write("parent::__construct(\$env);\n\n") + ->write("\$this->source = \$this->getSourceContext();\n\n") ; // parent @@ -203,18 +190,24 @@ protected function compileConstructor(Compiler $compiler) if ($countTraits) { // traits foreach ($this->getNode('traits') as $i => $trait) { - $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i)); - $node = $trait->getNode('template'); + $compiler ->addDebugInfo($node) + ->write(sprintf('$_trait_%s = $this->loadTemplate(', $i)) + ->subcompile($node) + ->raw(', ') + ->repr($node->getTemplateName()) + ->raw(', ') + ->repr($node->getTemplateLine()) + ->raw(");\n") ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i)) ->indent() ->write("throw new RuntimeError('Template \"'.") ->subcompile($trait->getNode('template')) ->raw(".'\" cannot be used as a trait.', ") ->repr($node->getTemplateLine()) - ->raw(", \$this->getSourceContext());\n") + ->raw(", \$this->source);\n") ->outdent() ->write("}\n") ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i)) @@ -226,13 +219,13 @@ protected function compileConstructor(Compiler $compiler) ->string($key) ->raw("])) {\n") ->indent() - ->write("throw new RuntimeError(sprintf('Block ") + ->write("throw new RuntimeError('Block ") ->string($key) ->raw(' is not defined in trait ') ->subcompile($trait->getNode('template')) - ->raw(".'), ") + ->raw(".', ") ->repr($node->getTemplateLine()) - ->raw(", \$this->getSourceContext());\n") + ->raw(", \$this->source);\n") ->outdent() ->write("}\n\n") @@ -318,6 +311,7 @@ protected function compileDisplay(Compiler $compiler) $compiler ->write("protected function doDisplay(array \$context, array \$blocks = [])\n", "{\n") ->indent() + ->write("\$macros = \$this->macros;\n") ->subcompile($this->getNode('display_start')) ->subcompile($this->getNode('body')) ; @@ -440,20 +434,6 @@ protected function compileDebugInfo(Compiler $compiler) ; } - protected function compileGetSource(Compiler $compiler) - { - $compiler - ->write("/** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */\n") - ->write("public function getSource()\n", "{\n") - ->indent() - ->write("@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);\n\n") - ->write('return $this->getSourceContext()->getCode();') - ->raw("\n") - ->outdent() - ->write("}\n\n") - ; - } - protected function compileGetSourceContext(Compiler $compiler) { $compiler diff --git a/system/libs/Twig/Node/Node.php b/system/libs/Twig/Node/Node.php index c890feb72d..97447525f7 100644 --- a/system/libs/Twig/Node/Node.php +++ b/system/libs/Twig/Node/Node.php @@ -20,7 +20,7 @@ * * @author Fabien Potencier */ -class Node implements \Twig_NodeInterface +class Node implements \Countable, \IteratorAggregate { protected $nodes; protected $attributes; @@ -36,11 +36,11 @@ class Node implements \Twig_NodeInterface * @param int $lineno The line number * @param string $tag The tag name associated with the Node */ - public function __construct(array $nodes = [], array $attributes = [], $lineno = 0, $tag = null) + public function __construct(array $nodes = [], array $attributes = [], int $lineno = 0, string $tag = null) { foreach ($nodes as $name => $node) { - if (!$node instanceof \Twig_NodeInterface) { - @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, \get_class($this)), E_USER_DEPRECATED); + if (!$node instanceof self) { + throw new \InvalidArgumentException(sprintf('Using "%s" for the value of node "%s" of "%s" is not supported. You must pass a \Twig\Node\Node instance.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, static::class)); } } $this->nodes = $nodes; @@ -56,7 +56,7 @@ public function __toString() $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); } - $repr = [\get_class($this).'('.implode(', ', $attributes)]; + $repr = [static::class.'('.implode(', ', $attributes)]; if (\count($this->nodes)) { foreach ($this->nodes as $name => $node) { @@ -77,41 +77,6 @@ public function __toString() return implode("\n", $repr); } - /** - * @deprecated since 1.16.1 (to be removed in 2.0) - */ - public function toXml($asDom = false) - { - @trigger_error(sprintf('%s is deprecated since version 1.16.1 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); - - $dom = new \DOMDocument('1.0', 'UTF-8'); - $dom->formatOutput = true; - $dom->appendChild($xml = $dom->createElement('twig')); - - $xml->appendChild($node = $dom->createElement('node')); - $node->setAttribute('class', \get_class($this)); - - foreach ($this->attributes as $name => $value) { - $node->appendChild($attribute = $dom->createElement('attribute')); - $attribute->setAttribute('name', $name); - $attribute->appendChild($dom->createTextNode($value)); - } - - foreach ($this->nodes as $name => $n) { - if (null === $n) { - continue; - } - - $child = $n->toXml(true)->getElementsByTagName('node')->item(0); - $child = $dom->importNode($child, true); - $child->setAttribute('name', $name); - - $node->appendChild($child); - } - - return $asDom ? $dom : $dom->saveXML(); - } - public function compile(Compiler $compiler) { foreach ($this->nodes as $node) { @@ -124,16 +89,6 @@ public function getTemplateLine() return $this->lineno; } - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getLine() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateLine() instead.', E_USER_DEPRECATED); - - return $this->lineno; - } - public function getNodeTag() { return $this->tag; @@ -153,7 +108,7 @@ public function hasAttribute($name) public function getAttribute($name) { if (!\array_key_exists($name, $this->attributes)) { - throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, \get_class($this))); + throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, static::class)); } return $this->attributes[$name]; @@ -178,7 +133,7 @@ public function removeAttribute($name) */ public function hasNode($name) { - return \array_key_exists($name, $this->nodes); + return isset($this->nodes[$name]); } /** @@ -186,19 +141,15 @@ public function hasNode($name) */ public function getNode($name) { - if (!\array_key_exists($name, $this->nodes)) { - throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, \get_class($this))); + if (!isset($this->nodes[$name])) { + throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, static::class)); } return $this->nodes[$name]; } - public function setNode($name, $node = null) + public function setNode($name, self $node) { - if (!$node instanceof \Twig_NodeInterface) { - @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, \get_class($this)), E_USER_DEPRECATED); - } - $this->nodes[$name] = $node; } @@ -207,65 +158,59 @@ public function removeNode($name) unset($this->nodes[$name]); } + /** + * @return int + */ + #[\ReturnTypeWillChange] public function count() { return \count($this->nodes); } + /** + * @return \Traversable + */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->nodes); } - public function setTemplateName($name) + /** + * @deprecated since 2.8 (to be removed in 3.0) + */ + public function setTemplateName($name/*, $triggerDeprecation = true */) { + $triggerDeprecation = 2 > \func_num_args() || \func_get_arg(1); + if ($triggerDeprecation) { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Use setSourceContext() instead.', \E_USER_DEPRECATED); + } + $this->name = $name; foreach ($this->nodes as $node) { - if (null !== $node) { - $node->setTemplateName($name); - } + $node->setTemplateName($name, $triggerDeprecation); } } public function getTemplateName() { - return $this->name; + return $this->sourceContext ? $this->sourceContext->getName() : null; } public function setSourceContext(Source $source) { $this->sourceContext = $source; foreach ($this->nodes as $node) { - if ($node instanceof Node) { - $node->setSourceContext($source); - } + $node->setSourceContext($source); } + + $this->setTemplateName($source->getName(), false); } public function getSourceContext() { return $this->sourceContext; } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function setFilename($name) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', E_USER_DEPRECATED); - - $this->setTemplateName($name); - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', E_USER_DEPRECATED); - - return $this->name; - } } class_alias('Twig\Node\Node', 'Twig_Node'); diff --git a/system/libs/Twig/Node/PrintNode.php b/system/libs/Twig/Node/PrintNode.php index 27f1ca4227..fcc086acd9 100644 --- a/system/libs/Twig/Node/PrintNode.php +++ b/system/libs/Twig/Node/PrintNode.php @@ -22,7 +22,7 @@ */ class PrintNode extends Node implements NodeOutputInterface { - public function __construct(AbstractExpression $expr, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, int $lineno, string $tag = null) { parent::__construct(['expr' => $expr], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/SandboxNode.php b/system/libs/Twig/Node/SandboxNode.php index 2d644c3a13..9f8ba46cd4 100644 --- a/system/libs/Twig/Node/SandboxNode.php +++ b/system/libs/Twig/Node/SandboxNode.php @@ -20,7 +20,7 @@ */ class SandboxNode extends Node { - public function __construct(\Twig_NodeInterface $body, $lineno, $tag = null) + public function __construct(Node $body, int $lineno, string $tag = null) { parent::__construct(['body' => $body], [], $lineno, $tag); } @@ -34,12 +34,19 @@ public function compile(Compiler $compiler) ->write("\$this->sandbox->enableSandbox();\n") ->outdent() ->write("}\n") + ->write("try {\n") + ->indent() ->subcompile($this->getNode('body')) + ->outdent() + ->write("} finally {\n") + ->indent() ->write("if (!\$alreadySandboxed) {\n") ->indent() ->write("\$this->sandbox->disableSandbox();\n") ->outdent() ->write("}\n") + ->outdent() + ->write("}\n") ; } } diff --git a/system/libs/Twig/Node/SandboxedPrintNode.php b/system/libs/Twig/Node/SandboxedPrintNode.php index 2359af9110..54e92e66f5 100644 --- a/system/libs/Twig/Node/SandboxedPrintNode.php +++ b/system/libs/Twig/Node/SandboxedPrintNode.php @@ -13,7 +13,6 @@ use Twig\Compiler; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\FilterExpression; /** * Adds a check for the __toString() method when the variable is an object and the sandbox is activated. @@ -42,28 +41,14 @@ public function compile(Compiler $compiler) ; } else { $compiler - ->write('$this->env->getExtension(\'\Twig\Extension\SandboxExtension\')->ensureToStringAllowed(') + ->write('$this->extensions[SandboxExtension::class]->ensureToStringAllowed(') ->subcompile($expr) - ->raw(");\n") + ->raw(', ') + ->repr($expr->getTemplateLine()) + ->raw(", \$this->source);\n") ; } } - - /** - * Removes node filters. - * - * This is mostly needed when another visitor adds filters (like the escaper one). - * - * @return Node - */ - protected function removeNodeFilter(Node $node) - { - if ($node instanceof FilterExpression) { - return $this->removeNodeFilter($node->getNode('node')); - } - - return $node; - } } class_alias('Twig\Node\SandboxedPrintNode', 'Twig_Node_SandboxedPrint'); diff --git a/system/libs/Twig/Node/SetNode.php b/system/libs/Twig/Node/SetNode.php index 656103b9fd..3cf4615f2b 100644 --- a/system/libs/Twig/Node/SetNode.php +++ b/system/libs/Twig/Node/SetNode.php @@ -21,7 +21,7 @@ */ class SetNode extends Node implements NodeCaptureInterface { - public function __construct($capture, \Twig_NodeInterface $names, \Twig_NodeInterface $values, $lineno, $tag = null) + public function __construct(bool $capture, Node $names, Node $values, int $lineno, string $tag = null) { parent::__construct(['names' => $names, 'values' => $values], ['capture' => $capture, 'safe' => false], $lineno, $tag); diff --git a/system/libs/Twig/Node/SpacelessNode.php b/system/libs/Twig/Node/SpacelessNode.php index c8d32daf6b..8fc4a2df3c 100644 --- a/system/libs/Twig/Node/SpacelessNode.php +++ b/system/libs/Twig/Node/SpacelessNode.php @@ -18,11 +18,13 @@ * * It removes spaces between HTML tags. * + * @deprecated since Twig 2.7, to be removed in 3.0 + * * @author Fabien Potencier */ -class SpacelessNode extends Node +class SpacelessNode extends Node implements NodeOutputInterface { - public function __construct(\Twig_NodeInterface $body, $lineno, $tag = 'spaceless') + public function __construct(Node $body, int $lineno, string $tag = 'spaceless') { parent::__construct(['body' => $body], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/TextNode.php b/system/libs/Twig/Node/TextNode.php index 9ac435e904..85640a56ed 100644 --- a/system/libs/Twig/Node/TextNode.php +++ b/system/libs/Twig/Node/TextNode.php @@ -21,7 +21,7 @@ */ class TextNode extends Node implements NodeOutputInterface { - public function __construct($data, $lineno) + public function __construct(string $data, int $lineno) { parent::__construct([], ['data' => $data], $lineno); } diff --git a/system/libs/Twig/Node/WithNode.php b/system/libs/Twig/Node/WithNode.php index f5ae9246dd..07a1c4e30d 100644 --- a/system/libs/Twig/Node/WithNode.php +++ b/system/libs/Twig/Node/WithNode.php @@ -20,14 +20,14 @@ */ class WithNode extends Node { - public function __construct(Node $body, Node $variables = null, $only = false, $lineno, $tag = null) + public function __construct(Node $body, ?Node $variables, bool $only, int $lineno, string $tag = null) { $nodes = ['body' => $body]; if (null !== $variables) { $nodes['variables'] = $variables; } - parent::__construct($nodes, ['only' => (bool) $only], $lineno, $tag); + parent::__construct($nodes, ['only' => $only], $lineno, $tag); } public function compile(Compiler $compiler) diff --git a/system/libs/Twig/NodeTraverser.php b/system/libs/Twig/NodeTraverser.php index bd25d3cc74..12c5a16d60 100644 --- a/system/libs/Twig/NodeTraverser.php +++ b/system/libs/Twig/NodeTraverser.php @@ -11,6 +11,7 @@ namespace Twig; +use Twig\Node\Node; use Twig\NodeVisitor\NodeVisitorInterface; /** @@ -18,14 +19,12 @@ * * It visits all nodes and their children and calls the given visitor for each. * - * @final - * * @author Fabien Potencier */ -class NodeTraverser +final class NodeTraverser { - protected $env; - protected $visitors = []; + private $env; + private $visitors = []; /** * @param NodeVisitorInterface[] $visitors @@ -45,10 +44,8 @@ public function addVisitor(NodeVisitorInterface $visitor) /** * Traverses a node and calls the registered visitors. - * - * @return \Twig_NodeInterface */ - public function traverse(\Twig_NodeInterface $node) + public function traverse(Node $node): Node { ksort($this->visitors); foreach ($this->visitors as $visitors) { @@ -60,24 +57,23 @@ public function traverse(\Twig_NodeInterface $node) return $node; } - protected function traverseForVisitor(NodeVisitorInterface $visitor, \Twig_NodeInterface $node = null) + /** + * @return Node|null + */ + private function traverseForVisitor(NodeVisitorInterface $visitor, Node $node) { - if (null === $node) { - return; - } - $node = $visitor->enterNode($node, $this->env); foreach ($node as $k => $n) { - if (null === $n) { - continue; - } - if (false !== ($m = $this->traverseForVisitor($visitor, $n)) && null !== $m) { if ($m !== $n) { $node->setNode($k, $m); } } else { + if (false === $m) { + @trigger_error('Returning "false" to remove a Node from NodeVisitorInterface::leaveNode() is deprecated since Twig version 2.9; return "null" instead.', \E_USER_DEPRECATED); + } + $node->removeNode($k); } } diff --git a/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php b/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php index b66c3c6f11..9c6cb124db 100644 --- a/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php @@ -23,21 +23,13 @@ */ abstract class AbstractNodeVisitor implements NodeVisitorInterface { - final public function enterNode(\Twig_NodeInterface $node, Environment $env) + final public function enterNode(Node $node, Environment $env) { - if (!$node instanceof Node) { - throw new \LogicException(sprintf('%s only supports \Twig\Node\Node instances.', __CLASS__)); - } - return $this->doEnterNode($node, $env); } - final public function leaveNode(\Twig_NodeInterface $node, Environment $env) + final public function leaveNode(Node $node, Environment $env) { - if (!$node instanceof Node) { - throw new \LogicException(sprintf('%s only supports \Twig\Node\Node instances.', __CLASS__)); - } - return $this->doLeaveNode($node, $env); } @@ -51,7 +43,7 @@ abstract protected function doEnterNode(Node $node, Environment $env); /** * Called after child nodes are visited. * - * @return Node|false|null The modified node or null if the node must be removed + * @return Node|null The modified node or null if the node must be removed */ abstract protected function doLeaveNode(Node $node, Environment $env); } diff --git a/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php b/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php index f6e16fa7d7..bfbfdc9e17 100644 --- a/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php @@ -12,6 +12,7 @@ namespace Twig\NodeVisitor; use Twig\Environment; +use Twig\Extension\EscaperExtension; use Twig\Node\AutoEscapeNode; use Twig\Node\BlockNode; use Twig\Node\BlockReferenceNode; @@ -27,18 +28,16 @@ use Twig\NodeTraverser; /** - * @final - * * @author Fabien Potencier */ -class EscaperNodeVisitor extends AbstractNodeVisitor +final class EscaperNodeVisitor extends AbstractNodeVisitor { - protected $statusStack = []; - protected $blocks = []; - protected $safeAnalysis; - protected $traverser; - protected $defaultStrategy = false; - protected $safeVars = []; + private $statusStack = []; + private $blocks = []; + private $safeAnalysis; + private $traverser; + private $defaultStrategy = false; + private $safeVars = []; public function __construct() { @@ -48,7 +47,7 @@ public function __construct() protected function doEnterNode(Node $node, Environment $env) { if ($node instanceof ModuleNode) { - if ($env->hasExtension('\Twig\Extension\EscaperExtension') && $defaultStrategy = $env->getExtension('\Twig\Extension\EscaperExtension')->getDefaultStrategy($node->getTemplateName())) { + if ($env->hasExtension(EscaperExtension::class) && $defaultStrategy = $env->getExtension(EscaperExtension::class)->getDefaultStrategy($node->getTemplateName())) { $this->defaultStrategy = $defaultStrategy; } $this->safeVars = []; @@ -128,7 +127,7 @@ private function escapeInlinePrintNode(InlinePrint $node, Environment $env, $typ return new InlinePrint($this->getEscaperFilter($type, $expression), $node->getTemplateLine()); } - protected function escapePrintNode(PrintNode $node, Environment $env, $type) + private function escapePrintNode(PrintNode $node, Environment $env, $type) { if (false === $type) { return $node; @@ -145,7 +144,7 @@ protected function escapePrintNode(PrintNode $node, Environment $env, $type) return new $class($this->getEscaperFilter($type, $expression), $node->getTemplateLine()); } - protected function preEscapeFilterNode(FilterExpression $filter, Environment $env) + private function preEscapeFilterNode(FilterExpression $filter, Environment $env) { $name = $filter->getNode('filter')->getAttribute('value'); @@ -164,7 +163,7 @@ protected function preEscapeFilterNode(FilterExpression $filter, Environment $en return $filter; } - protected function isSafeFor($type, \Twig_NodeInterface $expression, $env) + private function isSafeFor($type, Node $expression, $env) { $safe = $this->safeAnalysis->getSafe($expression); @@ -182,7 +181,7 @@ protected function isSafeFor($type, \Twig_NodeInterface $expression, $env) return \in_array($type, $safe) || \in_array('all', $safe); } - protected function needEscaping(Environment $env) + private function needEscaping(Environment $env) { if (\count($this->statusStack)) { return $this->statusStack[\count($this->statusStack) - 1]; @@ -191,7 +190,7 @@ protected function needEscaping(Environment $env) return $this->defaultStrategy ? $this->defaultStrategy : false; } - protected function getEscaperFilter($type, \Twig_NodeInterface $node) + private function getEscaperFilter(string $type, Node $node): FilterExpression { $line = $node->getTemplateLine(); $name = new ConstantExpression('escape', $line); diff --git a/system/libs/Twig/NodeVisitor/MacroAutoImportNodeVisitor.php b/system/libs/Twig/NodeVisitor/MacroAutoImportNodeVisitor.php new file mode 100644 index 0000000000..f41d4637e1 --- /dev/null +++ b/system/libs/Twig/NodeVisitor/MacroAutoImportNodeVisitor.php @@ -0,0 +1,72 @@ + + */ +final class MacroAutoImportNodeVisitor implements NodeVisitorInterface +{ + private $inAModule = false; + private $hasMacroCalls = false; + + public function enterNode(Node $node, Environment $env) + { + if ($node instanceof ModuleNode) { + $this->inAModule = true; + $this->hasMacroCalls = false; + } + + return $node; + } + + public function leaveNode(Node $node, Environment $env) + { + if ($node instanceof ModuleNode) { + $this->inAModule = false; + if ($this->hasMacroCalls) { + $node->getNode('constructor_end')->setNode('_auto_macro_import', new ImportNode(new NameExpression('_self', 0), new AssignNameExpression('_self', 0), 0, 'import', true)); + } + } elseif ($this->inAModule) { + if ( + $node instanceof GetAttrExpression && + $node->getNode('node') instanceof NameExpression && + '_self' === $node->getNode('node')->getAttribute('name') && + $node->getNode('attribute') instanceof ConstantExpression + ) { + $this->hasMacroCalls = true; + + $name = $node->getNode('attribute')->getAttribute('value'); + $node = new MethodCallExpression($node->getNode('node'), 'macro_'.$name, $node->getNode('arguments'), $node->getTemplateLine()); + $node->setAttribute('safe', true); + } + } + + return $node; + } + + public function getPriority() + { + // we must be ran before auto-escaping + return -10; + } +} diff --git a/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php b/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php index 9b8730b48d..e0ffae2c0e 100644 --- a/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php +++ b/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php @@ -12,6 +12,7 @@ namespace Twig\NodeVisitor; use Twig\Environment; +use Twig\Node\Node; /** * Interface for node visitor classes. @@ -23,16 +24,16 @@ interface NodeVisitorInterface /** * Called before child nodes are visited. * - * @return \Twig_NodeInterface The modified node + * @return Node The modified node */ - public function enterNode(\Twig_NodeInterface $node, Environment $env); + public function enterNode(Node $node, Environment $env); /** * Called after child nodes are visited. * - * @return \Twig_NodeInterface|false|null The modified node or null if the node must be removed + * @return Node|null The modified node or null if the node must be removed */ - public function leaveNode(\Twig_NodeInterface $node, Environment $env); + public function leaveNode(Node $node, Environment $env); /** * Returns the priority for this visitor. diff --git a/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php b/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php index e5ea9b7cc3..62f7aafbae 100644 --- a/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php @@ -13,8 +13,6 @@ use Twig\Environment; use Twig\Node\BlockReferenceNode; -use Twig\Node\BodyNode; -use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\BlockReferenceExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FilterExpression; @@ -22,12 +20,10 @@ use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\ParentExpression; -use Twig\Node\Expression\TempNameExpression; use Twig\Node\ForNode; use Twig\Node\IncludeNode; use Twig\Node\Node; use Twig\Node\PrintNode; -use Twig\Node\SetTempNode; /** * Tries to optimize the AST. @@ -37,28 +33,25 @@ * You can configure which optimizations you want to activate via the * optimizer mode. * - * @final - * * @author Fabien Potencier */ -class OptimizerNodeVisitor extends AbstractNodeVisitor +final class OptimizerNodeVisitor extends AbstractNodeVisitor { - const OPTIMIZE_ALL = -1; - const OPTIMIZE_NONE = 0; - const OPTIMIZE_FOR = 2; - const OPTIMIZE_RAW_FILTER = 4; - const OPTIMIZE_VAR_ACCESS = 8; - - protected $loops = []; - protected $loopsTargets = []; - protected $optimizers; - protected $prependedNodes = []; - protected $inABody = false; + public const OPTIMIZE_ALL = -1; + public const OPTIMIZE_NONE = 0; + public const OPTIMIZE_FOR = 2; + public const OPTIMIZE_RAW_FILTER = 4; + // obsolete, does not do anything + public const OPTIMIZE_VAR_ACCESS = 8; + + private $loops = []; + private $loopsTargets = []; + private $optimizers; /** * @param int $optimizers The optimizer mode */ - public function __construct($optimizers = -1) + public function __construct(int $optimizers = -1) { if (!\is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) { throw new \InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); @@ -73,27 +66,11 @@ protected function doEnterNode(Node $node, Environment $env) $this->enterOptimizeFor($node, $env); } - if (\PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('\Twig\Extension\SandboxExtension')) { - if ($this->inABody) { - if (!$node instanceof AbstractExpression) { - if ('Twig_Node' !== \get_class($node)) { - array_unshift($this->prependedNodes, []); - } - } else { - $node = $this->optimizeVariables($node, $env); - } - } elseif ($node instanceof BodyNode) { - $this->inABody = true; - } - } - return $node; } protected function doLeaveNode(Node $node, Environment $env) { - $expression = $node instanceof AbstractExpression; - if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { $this->leaveOptimizeFor($node, $env); } @@ -104,33 +81,6 @@ protected function doLeaveNode(Node $node, Environment $env) $node = $this->optimizePrintNode($node, $env); - if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('\Twig\Extension\SandboxExtension')) { - if ($node instanceof BodyNode) { - $this->inABody = false; - } elseif ($this->inABody) { - if (!$expression && 'Twig_Node' !== \get_class($node) && $prependedNodes = array_shift($this->prependedNodes)) { - $nodes = []; - foreach (array_unique($prependedNodes) as $name) { - $nodes[] = new SetTempNode($name, $node->getTemplateLine()); - } - - $nodes[] = $node; - $node = new Node($nodes); - } - } - } - - return $node; - } - - protected function optimizeVariables(\Twig_NodeInterface $node, Environment $env) - { - if ('Twig_Node_Expression_Name' === \get_class($node) && $node->isSimple()) { - $this->prependedNodes[0][] = $node->getAttribute('name'); - - return new TempNameExpression($node->getAttribute('name'), $node->getTemplateLine()); - } - return $node; } @@ -140,10 +90,8 @@ protected function optimizeVariables(\Twig_NodeInterface $node, Environment $env * It replaces: * * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" - * - * @return \Twig_NodeInterface */ - protected function optimizePrintNode(\Twig_NodeInterface $node, Environment $env) + private function optimizePrintNode(Node $node, Environment $env): Node { if (!$node instanceof PrintNode) { return $node; @@ -164,10 +112,8 @@ protected function optimizePrintNode(\Twig_NodeInterface $node, Environment $env /** * Removes "raw" filters. - * - * @return \Twig_NodeInterface */ - protected function optimizeRawFilter(\Twig_NodeInterface $node, Environment $env) + private function optimizeRawFilter(Node $node, Environment $env): Node { if ($node instanceof FilterExpression && 'raw' == $node->getNode('filter')->getAttribute('value')) { return $node->getNode('node'); @@ -179,7 +125,7 @@ protected function optimizeRawFilter(\Twig_NodeInterface $node, Environment $env /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. */ - protected function enterOptimizeFor(\Twig_NodeInterface $node, Environment $env) + private function enterOptimizeFor(Node $node, Environment $env) { if ($node instanceof ForNode) { // disable the loop variable by default @@ -243,7 +189,7 @@ protected function enterOptimizeFor(\Twig_NodeInterface $node, Environment $env) /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. */ - protected function leaveOptimizeFor(\Twig_NodeInterface $node, Environment $env) + private function leaveOptimizeFor(Node $node, Environment $env) { if ($node instanceof ForNode) { array_shift($this->loops); @@ -252,12 +198,12 @@ protected function leaveOptimizeFor(\Twig_NodeInterface $node, Environment $env) } } - protected function addLoopToCurrent() + private function addLoopToCurrent() { $this->loops[0]->setAttribute('with_loop', true); } - protected function addLoopToAll() + private function addLoopToAll() { foreach ($this->loops as $loop) { $loop->setAttribute('with_loop', true); diff --git a/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php b/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php index 97a7a3e6ee..02a2af436b 100644 --- a/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php @@ -23,20 +23,17 @@ use Twig\Node\Expression\ParentExpression; use Twig\Node\Node; -/** - * @final - */ -class SafeAnalysisNodeVisitor extends AbstractNodeVisitor +final class SafeAnalysisNodeVisitor extends AbstractNodeVisitor { - protected $data = []; - protected $safeVars = []; + private $data = []; + private $safeVars = []; public function setSafeVars($safeVars) { $this->safeVars = $safeVars; } - public function getSafe(\Twig_NodeInterface $node) + public function getSafe(Node $node) { $hash = spl_object_hash($node); if (!isset($this->data[$hash])) { @@ -56,7 +53,7 @@ public function getSafe(\Twig_NodeInterface $node) } } - protected function setSafe(\Twig_NodeInterface $node, array $safe) + private function setSafe(Node $node, array $safe) { $hash = spl_object_hash($node); if (isset($this->data[$hash])) { @@ -125,8 +122,7 @@ protected function doLeaveNode(Node $node, Environment $env) } } elseif ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression) { $name = $node->getNode('node')->getAttribute('name'); - // attributes on template instances are safe - if ('_self' == $name || \in_array($name, $this->safeVars)) { + if (\in_array($name, $this->safeVars)) { $this->setSafe($node, ['all']); } else { $this->setSafe($node, []); @@ -138,7 +134,7 @@ protected function doLeaveNode(Node $node, Environment $env) return $node; } - protected function intersectSafe(array $a = null, array $b = null) + private function intersectSafe(array $a = null, array $b = null): array { if (null === $a || null === $b) { return []; diff --git a/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php b/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php index c9403398f0..a51fa10d69 100644 --- a/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php @@ -12,6 +12,7 @@ namespace Twig\NodeVisitor; use Twig\Environment; +use Twig\Node\CheckSecurityCallNode; use Twig\Node\CheckSecurityNode; use Twig\Node\CheckToStringNode; use Twig\Node\Expression\Binary\ConcatBinary; @@ -26,16 +27,14 @@ use Twig\Node\SetNode; /** - * @final - * * @author Fabien Potencier */ -class SandboxNodeVisitor extends AbstractNodeVisitor +final class SandboxNodeVisitor extends AbstractNodeVisitor { - protected $inAModule = false; - protected $tags; - protected $filters; - protected $functions; + private $inAModule = false; + private $tags; + private $filters; + private $functions; private $needsToStringWrap = false; @@ -102,7 +101,8 @@ protected function doLeaveNode(Node $node, Environment $env) if ($node instanceof ModuleNode) { $this->inAModule = false; - $node->getNode('constructor_end')->setNode('_security_check', new Node([new CheckSecurityNode($this->filters, $this->tags, $this->functions), $node->getNode('display_start')])); + $node->setNode('constructor_end', new Node([new CheckSecurityCallNode(), $node->getNode('constructor_end')])); + $node->setNode('class_end', new Node([new CheckSecurityNode($this->filters, $this->tags, $this->functions), $node->getNode('class_end')])); } elseif ($this->inAModule) { if ($node instanceof PrintNode || $node instanceof SetNode) { $this->needsToStringWrap = false; @@ -112,7 +112,7 @@ protected function doLeaveNode(Node $node, Environment $env) return $node; } - private function wrapNode(Node $node, $name) + private function wrapNode(Node $node, string $name) { $expr = $node->getNode($name); if ($expr instanceof NameExpression || $expr instanceof GetAttrExpression) { @@ -120,7 +120,7 @@ private function wrapNode(Node $node, $name) } } - private function wrapArrayNode(Node $node, $name) + private function wrapArrayNode(Node $node, string $name) { $args = $node->getNode($name); foreach ($args as $name => $_) { diff --git a/system/libs/Twig/Parser.php b/system/libs/Twig/Parser.php index 0ea102cc81..0ef3dc2a07 100644 --- a/system/libs/Twig/Parser.php +++ b/system/libs/Twig/Parser.php @@ -23,8 +23,8 @@ use Twig\Node\NodeCaptureInterface; use Twig\Node\NodeOutputInterface; use Twig\Node\PrintNode; +use Twig\Node\SpacelessNode; use Twig\Node\TextNode; -use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; /** @@ -32,22 +32,21 @@ * * @author Fabien Potencier */ -class Parser implements \Twig_ParserInterface +class Parser { - protected $stack = []; - protected $stream; - protected $parent; - protected $handlers; - protected $visitors; - protected $expressionParser; - protected $blocks; - protected $blockStack; - protected $macros; - protected $env; - protected $reservedMacroNames; - protected $importedSymbols; - protected $traits; - protected $embeddedTemplates = []; + private $stack = []; + private $stream; + private $parent; + private $handlers; + private $visitors; + private $expressionParser; + private $blocks; + private $blockStack; + private $macros; + private $env; + private $importedSymbols; + private $traits; + private $embeddedTemplates = []; private $varNameSalt = 0; public function __construct(Environment $env) @@ -55,48 +54,25 @@ public function __construct(Environment $env) $this->env = $env; } - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getEnvironment() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - return $this->env; - } - public function getVarName() { - return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->stream->getSourceContext()->getCode().$this->varNameSalt++)); - } - - /** - * @deprecated since 1.27 (to be removed in 2.0). Use $parser->getStream()->getSourceContext()->getPath() instead. - */ - public function getFilename() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use $parser->getStream()->getSourceContext()->getPath() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->stream->getSourceContext()->getName(); + return sprintf('__internal_parse_%d', $this->varNameSalt++); } public function parse(TokenStream $stream, $test = null, $dropNeedle = false) { - // push all variables into the stack to keep the current state of the parser - // using get_object_vars() instead of foreach would lead to https://bugs.php.net/71336 - // This hack can be removed when min version if PHP 7.0 - $vars = []; - foreach ($this as $k => $v) { - $vars[$k] = $v; - } - - unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']); + $vars = get_object_vars($this); + unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['varNameSalt']); $this->stack[] = $vars; // tag handlers if (null === $this->handlers) { - $this->handlers = $this->env->getTokenParsers(); - $this->handlers->setParser($this); + $this->handlers = []; + foreach ($this->env->getTokenParsers() as $handler) { + $handler->setParser($this); + + $this->handlers[$handler->getTag()] = $handler; + } } // node visitors @@ -116,7 +92,6 @@ public function parse(TokenStream $stream, $test = null, $dropNeedle = false) $this->blockStack = []; $this->importedSymbols = [[]]; $this->embeddedTemplates = []; - $this->varNameSalt = 0; try { $body = $this->subparse($test, $dropNeedle); @@ -156,27 +131,27 @@ public function subparse($test, $dropNeedle = false) $rv = []; while (!$this->stream->isEOF()) { switch ($this->getCurrentToken()->getType()) { - case Token::TEXT_TYPE: + case /* Token::TEXT_TYPE */ 0: $token = $this->stream->next(); $rv[] = new TextNode($token->getValue(), $token->getLine()); break; - case Token::VAR_START_TYPE: + case /* Token::VAR_START_TYPE */ 2: $token = $this->stream->next(); $expr = $this->expressionParser->parseExpression(); - $this->stream->expect(Token::VAR_END_TYPE); + $this->stream->expect(/* Token::VAR_END_TYPE */ 4); $rv[] = new PrintNode($expr, $token->getLine()); break; - case Token::BLOCK_START_TYPE: + case /* Token::BLOCK_START_TYPE */ 1: $this->stream->next(); $token = $this->getCurrentToken(); - if (Token::NAME_TYPE !== $token->getType()) { + if (/* Token::NAME_TYPE */ 5 !== $token->getType()) { throw new SyntaxError('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext()); } - if (null !== $test && \call_user_func($test, $token)) { + if (null !== $test && $test($token)) { if ($dropNeedle) { $this->stream->next(); } @@ -188,8 +163,7 @@ public function subparse($test, $dropNeedle = false) return new Node($rv, [], $lineno); } - $subparser = $this->handlers->getTokenParser($token->getValue()); - if (null === $subparser) { + if (!isset($this->handlers[$token->getValue()])) { if (null !== $test) { $e = new SyntaxError(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()); @@ -206,6 +180,7 @@ public function subparse($test, $dropNeedle = false) $this->stream->next(); + $subparser = $this->handlers[$token->getValue()]; $node = $subparser->parse($token); if (null !== $node) { $rv[] = $node; @@ -224,26 +199,6 @@ public function subparse($test, $dropNeedle = false) return new Node($rv, [], $lineno); } - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function addHandler($name, $class) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - $this->handlers[$name] = $class; - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function addNodeVisitor(NodeVisitorInterface $visitor) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - $this->visitors[] = $visitor; - } - public function getBlockStack() { return $this->blockStack; @@ -286,28 +241,17 @@ public function hasMacro($name) public function setMacro($name, MacroNode $node) { - if ($this->isReservedMacroName($name)) { - throw new SyntaxError(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword.', $name), $node->getTemplateLine(), $this->stream->getSourceContext()); - } - $this->macros[$name] = $node; } + /** + * @deprecated since Twig 2.7 as there are no reserved macro names anymore, will be removed in 3.0. + */ public function isReservedMacroName($name) { - if (null === $this->reservedMacroNames) { - $this->reservedMacroNames = []; - $r = new \ReflectionClass($this->env->getBaseTemplateClass()); - foreach ($r->getMethods() as $method) { - $methodName = strtolower($method->getName()); - - if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) { - $this->reservedMacroNames[] = substr($methodName, 3); - } - } - } + @trigger_error(sprintf('The "%s" method is deprecated since Twig 2.7 and will be removed in 3.0.', __METHOD__), \E_USER_DEPRECATED); - return \in_array(strtolower($name), $this->reservedMacroNames); + return false; } public function addTrait($trait) @@ -334,19 +278,8 @@ public function addImportedSymbol($type, $alias, $name = null, AbstractExpressio public function getImportedSymbol($type, $alias) { - if (null !== $this->peekBlockStack()) { - foreach ($this->importedSymbols as $functions) { - if (isset($functions[$type][$alias])) { - if (\count($this->blockStack) > 1) { - return null; - } - - return $functions[$type][$alias]; - } - } - } else { - return isset($this->importedSymbols[0][$type][$alias]) ? $this->importedSymbols[0][$type][$alias] : null; - } + // if the symbol does not exist in the current scope (0), try in the main/global scope (last index) + return $this->importedSymbols[0][$type][$alias] ?? ($this->importedSymbols[\count($this->importedSymbols) - 1][$type][$alias] ?? null); } public function isMainScope() @@ -398,13 +331,14 @@ public function getCurrentToken() return $this->stream->getCurrent(); } - protected function filterBodyNodes(\Twig_NodeInterface $node) + private function filterBodyNodes(Node $node, bool $nested = false) { // check that the body does not contain non-empty output nodes if ( ($node instanceof TextNode && !ctype_space($node->getAttribute('data'))) || - (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && $node instanceof NodeOutputInterface) + // the "&& !$node instanceof SpacelessNode" part of the condition must be removed in 3.0 + (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && ($node instanceof NodeOutputInterface && !$node instanceof SpacelessNode)) ) { if (false !== strpos((string) $node, \chr(0xEF).\chr(0xBB).\chr(0xBF))) { $t = substr($node->getAttribute('data'), 3); @@ -417,17 +351,37 @@ protected function filterBodyNodes(\Twig_NodeInterface $node) throw new SyntaxError('A template that extends another one cannot include content outside Twig blocks. Did you forget to put the content inside a {% block %} tag?', $node->getTemplateLine(), $this->stream->getSourceContext()); } - // bypass nodes that will "capture" the output + // bypass nodes that "capture" the output if ($node instanceof NodeCaptureInterface) { + // a "block" tag in such a node will serve as a block definition AND be displayed in place as well return $node; } - if ($node instanceof NodeOutputInterface) { + // to be removed completely in Twig 3.0 + if (!$nested && $node instanceof SpacelessNode) { + @trigger_error(sprintf('Using the spaceless tag at the root level of a child template in "%s" at line %d is deprecated since Twig 2.5.0 and will become a syntax error in 3.0.', $this->stream->getSourceContext()->getName(), $node->getTemplateLine()), \E_USER_DEPRECATED); + } + + // "block" tags that are not captured (see above) are only used for defining + // the content of the block. In such a case, nesting it does not work as + // expected as the definition is not part of the default template code flow. + if ($nested && ($node instanceof BlockReferenceNode || $node instanceof \Twig_Node_BlockReference)) { + //throw new SyntaxError('A block definition cannot be nested under non-capturing nodes.', $node->getTemplateLine(), $this->stream->getSourceContext()); + @trigger_error(sprintf('Nesting a block definition under a non-capturing node in "%s" at line %d is deprecated since Twig 2.5.0 and will become a syntax error in 3.0.', $this->stream->getSourceContext()->getName(), $node->getTemplateLine()), \E_USER_DEPRECATED); + + return; + } + + // the "&& !$node instanceof SpacelessNode" part of the condition must be removed in 3.0 + if ($node instanceof NodeOutputInterface && !$node instanceof SpacelessNode) { return; } + // here, $nested means "being at the root level of a child template" + // we need to discard the wrapping "Twig_Node" for the "body" node + $nested = $nested || ('Twig_Node' !== \get_class($node) && Node::class !== \get_class($node)); foreach ($node as $k => $n) { - if (null !== $n && null === $this->filterBodyNodes($n)) { + if (null !== $n && null === $this->filterBodyNodes($n, $nested)) { $node->removeNode($k); } } diff --git a/system/libs/Twig/Profiler/Dumper/BaseDumper.php b/system/libs/Twig/Profiler/Dumper/BaseDumper.php index d965dc7542..1631987bba 100644 --- a/system/libs/Twig/Profiler/Dumper/BaseDumper.php +++ b/system/libs/Twig/Profiler/Dumper/BaseDumper.php @@ -31,7 +31,7 @@ abstract protected function formatNonTemplate(Profile $profile, $prefix); abstract protected function formatTime(Profile $profile, $percent); - private function dumpProfile(Profile $profile, $prefix = '', $sibling = false) + private function dumpProfile(Profile $profile, $prefix = '', $sibling = false): string { if ($profile->isRoot()) { $this->root = $profile->getDuration(); diff --git a/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php b/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php index a1c3c7bce6..f33342905b 100644 --- a/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php +++ b/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php @@ -15,10 +15,8 @@ /** * @author Fabien Potencier - * - * @final */ -class BlackfireDumper +final class BlackfireDumper { public function dump(Profile $profile) { @@ -42,7 +40,7 @@ public function dump(Profile $profile) return $str; } - private function dumpChildren($parent, Profile $profile, &$data) + private function dumpChildren(string $parent, Profile $profile, &$data) { foreach ($profile as $p) { if ($p->isTemplate()) { @@ -55,7 +53,7 @@ private function dumpChildren($parent, Profile $profile, &$data) } } - private function dumpProfile($edge, Profile $profile, &$data) + private function dumpProfile(string $edge, Profile $profile, &$data) { if (isset($data[$edge])) { ++$data[$edge]['ct']; diff --git a/system/libs/Twig/Profiler/Dumper/HtmlDumper.php b/system/libs/Twig/Profiler/Dumper/HtmlDumper.php index c70b405b30..5be5abeb63 100644 --- a/system/libs/Twig/Profiler/Dumper/HtmlDumper.php +++ b/system/libs/Twig/Profiler/Dumper/HtmlDumper.php @@ -15,10 +15,8 @@ /** * @author Fabien Potencier - * - * @final */ -class HtmlDumper extends BaseDumper +final class HtmlDumper extends BaseDumper { private static $colors = [ 'block' => '#dfd', diff --git a/system/libs/Twig/Profiler/Dumper/TextDumper.php b/system/libs/Twig/Profiler/Dumper/TextDumper.php index c6b515891e..395ef9d383 100644 --- a/system/libs/Twig/Profiler/Dumper/TextDumper.php +++ b/system/libs/Twig/Profiler/Dumper/TextDumper.php @@ -15,10 +15,8 @@ /** * @author Fabien Potencier - * - * @final */ -class TextDumper extends BaseDumper +final class TextDumper extends BaseDumper { protected function formatTemplate(Profile $profile, $prefix) { diff --git a/system/libs/Twig/Profiler/Node/EnterProfileNode.php b/system/libs/Twig/Profiler/Node/EnterProfileNode.php index 8ffd3dc78c..91de5ffc81 100644 --- a/system/libs/Twig/Profiler/Node/EnterProfileNode.php +++ b/system/libs/Twig/Profiler/Node/EnterProfileNode.php @@ -21,7 +21,7 @@ */ class EnterProfileNode extends Node { - public function __construct($extensionName, $type, $name, $varName) + public function __construct(string $extensionName, string $type, string $name, string $varName) { parent::__construct([], ['extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName]); } @@ -29,9 +29,9 @@ public function __construct($extensionName, $type, $name, $varName) public function compile(Compiler $compiler) { $compiler - ->write(sprintf('$%s = $this->env->getExtension(', $this->getAttribute('var_name'))) + ->write(sprintf('$%s = $this->extensions[', $this->getAttribute('var_name'))) ->repr($this->getAttribute('extension_name')) - ->raw(");\n") + ->raw("];\n") ->write(sprintf('$%s->enter($%s = new \Twig\Profiler\Profile($this->getTemplateName(), ', $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) ->repr($this->getAttribute('type')) ->raw(', ') diff --git a/system/libs/Twig/Profiler/Node/LeaveProfileNode.php b/system/libs/Twig/Profiler/Node/LeaveProfileNode.php index 3b7a74d026..7fbf4354b0 100644 --- a/system/libs/Twig/Profiler/Node/LeaveProfileNode.php +++ b/system/libs/Twig/Profiler/Node/LeaveProfileNode.php @@ -21,7 +21,7 @@ */ class LeaveProfileNode extends Node { - public function __construct($varName) + public function __construct(string $varName) { parent::__construct([], ['var_name' => $varName]); } diff --git a/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php b/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php index 41ca9e1f29..8b7c18adb6 100644 --- a/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php +++ b/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php @@ -24,16 +24,16 @@ /** * @author Fabien Potencier - * - * @final */ -class ProfilerNodeVisitor extends AbstractNodeVisitor +final class ProfilerNodeVisitor extends AbstractNodeVisitor { private $extensionName; + private $varName; - public function __construct($extensionName) + public function __construct(string $extensionName) { $this->extensionName = $extensionName; + $this->varName = sprintf('__internal_%s', hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $extensionName)); } protected function doEnterNode(Node $node, Environment $env) @@ -44,33 +44,25 @@ protected function doEnterNode(Node $node, Environment $env) protected function doLeaveNode(Node $node, Environment $env) { if ($node instanceof ModuleNode) { - $varName = $this->getVarName(); - $node->setNode('display_start', new Node([new EnterProfileNode($this->extensionName, Profile::TEMPLATE, $node->getTemplateName(), $varName), $node->getNode('display_start')])); - $node->setNode('display_end', new Node([new LeaveProfileNode($varName), $node->getNode('display_end')])); + $node->setNode('display_start', new Node([new EnterProfileNode($this->extensionName, Profile::TEMPLATE, $node->getTemplateName(), $this->varName), $node->getNode('display_start')])); + $node->setNode('display_end', new Node([new LeaveProfileNode($this->varName), $node->getNode('display_end')])); } elseif ($node instanceof BlockNode) { - $varName = $this->getVarName(); $node->setNode('body', new BodyNode([ - new EnterProfileNode($this->extensionName, Profile::BLOCK, $node->getAttribute('name'), $varName), + new EnterProfileNode($this->extensionName, Profile::BLOCK, $node->getAttribute('name'), $this->varName), $node->getNode('body'), - new LeaveProfileNode($varName), + new LeaveProfileNode($this->varName), ])); } elseif ($node instanceof MacroNode) { - $varName = $this->getVarName(); $node->setNode('body', new BodyNode([ - new EnterProfileNode($this->extensionName, Profile::MACRO, $node->getAttribute('name'), $varName), + new EnterProfileNode($this->extensionName, Profile::MACRO, $node->getAttribute('name'), $this->varName), $node->getNode('body'), - new LeaveProfileNode($varName), + new LeaveProfileNode($this->varName), ])); } return $node; } - private function getVarName() - { - return sprintf('__internal_%s', hash('sha256', $this->extensionName)); - } - public function getPriority() { return 0; diff --git a/system/libs/Twig/Profiler/Profile.php b/system/libs/Twig/Profiler/Profile.php index d83da40af3..3a5ff8b50f 100644 --- a/system/libs/Twig/Profiler/Profile.php +++ b/system/libs/Twig/Profiler/Profile.php @@ -14,14 +14,14 @@ /** * @author Fabien Potencier * - * @final + * @final since Twig 2.4.0 */ class Profile implements \IteratorAggregate, \Serializable { - const ROOT = 'ROOT'; - const BLOCK = 'block'; - const TEMPLATE = 'template'; - const MACRO = 'macro'; + public const ROOT = 'ROOT'; + public const BLOCK = 'block'; + public const TEMPLATE = 'template'; + public const MACRO = 'macro'; private $template; private $name; @@ -30,8 +30,12 @@ class Profile implements \IteratorAggregate, \Serializable private $ends = []; private $profiles = []; - public function __construct($template = 'main', $type = self::ROOT, $name = 'main') + public function __construct(string $template = 'main', string $type = self::ROOT, string $name = 'main') { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->template = $template; $this->type = $type; $this->name = 0 === strpos($name, '__internal_') ? 'INTERNAL' : $name; @@ -153,17 +157,18 @@ public function reset() $this->enter(); } - public function getIterator() + #[\ReturnTypeWillChange] + public function getIterator(): \Traversable { return new \ArrayIterator($this->profiles); } - public function serialize() + public function serialize(): string { return serialize($this->__serialize()); } - public function unserialize($data) + public function unserialize($data): void { $this->__unserialize(unserialize($data)); } @@ -171,7 +176,7 @@ public function unserialize($data) /** * @internal */ - public function __serialize() + public function __serialize(): array { return [$this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles]; } @@ -179,7 +184,7 @@ public function __serialize() /** * @internal */ - public function __unserialize(array $data) + public function __unserialize(array $data): void { list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = $data; } diff --git a/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php b/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php index 43b5f24eba..e4676f7cfb 100644 --- a/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php +++ b/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php @@ -23,7 +23,7 @@ class FactoryRuntimeLoader implements RuntimeLoaderInterface /** * @param array $map An array where keys are class names and values factory callables */ - public function __construct($map = []) + public function __construct(array $map = []) { $this->map = $map; } diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php index fa0fdee72f..33c84f2231 100644 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php @@ -15,13 +15,24 @@ * Exception thrown when a not allowed filter is used in a template. * * @author Martin Hasoň + * + * @final */ class SecurityNotAllowedFilterError extends SecurityError { private $filterName; - public function __construct($message, $functionName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $functionName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->filterName = $functionName; } diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php index 8f23f93acd..5151762b56 100644 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php @@ -15,13 +15,24 @@ * Exception thrown when a not allowed function is used in a template. * * @author Martin Hasoň + * + * @final */ class SecurityNotAllowedFunctionError extends SecurityError { private $functionName; - public function __construct($message, $functionName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $functionName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->functionName = $functionName; } diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php index 62e13f49bd..62c3fddd5f 100644 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php @@ -15,14 +15,25 @@ * Exception thrown when a not allowed class method is used in a template. * * @author Kit Burton-Senior + * + * @final */ class SecurityNotAllowedMethodError extends SecurityError { private $className; private $methodName; - public function __construct($message, $className, $methodName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $className, string $methodName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->className = $className; $this->methodName = $methodName; diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php index 3bf530574f..a9e4aff272 100644 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php @@ -15,14 +15,25 @@ * Exception thrown when a not allowed class property is used in a template. * * @author Kit Burton-Senior + * + * @final */ class SecurityNotAllowedPropertyError extends SecurityError { private $className; private $propertyName; - public function __construct($message, $className, $propertyName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $className, string $propertyName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->className = $className; $this->propertyName = $propertyName; diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php index de283b40cd..0abc49ef31 100644 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php @@ -15,13 +15,24 @@ * Exception thrown when a not allowed tag is used in a template. * * @author Martin Hasoň + * + * @final */ class SecurityNotAllowedTagError extends SecurityError { private $tagName; - public function __construct($message, $tagName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $tagName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->tagName = $tagName; } diff --git a/system/libs/Twig/Sandbox/SecurityPolicy.php b/system/libs/Twig/Sandbox/SecurityPolicy.php index 31b6c34833..1406e8061a 100644 --- a/system/libs/Twig/Sandbox/SecurityPolicy.php +++ b/system/libs/Twig/Sandbox/SecurityPolicy.php @@ -12,21 +12,20 @@ namespace Twig\Sandbox; use Twig\Markup; +use Twig\Template; /** * Represents a security policy which need to be enforced when sandbox mode is enabled. * - * @final - * * @author Fabien Potencier */ -class SecurityPolicy implements SecurityPolicyInterface +final class SecurityPolicy implements SecurityPolicyInterface { - protected $allowedTags; - protected $allowedFilters; - protected $allowedMethods; - protected $allowedProperties; - protected $allowedFunctions; + private $allowedTags; + private $allowedFilters; + private $allowedMethods; + private $allowedProperties; + private $allowedFunctions; public function __construct(array $allowedTags = [], array $allowedFilters = [], array $allowedMethods = [], array $allowedProperties = [], array $allowedFunctions = []) { @@ -51,7 +50,7 @@ public function setAllowedMethods(array $methods) { $this->allowedMethods = []; foreach ($methods as $class => $m) { - $this->allowedMethods[$class] = array_map('strtolower', \is_array($m) ? $m : [$m]); + $this->allowedMethods[$class] = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, \is_array($m) ? $m : [$m]); } } @@ -88,12 +87,12 @@ public function checkSecurity($tags, $filters, $functions) public function checkMethodAllowed($obj, $method) { - if ($obj instanceof \Twig_TemplateInterface || $obj instanceof Markup) { + if ($obj instanceof Template || $obj instanceof Markup) { return; } $allowed = false; - $method = strtolower($method); + $method = strtr($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); foreach ($this->allowedMethods as $class => $methods) { if ($obj instanceof $class) { $allowed = \in_array($method, $methods); diff --git a/system/libs/Twig/Sandbox/SecurityPolicyInterface.php b/system/libs/Twig/Sandbox/SecurityPolicyInterface.php index a31863f6c2..0166f67a38 100644 --- a/system/libs/Twig/Sandbox/SecurityPolicyInterface.php +++ b/system/libs/Twig/Sandbox/SecurityPolicyInterface.php @@ -18,11 +18,30 @@ */ interface SecurityPolicyInterface { + /** + * @param string[] $tags + * @param string[] $filters + * @param string[] $functions + * + * @throws SecurityError + */ public function checkSecurity($tags, $filters, $functions); + /** + * @param object $obj + * @param string $method + * + * @throws SecurityNotAllowedMethodError + */ public function checkMethodAllowed($obj, $method); - public function checkPropertyAllowed($obj, $method); + /** + * @param object $obj + * @param string $property + * + * @throws SecurityNotAllowedPropertyError + */ + public function checkPropertyAllowed($obj, $property); } class_alias('Twig\Sandbox\SecurityPolicyInterface', 'Twig_Sandbox_SecurityPolicyInterface'); diff --git a/system/libs/Twig/Source.php b/system/libs/Twig/Source.php index 32a82163f4..a72877880c 100644 --- a/system/libs/Twig/Source.php +++ b/system/libs/Twig/Source.php @@ -14,11 +14,9 @@ /** * Holds information about a non-compiled Twig template. * - * @final - * * @author Fabien Potencier */ -class Source +final class Source { private $code; private $name; @@ -29,14 +27,14 @@ class Source * @param string $name The template logical name * @param string $path The filesystem path of the template if any */ - public function __construct($code, $name, $path = '') + public function __construct(string $code, string $name, string $path = '') { $this->code = $code; $this->name = $name; $this->path = $path; } - public function getCode() + public function getCode(): string { return $this->code; } @@ -46,7 +44,7 @@ public function getName() return $this->name; } - public function getPath() + public function getPath(): string { return $this->path; } diff --git a/system/libs/Twig/Template.php b/system/libs/Twig/Template.php index 3f7447c126..76d55cbcb3 100644 --- a/system/libs/Twig/Template.php +++ b/system/libs/Twig/Template.php @@ -27,27 +27,28 @@ * * @internal */ -abstract class Template implements \Twig_TemplateInterface +abstract class Template { - /** - * @internal - */ - protected static $cache = []; + public const ANY_CALL = 'any'; + public const ARRAY_CALL = 'array'; + public const METHOD_CALL = 'method'; protected $parent; protected $parents = []; protected $env; protected $blocks = []; protected $traits = []; + protected $extensions = []; protected $sandbox; public function __construct(Environment $env) { $this->env = $env; + $this->extensions = $env->getExtensions(); } /** - * @internal this method will be removed in 2.0 and is only used internally to provide an upgrade path from 1.x to 2.0 + * @internal this method will be removed in 3.0 and is only used internally to provide an upgrade path from 1.x to 2.0 */ public function __toString() { @@ -66,24 +67,7 @@ abstract public function getTemplateName(); * * @return array Debug information */ - public function getDebugInfo() - { - return []; - } - - /** - * Returns the template source code. - * - * @return string The template source code - * - * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead - */ - public function getSource() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); - - return ''; - } + abstract public function getDebugInfo(); /** * Returns information about the original template source code. @@ -95,27 +79,13 @@ public function getSourceContext() return new Source('', $this->getTemplateName()); } - /** - * @deprecated since 1.20 (to be removed in 2.0) - */ - public function getEnvironment() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.20 and will be removed in 2.0.', E_USER_DEPRECATED); - - return $this->env; - } - /** * Returns the parent template. * * This method is for internal use only and should never be called * directly. * - * @param array $context - * - * @return \Twig_TemplateInterface|TemplateWrapper|false The parent template or false if there is no parent - * - * @internal + * @return Template|TemplateWrapper|false The parent template or false if there is no parent */ public function getParent(array $context) { @@ -169,8 +139,6 @@ public function isTraitable() */ public function displayParentBlock($name, array $context, array $blocks = []) { - $name = (string) $name; - if (isset($this->traits[$name])) { $this->traits[$name][0]->displayBlock($name, $context, $blocks, false); } elseif (false !== $parent = $this->getParent($context)) { @@ -191,10 +159,8 @@ public function displayParentBlock($name, array $context, array $blocks = []) * @param array $blocks The current set of blocks * @param bool $useBlocks Whether to use the current set of blocks */ - public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true) + public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true, self $templateContext = null) { - $name = (string) $name; - if ($useBlocks && isset($blocks[$name])) { $template = $blocks[$name][0]; $block = $blocks[$name][1]; @@ -233,9 +199,11 @@ public function displayBlock($name, array $context, array $blocks = [], $useBloc throw $e; } } elseif (false !== $parent = $this->getParent($context)) { - $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false); + $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false, $templateContext ?? $this); + } elseif (isset($blocks[$name])) { + throw new RuntimeError(sprintf('Block "%s" should not call parent() in "%s" as the block does not exist in the parent template "%s".', $name, $blocks[$name][0]->getTemplateName(), $this->getTemplateName()), -1, $blocks[$name][0]->getSourceContext()); } else { - @trigger_error(sprintf('Silent display of undefined block "%s" in template "%s" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block(\'%s\') is defined" expression to test for block existence.', $name, $this->getTemplateName(), $name), E_USER_DEPRECATED); + throw new RuntimeError(sprintf('Block "%s" on template "%s" does not exist.', $name, $this->getTemplateName()), -1, ($templateContext ?? $this)->getSourceContext()); } } @@ -300,14 +268,8 @@ public function renderBlock($name, array $context, array $blocks = [], $useBlock * * @return bool true if the block exists, false otherwise */ - public function hasBlock($name, array $context = null, array $blocks = []) + public function hasBlock($name, array $context, array $blocks = []) { - if (null === $context) { - @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); - - return isset($this->blocks[(string) $name]); - } - if (isset($blocks[$name])) { return $blocks[$name][0] instanceof self; } @@ -334,14 +296,8 @@ public function hasBlock($name, array $context = null, array $blocks = []) * * @return array An array of block names */ - public function getBlockNames(array $context = null, array $blocks = []) + public function getBlockNames(array $context, array $blocks = []) { - if (null === $context) { - @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); - - return array_keys($this->blocks); - } - $names = array_merge(array_keys($blocks), array_keys($this->blocks)); if (false !== $parent = $this->getParent($context)) { @@ -366,7 +322,7 @@ protected function loadTemplate($template, $templateName = null, $line = null, $ } if ($template === $this->getTemplateName()) { - $class = \get_class($this); + $class = static::class; if (false !== $pos = strrpos($class, '___', -1)) { $class = substr($class, 0, $pos); } @@ -399,7 +355,7 @@ protected function loadTemplate($template, $templateName = null, $line = null, $ * * @return Template */ - protected function unwrap() + public function unwrap() { return $this; } @@ -432,12 +388,6 @@ public function render(array $context) } try { $this->display($context); - } catch (\Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; } catch (\Throwable $e) { while (ob_get_level() > $level) { ob_end_clean(); @@ -480,254 +430,6 @@ protected function displayWithErrorHandling(array $context, array $blocks = []) * @param array $blocks An array of blocks to pass to the template */ abstract protected function doDisplay(array $context, array $blocks = []); - - /** - * Returns a variable from the context. - * - * This method is for internal use only and should never be called - * directly. - * - * This method should not be overridden in a sub-class as this is an - * implementation detail that has been introduced to optimize variable - * access for versions of PHP before 5.4. This is not a way to override - * the way to get a variable value. - * - * @param array $context The context - * @param string $item The variable to return from the context - * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not - * - * @return mixed The content of the context variable - * - * @throws RuntimeError if the variable does not exist and Twig is running in strict mode - * - * @internal - */ - final protected function getContext($context, $item, $ignoreStrictCheck = false) - { - if (!\array_key_exists($item, $context)) { - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - throw new RuntimeError(sprintf('Variable "%s" does not exist.', $item), -1, $this->getSourceContext()); - } - - return $context[$item]; - } - - /** - * Returns the attribute value for a given array/object. - * - * @param mixed $object The object or array from where to get the item - * @param mixed $item The item to get from the array or object - * @param array $arguments An array of arguments to pass if the item is an object method - * @param string $type The type of attribute (@see \Twig\Template constants) - * @param bool $isDefinedTest Whether this is only a defined check - * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not - * - * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true - * - * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false - * - * @internal - */ - protected function getAttribute($object, $item, array $arguments = [], $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) - { - // array - if (self::METHOD_CALL !== $type) { - $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item; - - if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object))) - || ($object instanceof \ArrayAccess && isset($object[$arrayItem])) - ) { - if ($isDefinedTest) { - return true; - } - - return $object[$arrayItem]; - } - - if (self::ARRAY_CALL === $type || !\is_object($object)) { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - if ($object instanceof \ArrayAccess) { - $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object)); - } elseif (\is_object($object)) { - $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object)); - } elseif (\is_array($object)) { - if (empty($object)) { - $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem); - } else { - $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); - } - } elseif (self::ARRAY_CALL === $type) { - if (null === $object) { - $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item); - } else { - $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); - } - } elseif (null === $object) { - $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item); - } else { - $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); - } - - throw new RuntimeError($message, -1, $this->getSourceContext()); - } - } - - if (!\is_object($object)) { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - if (null === $object) { - $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); - } elseif (\is_array($object)) { - $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item); - } else { - $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); - } - - throw new RuntimeError($message, -1, $this->getSourceContext()); - } - - // object property - if (self::METHOD_CALL !== $type && !$object instanceof self) { // \Twig\Template does not have public properties, and we don't want to allow access to internal ones - if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) { - if ($isDefinedTest) { - return true; - } - - if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) { - $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkPropertyAllowed($object, $item); - } - - return $object->$item; - } - } - - $class = \get_class($object); - - // object method - if (!isset(self::$cache[$class])) { - // get_class_methods returns all methods accessible in the scope, but we only want public ones to be accessible in templates - if ($object instanceof self) { - $ref = new \ReflectionClass($class); - $methods = []; - - foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC) as $refMethod) { - // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment - if ('getenvironment' !== strtolower($refMethod->name)) { - $methods[] = $refMethod->name; - } - } - } else { - $methods = get_class_methods($object); - } - // sort values to have consistent behavior, so that "get" methods win precedence over "is" methods - sort($methods); - - $cache = []; - - foreach ($methods as $method) { - $cache[$method] = $method; - $cache[$lcName = strtolower($method)] = $method; - - if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) { - $name = substr($method, 3); - $lcName = substr($lcName, 3); - } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) { - $name = substr($method, 2); - $lcName = substr($lcName, 2); - } else { - continue; - } - - // skip get() and is() methods (in which case, $name is empty) - if ($name) { - if (!isset($cache[$name])) { - $cache[$name] = $method; - } - if (!isset($cache[$lcName])) { - $cache[$lcName] = $method; - } - } - } - self::$cache[$class] = $cache; - } - - $call = false; - if (isset(self::$cache[$class][$item])) { - $method = self::$cache[$class][$item]; - } elseif (isset(self::$cache[$class][$lcItem = strtolower($item)])) { - $method = self::$cache[$class][$lcItem]; - } elseif (isset(self::$cache[$class]['__call'])) { - $method = $item; - $call = true; - } else { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), -1, $this->getSourceContext()); - } - - if ($isDefinedTest) { - return true; - } - - if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) { - $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkMethodAllowed($object, $method); - } - - // Some objects throw exceptions when they have __call, and the method we try - // to call is not supported. If ignoreStrictCheck is true, we should return null. - try { - if (!$arguments) { - $ret = $object->$method(); - } else { - $ret = \call_user_func_array([$object, $method], $arguments); - } - } catch (\BadMethodCallException $e) { - if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { - return; - } - throw $e; - } - - // @deprecated in 1.28 - if ($object instanceof \Twig_TemplateInterface) { - $self = $object->getTemplateName() === $this->getTemplateName(); - $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $item, $object->getTemplateName(), $this->getTemplateName()); - if ('renderBlock' === $method || 'displayBlock' === $method) { - $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ? '' : ', template'); - } elseif ('hasBlock' === $method) { - $message .= sprintf(' Use "block("%s"%s) is defined" instead).', $arguments[0], $self ? '' : ', template'); - } elseif ('render' === $method || 'display' === $method) { - $message .= sprintf(' Use include("%s") instead).', $object->getTemplateName()); - } - @trigger_error($message, E_USER_DEPRECATED); - - return '' === $ret ? '' : new Markup($ret, $this->env->getCharset()); - } - - return $ret; - } } class_alias('Twig\Template', 'Twig_Template'); diff --git a/system/libs/Twig/TemplateWrapper.php b/system/libs/Twig/TemplateWrapper.php index e2654094e4..8b44815313 100644 --- a/system/libs/Twig/TemplateWrapper.php +++ b/system/libs/Twig/TemplateWrapper.php @@ -37,14 +37,12 @@ public function __construct(Environment $env, Template $template) * Renders the template. * * @param array $context An array of parameters to pass to the template - * - * @return string The rendered template */ - public function render($context = []) + public function render(array $context = []): string { // using func_get_args() allows to not expose the blocks argument // as it should only be used by internal code - return $this->template->render($context, \func_num_args() > 1 ? func_get_arg(1) : []); + return $this->template->render($context, \func_get_args()[1] ?? []); } /** @@ -52,11 +50,11 @@ public function render($context = []) * * @param array $context An array of parameters to pass to the template */ - public function display($context = []) + public function display(array $context = []) { // using func_get_args() allows to not expose the blocks argument // as it should only be used by internal code - $this->template->display($context, \func_num_args() > 1 ? func_get_arg(1) : []); + $this->template->display($context, \func_get_args()[1] ?? []); } /** @@ -64,10 +62,8 @@ public function display($context = []) * * @param string $name The block name * @param array $context An array of parameters to pass to the template - * - * @return bool */ - public function hasBlock($name, $context = []) + public function hasBlock(string $name, array $context = []): bool { return $this->template->hasBlock($name, $context); } @@ -79,7 +75,7 @@ public function hasBlock($name, $context = []) * * @return string[] An array of defined template block names */ - public function getBlockNames($context = []) + public function getBlockNames(array $context = []): array { return $this->template->getBlockNames($context); } @@ -92,7 +88,7 @@ public function getBlockNames($context = []) * * @return string The rendered block */ - public function renderBlock($name, $context = []) + public function renderBlock(string $name, array $context = []): string { $context = $this->env->mergeGlobals($context); $level = ob_get_level(); @@ -103,12 +99,6 @@ public function renderBlock($name, $context = []) } try { $this->template->displayBlock($name, $context); - } catch (\Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; } catch (\Throwable $e) { while (ob_get_level() > $level) { ob_end_clean(); @@ -126,23 +116,17 @@ public function renderBlock($name, $context = []) * @param string $name The block name to render * @param array $context An array of parameters to pass to the template */ - public function displayBlock($name, $context = []) + public function displayBlock(string $name, array $context = []) { $this->template->displayBlock($name, $this->env->mergeGlobals($context)); } - /** - * @return Source - */ - public function getSourceContext() + public function getSourceContext(): Source { return $this->template->getSourceContext(); } - /** - * @return string - */ - public function getTemplateName() + public function getTemplateName(): string { return $this->template->getTemplateName(); } diff --git a/system/libs/Twig/Test/IntegrationTestCase.php b/system/libs/Twig/Test/IntegrationTestCase.php index 36b3607586..df880a8412 100644 --- a/system/libs/Twig/Test/IntegrationTestCase.php +++ b/system/libs/Twig/Test/IntegrationTestCase.php @@ -16,9 +16,7 @@ use Twig\Error\Error; use Twig\Extension\ExtensionInterface; use Twig\Loader\ArrayLoader; -use Twig\Loader\SourceContextLoaderInterface; use Twig\RuntimeLoader\RuntimeLoaderInterface; -use Twig\Source; use Twig\TwigFilter; use Twig\TwigFunction; use Twig\TwigTest; @@ -79,18 +77,18 @@ protected function getTwigTests() /** * @dataProvider getTests */ - public function testIntegration($file, $message, $condition, $templates, $exception, $outputs) + public function testIntegration($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '') { - $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); + $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation); } /** * @dataProvider getLegacyTests * @group legacy */ - public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs) + public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '') { - $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); + $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation); } public function getTests($name, $legacyTests = false) @@ -109,23 +107,25 @@ public function getTests($name, $legacyTests = false) $test = file_get_contents($file->getRealpath()); - if (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { + if (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*(?:--DEPRECATION--\s*(.*?))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { $message = $match[1]; $condition = $match[2]; - $templates = self::parseTemplates($match[3]); - $exception = $match[5]; - $outputs = [[null, $match[4], null, '']]; - } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { + $deprecation = $match[3]; + $templates = self::parseTemplates($match[4]); + $exception = $match[6]; + $outputs = [[null, $match[5], null, '']]; + } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*(?:--DEPRECATION--\s*(.*?))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { $message = $match[1]; $condition = $match[2]; - $templates = self::parseTemplates($match[3]); + $deprecation = $match[3]; + $templates = self::parseTemplates($match[4]); $exception = false; - preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER); + preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, \PREG_SET_ORDER); } else { throw new \InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file))); } - $tests[] = [str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs]; + $tests[] = [str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs, $deprecation]; } if ($legacyTests && empty($tests)) { @@ -141,7 +141,7 @@ public function getLegacyTests() return $this->getTests('testLegacyIntegration', true); } - protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs) + protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '') { if (!$outputs) { $this->markTestSkipped('no tests to run'); @@ -183,11 +183,23 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e $twig->addFunction($function); } + // avoid using the same PHP class name for different cases $p = new \ReflectionProperty($twig, 'templateClassPrefix'); $p->setAccessible(true); - $p->setValue($twig, '__TwigTemplate_'.hash('sha256', uniqid(mt_rand(), true), false).'_'); + $p->setValue($twig, '__TwigTemplate_'.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', uniqid(mt_rand(), true), false).'_'); + $deprecations = []; try { + $prevHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$deprecations, &$prevHandler) { + if (\E_USER_DEPRECATED === $type) { + $deprecations[] = $msg; + + return true; + } + + return $prevHandler ? $prevHandler($type, $msg, $file, $line, $context) : false; + }); + $template = $twig->load('index.twig'); } catch (\Exception $e) { if (false !== $exception) { @@ -200,8 +212,12 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e } throw new Error(sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e); + } finally { + restore_error_handler(); } + $this->assertSame($deprecation, implode("\n", $deprecations)); + try { $output = trim($template->render(eval($match[1].';')), "\n "); } catch (\Exception $e) { @@ -229,13 +245,7 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e foreach (array_keys($templates) as $name) { echo "Template: $name\n"; - $loader = $twig->getLoader(); - if (!$loader instanceof SourceContextLoaderInterface) { - $source = new Source($loader->getSource($name), $name); - } else { - $source = $loader->getSourceContext($name); - } - echo $twig->compile($twig->parse($twig->tokenize($source))); + echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSourceContext($name)))); } } $this->assertEquals($expected, $output, $message.' (in '.$file.')'); @@ -245,9 +255,9 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e protected static function parseTemplates($test) { $templates = []; - preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER); + preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, \PREG_SET_ORDER); foreach ($matches as $match) { - $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2]; + $templates[($match[1] ?: 'index.twig')] = $match[2]; } return $templates; diff --git a/system/libs/Twig/Test/NodeTestCase.php b/system/libs/Twig/Test/NodeTestCase.php index f3358cb9a3..368ceb1040 100644 --- a/system/libs/Twig/Test/NodeTestCase.php +++ b/system/libs/Twig/Test/NodeTestCase.php @@ -55,24 +55,12 @@ protected function getVariableGetter($name, $line = false) { $line = $line > 0 ? "// line {$line}\n" : ''; - if (\PHP_VERSION_ID >= 70000) { - return sprintf('%s($context["%s"] ?? null)', $line, $name); - } - - if (\PHP_VERSION_ID >= 50400) { - return sprintf('%s(isset($context["%s"]) ? $context["%s"] : null)', $line, $name, $name); - } - - return sprintf('%s$this->getContext($context, "%s")', $line, $name); + return sprintf('%s($context["%s"] ?? null)', $line, $name); } protected function getAttributeGetter() { - if (\function_exists('twig_template_get_attributes')) { - return 'twig_template_get_attributes($this, '; - } - - return '$this->getAttribute('; + return 'twig_get_attribute($this->env, $this->source, '; } } diff --git a/system/libs/Twig/Token.php b/system/libs/Twig/Token.php index a0bb11af15..0b2ef9be43 100644 --- a/system/libs/Twig/Token.php +++ b/system/libs/Twig/Token.php @@ -16,29 +16,27 @@ * Represents a Token. * * @author Fabien Potencier - * - * @final */ -class Token +final class Token { - protected $value; - protected $type; - protected $lineno; + private $value; + private $type; + private $lineno; - const EOF_TYPE = -1; - const TEXT_TYPE = 0; - const BLOCK_START_TYPE = 1; - const VAR_START_TYPE = 2; - const BLOCK_END_TYPE = 3; - const VAR_END_TYPE = 4; - const NAME_TYPE = 5; - const NUMBER_TYPE = 6; - const STRING_TYPE = 7; - const OPERATOR_TYPE = 8; - const PUNCTUATION_TYPE = 9; - const INTERPOLATION_START_TYPE = 10; - const INTERPOLATION_END_TYPE = 11; - const ARROW_TYPE = 12; + public const EOF_TYPE = -1; + public const TEXT_TYPE = 0; + public const BLOCK_START_TYPE = 1; + public const VAR_START_TYPE = 2; + public const BLOCK_END_TYPE = 3; + public const VAR_END_TYPE = 4; + public const NAME_TYPE = 5; + public const NUMBER_TYPE = 6; + public const STRING_TYPE = 7; + public const OPERATOR_TYPE = 8; + public const PUNCTUATION_TYPE = 9; + public const INTERPOLATION_START_TYPE = 10; + public const INTERPOLATION_END_TYPE = 11; + public const ARROW_TYPE = 12; /** * @param int $type The type of the token diff --git a/system/libs/Twig/TokenParser/ApplyTokenParser.php b/system/libs/Twig/TokenParser/ApplyTokenParser.php index 879879a2b0..c75e5ef8aa 100644 --- a/system/libs/Twig/TokenParser/ApplyTokenParser.php +++ b/system/libs/Twig/TokenParser/ApplyTokenParser.php @@ -22,7 +22,7 @@ * * {% apply upper %} * This text becomes uppercase - * {% endapplys %} + * {% endapply %} */ final class ApplyTokenParser extends AbstractTokenParser { diff --git a/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php b/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php index 2cd0cc69d7..10fdb8180d 100644 --- a/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php +++ b/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php @@ -18,58 +18,27 @@ /** * Marks a section of a template to be escaped or not. - * - * {% autoescape true %} - * Everything will be automatically escaped in this block - * {% endautoescape %} - * - * {% autoescape false %} - * Everything will be outputed as is in this block - * {% endautoescape %} - * - * {% autoescape true js %} - * Everything will be automatically escaped in this block - * using the js escaping strategy - * {% endautoescape %} - * - * @final */ -class AutoEscapeTokenParser extends AbstractTokenParser +final class AutoEscapeTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - if ($stream->test(Token::BLOCK_END_TYPE)) { + if ($stream->test(/* Token::BLOCK_END_TYPE */ 3)) { $value = 'html'; } else { $expr = $this->parser->getExpressionParser()->parseExpression(); if (!$expr instanceof ConstantExpression) { - throw new SyntaxError('An escaping strategy must be a string or a bool.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); + throw new SyntaxError('An escaping strategy must be a string or false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } $value = $expr->getAttribute('value'); - - $compat = true === $value || false === $value; - - if (true === $value) { - $value = 'html'; - } - - if ($compat && $stream->test(Token::NAME_TYPE)) { - @trigger_error('Using the autoescape tag with "true" or "false" before the strategy name is deprecated since version 1.21.', E_USER_DEPRECATED); - - if (false === $value) { - throw new SyntaxError('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - - $value = $stream->next()->getValue(); - } } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new AutoEscapeNode($value, $body, $lineno, $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/BlockTokenParser.php b/system/libs/Twig/TokenParser/BlockTokenParser.php index caf11f0b72..449a2c05e2 100644 --- a/system/libs/Twig/TokenParser/BlockTokenParser.php +++ b/system/libs/Twig/TokenParser/BlockTokenParser.php @@ -26,16 +26,14 @@ * * {% block title %}{% endblock %} - My Webpage * {% endblock %} - * - * @final */ -class BlockTokenParser extends AbstractTokenParser +final class BlockTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); if ($this->parser->hasBlock($name)) { throw new SyntaxError(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getTemplateLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext()); } @@ -43,9 +41,9 @@ public function parse(Token $token) $this->parser->pushLocalScope(); $this->parser->pushBlockStack($name); - if ($stream->nextIf(Token::BLOCK_END_TYPE)) { + if ($stream->nextIf(/* Token::BLOCK_END_TYPE */ 3)) { $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - if ($token = $stream->nextIf(Token::NAME_TYPE)) { + if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) { $value = $token->getValue(); if ($value != $name) { @@ -57,7 +55,7 @@ public function parse(Token $token) new PrintNode($this->parser->getExpressionParser()->parseExpression(), $lineno), ]); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $block->setNode('body', $body); $this->parser->popBlockStack(); diff --git a/system/libs/Twig/TokenParser/DoTokenParser.php b/system/libs/Twig/TokenParser/DoTokenParser.php index e1eae10f23..e5a07d69b8 100644 --- a/system/libs/Twig/TokenParser/DoTokenParser.php +++ b/system/libs/Twig/TokenParser/DoTokenParser.php @@ -16,16 +16,14 @@ /** * Evaluates an expression, discarding the returned value. - * - * @final */ -class DoTokenParser extends AbstractTokenParser +final class DoTokenParser extends AbstractTokenParser { public function parse(Token $token) { $expr = $this->parser->getExpressionParser()->parseExpression(); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3); return new DoNode($expr, $token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/EmbedTokenParser.php b/system/libs/Twig/TokenParser/EmbedTokenParser.php index 973ff2e45b..83a545e7ba 100644 --- a/system/libs/Twig/TokenParser/EmbedTokenParser.php +++ b/system/libs/Twig/TokenParser/EmbedTokenParser.php @@ -18,10 +18,8 @@ /** * Embeds a template. - * - * @final */ -class EmbedTokenParser extends IncludeTokenParser +final class EmbedTokenParser extends IncludeTokenParser { public function parse(Token $token) { @@ -31,19 +29,19 @@ public function parse(Token $token) list($variables, $only, $ignoreMissing) = $this->parseArguments(); - $parentToken = $fakeParentToken = new Token(Token::STRING_TYPE, '__parent__', $token->getLine()); + $parentToken = $fakeParentToken = new Token(/* Token::STRING_TYPE */ 7, '__parent__', $token->getLine()); if ($parent instanceof ConstantExpression) { - $parentToken = new Token(Token::STRING_TYPE, $parent->getAttribute('value'), $token->getLine()); + $parentToken = new Token(/* Token::STRING_TYPE */ 7, $parent->getAttribute('value'), $token->getLine()); } elseif ($parent instanceof NameExpression) { - $parentToken = new Token(Token::NAME_TYPE, $parent->getAttribute('name'), $token->getLine()); + $parentToken = new Token(/* Token::NAME_TYPE */ 5, $parent->getAttribute('name'), $token->getLine()); } // inject a fake parent to make the parent() function work $stream->injectTokens([ - new Token(Token::BLOCK_START_TYPE, '', $token->getLine()), - new Token(Token::NAME_TYPE, 'extends', $token->getLine()), + new Token(/* Token::BLOCK_START_TYPE */ 1, '', $token->getLine()), + new Token(/* Token::NAME_TYPE */ 5, 'extends', $token->getLine()), $parentToken, - new Token(Token::BLOCK_END_TYPE, '', $token->getLine()), + new Token(/* Token::BLOCK_END_TYPE */ 3, '', $token->getLine()), ]); $module = $this->parser->parse($stream, [$this, 'decideBlockEnd'], true); @@ -55,7 +53,7 @@ public function parse(Token $token) $this->parser->embedTemplate($module); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new EmbedNode($module->getTemplateName(), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/ExtendsTokenParser.php b/system/libs/Twig/TokenParser/ExtendsTokenParser.php index e66789a7bd..a44980fbc7 100644 --- a/system/libs/Twig/TokenParser/ExtendsTokenParser.php +++ b/system/libs/Twig/TokenParser/ExtendsTokenParser.php @@ -20,10 +20,8 @@ * Extends a template by another one. * * {% extends "base.html" %} - * - * @final */ -class ExtendsTokenParser extends AbstractTokenParser +final class ExtendsTokenParser extends AbstractTokenParser { public function parse(Token $token) { diff --git a/system/libs/Twig/TokenParser/FilterTokenParser.php b/system/libs/Twig/TokenParser/FilterTokenParser.php index dc07dcfa41..5f66c58296 100644 --- a/system/libs/Twig/TokenParser/FilterTokenParser.php +++ b/system/libs/Twig/TokenParser/FilterTokenParser.php @@ -24,25 +24,30 @@ * This text becomes uppercase * {% endfilter %} * - * @final + * @deprecated since Twig 2.9, to be removed in 3.0 (use the "apply" tag instead) */ -class FilterTokenParser extends AbstractTokenParser +final class FilterTokenParser extends AbstractTokenParser { public function parse(Token $token) { + $stream = $this->parser->getStream(); + $lineno = $token->getLine(); + + @trigger_error(sprintf('The "filter" tag in "%s" at line %d is deprecated since Twig 2.9, use the "apply" tag instead.', $stream->getSourceContext()->getName(), $lineno), \E_USER_DEPRECATED); + $name = $this->parser->getVarName(); - $ref = new BlockReferenceExpression(new ConstantExpression($name, $token->getLine()), null, $token->getLine(), $this->getTag()); + $ref = new BlockReferenceExpression(new ConstantExpression($name, $lineno), null, $lineno, $this->getTag()); $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag()); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); - $block = new BlockNode($name, $body, $token->getLine()); + $block = new BlockNode($name, $body, $lineno); $this->parser->setBlock($name, $block); - return new PrintNode($filter, $token->getLine(), $this->getTag()); + return new PrintNode($filter, $lineno, $this->getTag()); } public function decideBlockEnd(Token $token) diff --git a/system/libs/Twig/TokenParser/FlushTokenParser.php b/system/libs/Twig/TokenParser/FlushTokenParser.php index b25524fa8d..70f433939b 100644 --- a/system/libs/Twig/TokenParser/FlushTokenParser.php +++ b/system/libs/Twig/TokenParser/FlushTokenParser.php @@ -18,14 +18,12 @@ * Flushes the output to the client. * * @see flush() - * - * @final */ -class FlushTokenParser extends AbstractTokenParser +final class FlushTokenParser extends AbstractTokenParser { public function parse(Token $token) { - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3); return new FlushNode($token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/ForTokenParser.php b/system/libs/Twig/TokenParser/ForTokenParser.php index 69278d98ed..a7987d95d9 100644 --- a/system/libs/Twig/TokenParser/ForTokenParser.php +++ b/system/libs/Twig/TokenParser/ForTokenParser.php @@ -18,6 +18,7 @@ use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\ForNode; +use Twig\Node\Node; use Twig\Token; use Twig\TokenStream; @@ -29,33 +30,33 @@ *
  • {{ user.username|e }}
  • * {% endfor %} * - * - * @final */ -class ForTokenParser extends AbstractTokenParser +final class ForTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $targets = $this->parser->getExpressionParser()->parseAssignmentExpression(); - $stream->expect(Token::OPERATOR_TYPE, 'in'); + $stream->expect(/* Token::OPERATOR_TYPE */ 8, 'in'); $seq = $this->parser->getExpressionParser()->parseExpression(); $ifexpr = null; - if ($stream->nextIf(Token::NAME_TYPE, 'if')) { + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'if')) { + @trigger_error(sprintf('Using an "if" condition on "for" tag in "%s" at line %d is deprecated since Twig 2.10.0, use a "filter" filter or an "if" condition inside the "for" body instead (if your condition depends on a variable updated inside the loop).', $stream->getSourceContext()->getName(), $lineno), \E_USER_DEPRECATED); + $ifexpr = $this->parser->getExpressionParser()->parseExpression(); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideForFork']); if ('else' == $stream->next()->getValue()) { - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $else = $this->parser->subparse([$this, 'decideForEnd'], true); } else { $else = null; } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); if (\count($targets) > 1) { $keyTarget = $targets->getNode(0); @@ -87,7 +88,7 @@ public function decideForEnd(Token $token) } // the loop variable cannot be used in the condition - protected function checkLoopUsageCondition(TokenStream $stream, \Twig_NodeInterface $node) + private function checkLoopUsageCondition(TokenStream $stream, Node $node) { if ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression && 'loop' == $node->getNode('node')->getAttribute('name')) { throw new SyntaxError('The "loop" variable cannot be used in a looping condition.', $node->getTemplateLine(), $stream->getSourceContext()); @@ -104,7 +105,7 @@ protected function checkLoopUsageCondition(TokenStream $stream, \Twig_NodeInterf // check usage of non-defined loop-items // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include) - protected function checkLoopUsageBody(TokenStream $stream, \Twig_NodeInterface $node) + private function checkLoopUsageBody(TokenStream $stream, Node $node) { if ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression && 'loop' == $node->getNode('node')->getAttribute('name')) { $attribute = $node->getNode('attribute'); diff --git a/system/libs/Twig/TokenParser/FromTokenParser.php b/system/libs/Twig/TokenParser/FromTokenParser.php index 4cce650d61..dd49f2fd33 100644 --- a/system/libs/Twig/TokenParser/FromTokenParser.php +++ b/system/libs/Twig/TokenParser/FromTokenParser.php @@ -11,7 +11,6 @@ namespace Twig\TokenParser; -use Twig\Error\SyntaxError; use Twig\Node\Expression\AssignNameExpression; use Twig\Node\ImportNode; use Twig\Token; @@ -20,44 +19,38 @@ * Imports macros. * * {% from 'forms.html' import forms %} - * - * @final */ -class FromTokenParser extends AbstractTokenParser +final class FromTokenParser extends AbstractTokenParser { public function parse(Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); $stream = $this->parser->getStream(); - $stream->expect(Token::NAME_TYPE, 'import'); + $stream->expect(/* Token::NAME_TYPE */ 5, 'import'); $targets = []; do { - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); $alias = $name; if ($stream->nextIf('as')) { - $alias = $stream->expect(Token::NAME_TYPE)->getValue(); + $alias = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); } $targets[$name] = $alias; - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } while (true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $var = new AssignNameExpression($this->parser->getVarName(), $token->getLine()); - $node = new ImportNode($macro, $var, $token->getLine(), $this->getTag()); + $node = new ImportNode($macro, $var, $token->getLine(), $this->getTag(), $this->parser->isMainScope()); foreach ($targets as $name => $alias) { - if ($this->parser->isReservedMacroName($name)) { - throw new SyntaxError(sprintf('"%s" cannot be an imported macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()); - } - - $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $var); + $this->parser->addImportedSymbol('function', $alias, 'macro_'.$name, $var); } return $node; diff --git a/system/libs/Twig/TokenParser/IfTokenParser.php b/system/libs/Twig/TokenParser/IfTokenParser.php index 2631a20cec..8ad99f0745 100644 --- a/system/libs/Twig/TokenParser/IfTokenParser.php +++ b/system/libs/Twig/TokenParser/IfTokenParser.php @@ -27,17 +27,15 @@ * {% endfor %} * * {% endif %} - * - * @final */ -class IfTokenParser extends AbstractTokenParser +final class IfTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $expr = $this->parser->getExpressionParser()->parseExpression(); $stream = $this->parser->getStream(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideIfFork']); $tests = [$expr, $body]; $else = null; @@ -46,13 +44,13 @@ public function parse(Token $token) while (!$end) { switch ($stream->next()->getValue()) { case 'else': - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $else = $this->parser->subparse([$this, 'decideIfEnd']); break; case 'elseif': $expr = $this->parser->getExpressionParser()->parseExpression(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideIfFork']); $tests[] = $expr; $tests[] = $body; @@ -67,7 +65,7 @@ public function parse(Token $token) } } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new IfNode(new Node($tests), $else, $lineno, $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/ImportTokenParser.php b/system/libs/Twig/TokenParser/ImportTokenParser.php index 88395b9248..b5674c1998 100644 --- a/system/libs/Twig/TokenParser/ImportTokenParser.php +++ b/system/libs/Twig/TokenParser/ImportTokenParser.php @@ -19,21 +19,19 @@ * Imports macros. * * {% import 'forms.html' as forms %} - * - * @final */ -class ImportTokenParser extends AbstractTokenParser +final class ImportTokenParser extends AbstractTokenParser { public function parse(Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); - $this->parser->getStream()->expect(Token::NAME_TYPE, 'as'); - $var = new AssignNameExpression($this->parser->getStream()->expect(Token::NAME_TYPE)->getValue(), $token->getLine()); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5, 'as'); + $var = new AssignNameExpression($this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5)->getValue(), $token->getLine()); + $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->addImportedSymbol('template', $var->getAttribute('name')); - return new ImportNode($macro, $var, $token->getLine(), $this->getTag()); + return new ImportNode($macro, $var, $token->getLine(), $this->getTag(), $this->parser->isMainScope()); } public function getTag() diff --git a/system/libs/Twig/TokenParser/IncludeTokenParser.php b/system/libs/Twig/TokenParser/IncludeTokenParser.php index 57aa4cf41a..e1e95da3d3 100644 --- a/system/libs/Twig/TokenParser/IncludeTokenParser.php +++ b/system/libs/Twig/TokenParser/IncludeTokenParser.php @@ -38,23 +38,23 @@ protected function parseArguments() $stream = $this->parser->getStream(); $ignoreMissing = false; - if ($stream->nextIf(Token::NAME_TYPE, 'ignore')) { - $stream->expect(Token::NAME_TYPE, 'missing'); + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'ignore')) { + $stream->expect(/* Token::NAME_TYPE */ 5, 'missing'); $ignoreMissing = true; } $variables = null; - if ($stream->nextIf(Token::NAME_TYPE, 'with')) { + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'with')) { $variables = $this->parser->getExpressionParser()->parseExpression(); } $only = false; - if ($stream->nextIf(Token::NAME_TYPE, 'only')) { + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'only')) { $only = true; } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return [$variables, $only, $ignoreMissing]; } diff --git a/system/libs/Twig/TokenParser/MacroTokenParser.php b/system/libs/Twig/TokenParser/MacroTokenParser.php index a0d66e7bea..d267387672 100644 --- a/system/libs/Twig/TokenParser/MacroTokenParser.php +++ b/system/libs/Twig/TokenParser/MacroTokenParser.php @@ -23,23 +23,21 @@ * {% macro input(name, value, type, size) %} * * {% endmacro %} - * - * @final */ -class MacroTokenParser extends AbstractTokenParser +final class MacroTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); $arguments = $this->parser->getExpressionParser()->parseArguments(true, true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->pushLocalScope(); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - if ($token = $stream->nextIf(Token::NAME_TYPE)) { + if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) { $value = $token->getValue(); if ($value != $name) { @@ -47,7 +45,7 @@ public function parse(Token $token) } } $this->parser->popLocalScope(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->setMacro($name, new MacroNode($name, new BodyNode([$body]), $arguments, $lineno, $this->getTag())); diff --git a/system/libs/Twig/TokenParser/SandboxTokenParser.php b/system/libs/Twig/TokenParser/SandboxTokenParser.php index 0f3ad9e3e6..1f57987947 100644 --- a/system/libs/Twig/TokenParser/SandboxTokenParser.php +++ b/system/libs/Twig/TokenParser/SandboxTokenParser.php @@ -25,17 +25,15 @@ * {% endsandbox %} * * @see https://twig.symfony.com/doc/api.html#sandbox-extension for details - * - * @final */ -class SandboxTokenParser extends AbstractTokenParser +final class SandboxTokenParser extends AbstractTokenParser { public function parse(Token $token) { $stream = $this->parser->getStream(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); // in a sandbox tag, only include tags are allowed if (!$body instanceof IncludeNode) { diff --git a/system/libs/Twig/TokenParser/SetTokenParser.php b/system/libs/Twig/TokenParser/SetTokenParser.php index eebebc6985..82fee26aed 100644 --- a/system/libs/Twig/TokenParser/SetTokenParser.php +++ b/system/libs/Twig/TokenParser/SetTokenParser.php @@ -24,10 +24,8 @@ * {% set foo = 'foo' ~ 'bar' %} * {% set foo, bar = 'foo', 'bar' %} * {% set foo %}Some content{% endset %} - * - * @final */ -class SetTokenParser extends AbstractTokenParser +final class SetTokenParser extends AbstractTokenParser { public function parse(Token $token) { @@ -36,10 +34,10 @@ public function parse(Token $token) $names = $this->parser->getExpressionParser()->parseAssignmentExpression(); $capture = false; - if ($stream->nextIf(Token::OPERATOR_TYPE, '=')) { + if ($stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) { $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); if (\count($names) !== \count($values)) { throw new SyntaxError('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); @@ -51,10 +49,10 @@ public function parse(Token $token) throw new SyntaxError('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $values = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); } return new SetNode($capture, $names, $values, $lineno, $this->getTag()); diff --git a/system/libs/Twig/TokenParser/SpacelessTokenParser.php b/system/libs/Twig/TokenParser/SpacelessTokenParser.php index 5b5656bc64..a609c2f7e2 100644 --- a/system/libs/Twig/TokenParser/SpacelessTokenParser.php +++ b/system/libs/Twig/TokenParser/SpacelessTokenParser.php @@ -24,17 +24,20 @@ * {% endspaceless %} * {# output will be
    foo
    #} * - * @final + * @deprecated since Twig 2.7, to be removed in 3.0 (use the "spaceless" filter with the "apply" tag instead) */ -class SpacelessTokenParser extends AbstractTokenParser +final class SpacelessTokenParser extends AbstractTokenParser { public function parse(Token $token) { + $stream = $this->parser->getStream(); $lineno = $token->getLine(); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + @trigger_error(sprintf('The spaceless tag in "%s" at line %d is deprecated since Twig 2.7, use the "spaceless" filter with the "apply" tag instead.', $stream->getSourceContext()->getName(), $lineno), \E_USER_DEPRECATED); + + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideSpacelessEnd'], true); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new SpacelessNode($body, $lineno, $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/TokenParserInterface.php b/system/libs/Twig/TokenParser/TokenParserInterface.php index 4b603b213f..6f34106f24 100644 --- a/system/libs/Twig/TokenParser/TokenParserInterface.php +++ b/system/libs/Twig/TokenParser/TokenParserInterface.php @@ -12,6 +12,7 @@ namespace Twig\TokenParser; use Twig\Error\SyntaxError; +use Twig\Node\Node; use Twig\Parser; use Twig\Token; @@ -30,7 +31,7 @@ public function setParser(Parser $parser); /** * Parses a token and returns a node. * - * @return \Twig_NodeInterface + * @return Node * * @throws SyntaxError */ diff --git a/system/libs/Twig/TokenParser/UseTokenParser.php b/system/libs/Twig/TokenParser/UseTokenParser.php index d2e39aabee..266efe5d98 100644 --- a/system/libs/Twig/TokenParser/UseTokenParser.php +++ b/system/libs/Twig/TokenParser/UseTokenParser.php @@ -27,10 +27,8 @@ * {% block content %}{% endblock %} * * @see https://twig.symfony.com/doc/templates.html#horizontal-reuse for details. - * - * @final */ -class UseTokenParser extends AbstractTokenParser +final class UseTokenParser extends AbstractTokenParser { public function parse(Token $token) { @@ -44,22 +42,22 @@ public function parse(Token $token) $targets = []; if ($stream->nextIf('with')) { do { - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); $alias = $name; if ($stream->nextIf('as')) { - $alias = $stream->expect(Token::NAME_TYPE)->getValue(); + $alias = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); } $targets[$name] = new ConstantExpression($alias, -1); - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } while (true); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->addTrait(new Node(['template' => $template, 'targets' => new Node($targets)])); diff --git a/system/libs/Twig/TokenParser/WithTokenParser.php b/system/libs/Twig/TokenParser/WithTokenParser.php index 411e2b4a13..c184fd75eb 100644 --- a/system/libs/Twig/TokenParser/WithTokenParser.php +++ b/system/libs/Twig/TokenParser/WithTokenParser.php @@ -18,10 +18,8 @@ * Creates a nested scope. * * @author Fabien Potencier - * - * @final */ -class WithTokenParser extends AbstractTokenParser +final class WithTokenParser extends AbstractTokenParser { public function parse(Token $token) { @@ -29,16 +27,16 @@ public function parse(Token $token) $variables = null; $only = false; - if (!$stream->test(Token::BLOCK_END_TYPE)) { + if (!$stream->test(/* Token::BLOCK_END_TYPE */ 3)) { $variables = $this->parser->getExpressionParser()->parseExpression(); - $only = $stream->nextIf(Token::NAME_TYPE, 'only'); + $only = (bool) $stream->nextIf(/* Token::NAME_TYPE */ 5, 'only'); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideWithEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new WithNode($body, $variables, $only, $token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenStream.php b/system/libs/Twig/TokenStream.php index 4597816959..3fb9e86e3d 100644 --- a/system/libs/Twig/TokenStream.php +++ b/system/libs/Twig/TokenStream.php @@ -17,38 +17,18 @@ /** * Represents a token stream. * - * @final - * * @author Fabien Potencier */ -class TokenStream +final class TokenStream { - protected $tokens; - protected $current = 0; - protected $filename; - + private $tokens; + private $current = 0; private $source; - /** - * @param array $tokens An array of tokens - * @param string|null $name The name of the template which tokens are associated with - * @param string|null $source The source code associated with the tokens - */ - public function __construct(array $tokens, $name = null, $source = null) + public function __construct(array $tokens, Source $source = null) { - if (!$name instanceof Source) { - if (null !== $name || null !== $source) { - @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a \Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - } - $this->source = new Source($source, $name); - } else { - $this->source = $name; - } - $this->tokens = $tokens; - - // deprecated, not used anymore, to be removed in 2.0 - $this->filename = $this->source->getName(); + $this->source = $source ?: new Source('', ''); } public function __toString() @@ -63,10 +43,8 @@ public function injectTokens(array $tokens) /** * Sets the pointer to the next token and returns the old one. - * - * @return Token */ - public function next() + public function next(): Token { if (!isset($this->tokens[++$this->current])) { throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source); @@ -89,10 +67,8 @@ public function nextIf($primary, $secondary = null) /** * Tests a token and returns it or throws a syntax error. - * - * @return Token */ - public function expect($type, $value = null, $message = null) + public function expect($type, $value = null, string $message = null): Token { $token = $this->tokens[$this->current]; if (!$token->test($type, $value)) { @@ -113,12 +89,8 @@ public function expect($type, $value = null, $message = null) /** * Looks at the next token. - * - * @param int $number - * - * @return Token */ - public function look($number = 1) + public function look(int $number = 1): Token { if (!isset($this->tokens[$this->current + $number])) { throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source); @@ -129,70 +101,31 @@ public function look($number = 1) /** * Tests the current token. - * - * @return bool */ - public function test($primary, $secondary = null) + public function test($primary, $secondary = null): bool { return $this->tokens[$this->current]->test($primary, $secondary); } /** * Checks if end of stream was reached. - * - * @return bool */ - public function isEOF() + public function isEOF(): bool { - return Token::EOF_TYPE === $this->tokens[$this->current]->getType(); + return /* Token::EOF_TYPE */ -1 === $this->tokens[$this->current]->getType(); } - /** - * @return Token - */ - public function getCurrent() + public function getCurrent(): Token { return $this->tokens[$this->current]; } - /** - * Gets the name associated with this stream (null if not defined). - * - * @return string|null - * - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->source->getName(); - } - - /** - * Gets the source code associated with this stream. - * - * @return string - * - * @internal Don't use this as it might be empty depending on the environment configuration - * - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getSource() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->source->getCode(); - } - /** * Gets the source associated with this stream. * - * @return Source - * * @internal */ - public function getSourceContext() + public function getSourceContext(): Source { return $this->source; } diff --git a/system/libs/Twig/Twig/BaseNodeVisitor.php b/system/libs/Twig/Twig/BaseNodeVisitor.php index fe99b25889..f44b02c513 100644 --- a/system/libs/Twig/Twig/BaseNodeVisitor.php +++ b/system/libs/Twig/Twig/BaseNodeVisitor.php @@ -4,7 +4,10 @@ class_exists('Twig\NodeVisitor\AbstractNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_BaseNodeVisitor" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\AbstractNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\AbstractNodeVisitor" instead */ class Twig_BaseNodeVisitor extends AbstractNodeVisitor { } diff --git a/system/libs/Twig/Twig/Cache/Filesystem.php b/system/libs/Twig/Twig/Cache/Filesystem.php index ce957583e0..29dacd4201 100644 --- a/system/libs/Twig/Twig/Cache/Filesystem.php +++ b/system/libs/Twig/Twig/Cache/Filesystem.php @@ -4,7 +4,10 @@ class_exists('Twig\Cache\FilesystemCache'); -if (\false) { +@trigger_error('Using the "Twig_Cache_Filesystem" class is deprecated since Twig version 2.7, use "Twig\Cache\FilesystemCache" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Cache\FilesystemCache" instead */ class Twig_Cache_Filesystem extends FilesystemCache { } diff --git a/system/libs/Twig/Twig/Cache/Null.php b/system/libs/Twig/Twig/Cache/Null.php index 5cfa40ec29..1ea298a781 100644 --- a/system/libs/Twig/Twig/Cache/Null.php +++ b/system/libs/Twig/Twig/Cache/Null.php @@ -4,7 +4,10 @@ class_exists('Twig\Cache\NullCache'); -if (\false) { +@trigger_error('Using the "Twig_Cache_Null" class is deprecated since Twig version 2.7, use "Twig\Cache\NullCache" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Cache\NullCache" instead */ class Twig_Cache_Null extends NullCache { } diff --git a/system/libs/Twig/Twig/CacheInterface.php b/system/libs/Twig/Twig/CacheInterface.php index 5d251dbd3c..764d82452f 100644 --- a/system/libs/Twig/Twig/CacheInterface.php +++ b/system/libs/Twig/Twig/CacheInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Cache\CacheInterface'); -if (\false) { +@trigger_error('Using the "Twig_CacheInterface" class is deprecated since Twig version 2.7, use "Twig\Cache\CacheInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Cache\CacheInterface" instead */ class Twig_CacheInterface extends CacheInterface { } diff --git a/system/libs/Twig/Twig/Compiler.php b/system/libs/Twig/Twig/Compiler.php index 8d3811d2b8..f8fa4244a8 100644 --- a/system/libs/Twig/Twig/Compiler.php +++ b/system/libs/Twig/Twig/Compiler.php @@ -4,7 +4,10 @@ class_exists('Twig\Compiler'); -if (\false) { +@trigger_error('Using the "Twig_Compiler" class is deprecated since Twig version 2.7, use "Twig\Compiler" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Compiler" instead */ class Twig_Compiler extends Compiler { } diff --git a/system/libs/Twig/Twig/ContainerRuntimeLoader.php b/system/libs/Twig/Twig/ContainerRuntimeLoader.php index b1f32f6823..6be55ffc77 100644 --- a/system/libs/Twig/Twig/ContainerRuntimeLoader.php +++ b/system/libs/Twig/Twig/ContainerRuntimeLoader.php @@ -4,7 +4,10 @@ class_exists('Twig\RuntimeLoader\ContainerRuntimeLoader'); -if (\false) { +@trigger_error('Using the "Twig_ContainerRuntimeLoader" class is deprecated since Twig version 2.7, use "Twig\RuntimeLoader\ContainerRuntimeLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\RuntimeLoader\ContainerRuntimeLoader" instead */ class Twig_ContainerRuntimeLoader extends ContainerRuntimeLoader { } diff --git a/system/libs/Twig/Twig/Environment.php b/system/libs/Twig/Twig/Environment.php index 8c056366ea..f1b45260ae 100644 --- a/system/libs/Twig/Twig/Environment.php +++ b/system/libs/Twig/Twig/Environment.php @@ -4,7 +4,10 @@ class_exists('Twig\Environment'); -if (\false) { +@trigger_error('Using the "Twig_Environment" class is deprecated since Twig version 2.7, use "Twig\Environment" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Environment" instead */ class Twig_Environment extends Environment { } diff --git a/system/libs/Twig/Twig/Error.php b/system/libs/Twig/Twig/Error.php index 887490ce69..b36f7ca1ee 100644 --- a/system/libs/Twig/Twig/Error.php +++ b/system/libs/Twig/Twig/Error.php @@ -4,7 +4,10 @@ class_exists('Twig\Error\Error'); -if (\false) { +@trigger_error('Using the "Twig_Error" class is deprecated since Twig version 2.7, use "Twig\Error\Error" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\Error" instead */ class Twig_Error extends Error { } diff --git a/system/libs/Twig/Twig/Error/Loader.php b/system/libs/Twig/Twig/Error/Loader.php index 8caca6fd11..d12aa0767e 100644 --- a/system/libs/Twig/Twig/Error/Loader.php +++ b/system/libs/Twig/Twig/Error/Loader.php @@ -4,7 +4,10 @@ class_exists('Twig\Error\LoaderError'); -if (\false) { +@trigger_error('Using the "Twig_Error_Loader" class is deprecated since Twig version 2.7, use "Twig\Error\LoaderError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\LoaderError" instead */ class Twig_Error_Loader extends LoaderError { } diff --git a/system/libs/Twig/Twig/Error/Runtime.php b/system/libs/Twig/Twig/Error/Runtime.php index d45133b897..33d46e7240 100644 --- a/system/libs/Twig/Twig/Error/Runtime.php +++ b/system/libs/Twig/Twig/Error/Runtime.php @@ -4,7 +4,10 @@ class_exists('Twig\Error\RuntimeError'); -if (\false) { +@trigger_error('Using the "Twig_Error_Runtime" class is deprecated since Twig version 2.7, use "Twig\Error\RuntimeError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\RuntimeError" instead */ class Twig_Error_Runtime extends RuntimeError { } diff --git a/system/libs/Twig/Twig/Error/Syntax.php b/system/libs/Twig/Twig/Error/Syntax.php index f5920c6237..0bd2a0f91a 100644 --- a/system/libs/Twig/Twig/Error/Syntax.php +++ b/system/libs/Twig/Twig/Error/Syntax.php @@ -4,7 +4,10 @@ class_exists('Twig\Error\SyntaxError'); -if (\false) { +@trigger_error('Using the "Twig_Error_Syntax" class is deprecated since Twig version 2.7, use "Twig\Error\SyntaxError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\SyntaxError" instead */ class Twig_Error_Syntax extends SyntaxError { } diff --git a/system/libs/Twig/Twig/ExistsLoaderInterface.php b/system/libs/Twig/Twig/ExistsLoaderInterface.php index 3acbf65baa..32f20d4b4d 100644 --- a/system/libs/Twig/Twig/ExistsLoaderInterface.php +++ b/system/libs/Twig/Twig/ExistsLoaderInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Loader\ExistsLoaderInterface'); -if (\false) { +@trigger_error('Using the "Twig_ExistsLoaderInterface" class is deprecated since Twig version 2.7, use "Twig\Loader\ExistsLoaderInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\ExistsLoaderInterface" instead */ class Twig_ExistsLoaderInterface extends ExistsLoaderInterface { } diff --git a/system/libs/Twig/Twig/ExpressionParser.php b/system/libs/Twig/Twig/ExpressionParser.php index 687404d6c8..b3d0a5628e 100644 --- a/system/libs/Twig/Twig/ExpressionParser.php +++ b/system/libs/Twig/Twig/ExpressionParser.php @@ -4,7 +4,10 @@ class_exists('Twig\ExpressionParser'); -if (\false) { +@trigger_error('Using the "Twig_ExpressionParser" class is deprecated since Twig version 2.7, use "Twig\ExpressionParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\ExpressionParser" instead */ class Twig_ExpressionParser extends ExpressionParser { } diff --git a/system/libs/Twig/Twig/Extension.php b/system/libs/Twig/Twig/Extension.php index 1cc8216a5e..865243d66f 100644 --- a/system/libs/Twig/Twig/Extension.php +++ b/system/libs/Twig/Twig/Extension.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\AbstractExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension" class is deprecated since Twig version 2.7, use "Twig\Extension\AbstractExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\AbstractExtension" instead */ class Twig_Extension extends AbstractExtension { } diff --git a/system/libs/Twig/Twig/Extension/Core.php b/system/libs/Twig/Twig/Extension/Core.php index fb5a754767..dd4e86641f 100644 --- a/system/libs/Twig/Twig/Extension/Core.php +++ b/system/libs/Twig/Twig/Extension/Core.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\CoreExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Core" class is deprecated since Twig version 2.7, use "Twig\Extension\CoreExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\CoreExtension" instead */ class Twig_Extension_Core extends CoreExtension { } diff --git a/system/libs/Twig/Twig/Extension/Debug.php b/system/libs/Twig/Twig/Extension/Debug.php index bbb44fe5c6..6b5713ae02 100644 --- a/system/libs/Twig/Twig/Extension/Debug.php +++ b/system/libs/Twig/Twig/Extension/Debug.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\DebugExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Debug" class is deprecated since Twig version 2.7, use "Twig\Extension\DebugExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\DebugExtension" instead */ class Twig_Extension_Debug extends DebugExtension { } diff --git a/system/libs/Twig/Twig/Extension/Escaper.php b/system/libs/Twig/Twig/Extension/Escaper.php index 8d15df4279..7a306e3498 100644 --- a/system/libs/Twig/Twig/Extension/Escaper.php +++ b/system/libs/Twig/Twig/Extension/Escaper.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\EscaperExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Escaper" class is deprecated since Twig version 2.7, use "Twig\Extension\EscaperExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\EscaperExtension" instead */ class Twig_Extension_Escaper extends EscaperExtension { } diff --git a/system/libs/Twig/Twig/Extension/GlobalsInterface.php b/system/libs/Twig/Twig/Extension/GlobalsInterface.php index 9bfcca4ede..f4778bff2c 100644 --- a/system/libs/Twig/Twig/Extension/GlobalsInterface.php +++ b/system/libs/Twig/Twig/Extension/GlobalsInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\GlobalsInterface'); -if (\false) { +@trigger_error('Using the "Twig_Extension_GlobalsInterface" class is deprecated since Twig version 2.7, use "Twig\Extension\GlobalsInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\GlobalsInterface" instead */ class Twig_Extension_GlobalsInterface extends GlobalsInterface { } diff --git a/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php b/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php index 6fbf1ba5bf..cba863d50e 100644 --- a/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php +++ b/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\InitRuntimeInterface'); -if (\false) { +@trigger_error('Using the "Twig_Extension_InitRuntimeInterface" class is deprecated since Twig version 2.7, use "Twig\Extension\InitRuntimeInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\InitRuntimeInterface" instead */ class Twig_Extension_InitRuntimeInterface extends InitRuntimeInterface { } diff --git a/system/libs/Twig/Twig/Extension/Optimizer.php b/system/libs/Twig/Twig/Extension/Optimizer.php index 14802deb1b..8f084797bb 100644 --- a/system/libs/Twig/Twig/Extension/Optimizer.php +++ b/system/libs/Twig/Twig/Extension/Optimizer.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\OptimizerExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Optimizer" class is deprecated since Twig version 2.7, use "Twig\Extension\OptimizerExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\OptimizerExtension" instead */ class Twig_Extension_Optimizer extends OptimizerExtension { } diff --git a/system/libs/Twig/Twig/Extension/Profiler.php b/system/libs/Twig/Twig/Extension/Profiler.php index 086b34f63d..bcc4919837 100644 --- a/system/libs/Twig/Twig/Extension/Profiler.php +++ b/system/libs/Twig/Twig/Extension/Profiler.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\ProfilerExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Profiler" class is deprecated since Twig version 2.7, use "Twig\Extension\ProfilerExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\ProfilerExtension" instead */ class Twig_Extension_Profiler extends ProfilerExtension { } diff --git a/system/libs/Twig/Twig/Extension/Sandbox.php b/system/libs/Twig/Twig/Extension/Sandbox.php index 2b8a1514f0..7594019d32 100644 --- a/system/libs/Twig/Twig/Extension/Sandbox.php +++ b/system/libs/Twig/Twig/Extension/Sandbox.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\SandboxExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Sandbox" class is deprecated since Twig version 2.7, use "Twig\Extension\SandboxExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\SandboxExtension" instead */ class Twig_Extension_Sandbox extends SandboxExtension { } diff --git a/system/libs/Twig/Twig/Extension/Staging.php b/system/libs/Twig/Twig/Extension/Staging.php index 7681b4985a..6a0ebdfd7c 100644 --- a/system/libs/Twig/Twig/Extension/Staging.php +++ b/system/libs/Twig/Twig/Extension/Staging.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\StagingExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Staging" class is deprecated since Twig version 2.7, use "Twig\Extension\StagingExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\StagingExtension" instead */ class Twig_Extension_Staging extends StagingExtension { } diff --git a/system/libs/Twig/Twig/Extension/StringLoader.php b/system/libs/Twig/Twig/Extension/StringLoader.php index 5ce2407e06..5f4d594634 100644 --- a/system/libs/Twig/Twig/Extension/StringLoader.php +++ b/system/libs/Twig/Twig/Extension/StringLoader.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\StringLoaderExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_StringLoader" class is deprecated since Twig version 2.7, use "Twig\Extension\StringLoaderExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\StringLoaderExtension" instead */ class Twig_Extension_StringLoader extends StringLoaderExtension { } diff --git a/system/libs/Twig/Twig/ExtensionInterface.php b/system/libs/Twig/Twig/ExtensionInterface.php index 3ef2ed5868..2554c80f03 100644 --- a/system/libs/Twig/Twig/ExtensionInterface.php +++ b/system/libs/Twig/Twig/ExtensionInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Extension\ExtensionInterface'); -if (\false) { +@trigger_error('Using the "Twig_ExtensionInterface" class is deprecated since Twig version 2.7, use "Twig\Extension\ExtensionInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\ExtensionInterface" instead */ class Twig_ExtensionInterface extends ExtensionInterface { } diff --git a/system/libs/Twig/Twig/ExtensionSet.php b/system/libs/Twig/Twig/ExtensionSet.php new file mode 100644 index 0000000000..54dcc72a01 --- /dev/null +++ b/system/libs/Twig/Twig/ExtensionSet.php @@ -0,0 +1,14 @@ + - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface -{ - protected $options; - protected $arguments = []; - - public function __construct(array $options = []) - { - $this->options = array_merge([ - 'needs_environment' => false, - 'needs_context' => false, - 'pre_escape' => null, - 'preserves_safety' => null, - 'callable' => null, - ], $options); - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Node $filterArgs) - { - if (isset($this->options['is_safe'])) { - return $this->options['is_safe']; - } - - if (isset($this->options['is_safe_callback'])) { - return \call_user_func($this->options['is_safe_callback'], $filterArgs); - } - } - - public function getPreservesSafety() - { - return $this->options['preserves_safety']; - } - - public function getPreEscape() - { - return $this->options['pre_escape']; - } - - public function getCallable() +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TwigFilter" instead */ + class Twig_Filter extends TwigFilter { - return $this->options['callable']; } } diff --git a/system/libs/Twig/Twig/Function.php b/system/libs/Twig/Twig/Function.php index 6646e746f5..f345b27735 100644 --- a/system/libs/Twig/Twig/Function.php +++ b/system/libs/Twig/Twig/Function.php @@ -1,76 +1,14 @@ - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface -{ - protected $options; - protected $arguments = []; - - public function __construct(array $options = []) - { - $this->options = array_merge([ - 'needs_environment' => false, - 'needs_context' => false, - 'callable' => null, - ], $options); - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Node $functionArgs) - { - if (isset($this->options['is_safe'])) { - return $this->options['is_safe']; - } - - if (isset($this->options['is_safe_callback'])) { - return \call_user_func($this->options['is_safe_callback'], $functionArgs); - } - - return []; - } - - public function getCallable() +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TwigFunction" instead */ + class Twig_Function extends TwigFunction { - return $this->options['callable']; } } diff --git a/system/libs/Twig/Twig/Lexer.php b/system/libs/Twig/Twig/Lexer.php index 00d74cc47a..fde2d91989 100644 --- a/system/libs/Twig/Twig/Lexer.php +++ b/system/libs/Twig/Twig/Lexer.php @@ -4,7 +4,10 @@ class_exists('Twig\Lexer'); -if (\false) { +@trigger_error('Using the "Twig_Lexer" class is deprecated since Twig version 2.7, use "Twig\Lexer" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Lexer" instead */ class Twig_Lexer extends Lexer { } diff --git a/system/libs/Twig/Twig/Loader/Array.php b/system/libs/Twig/Twig/Loader/Array.php index 13f915c95f..9f6a918cb6 100644 --- a/system/libs/Twig/Twig/Loader/Array.php +++ b/system/libs/Twig/Twig/Loader/Array.php @@ -4,7 +4,10 @@ class_exists('Twig\Loader\ArrayLoader'); -if (\false) { +@trigger_error('Using the "Twig_Loader_Array" class is deprecated since Twig version 2.7, use "Twig\Loader\ArrayLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\ArrayLoader" instead */ class Twig_Loader_Array extends ArrayLoader { } diff --git a/system/libs/Twig/Twig/Loader/Chain.php b/system/libs/Twig/Twig/Loader/Chain.php index 885b37a7fe..39efb8e514 100644 --- a/system/libs/Twig/Twig/Loader/Chain.php +++ b/system/libs/Twig/Twig/Loader/Chain.php @@ -4,7 +4,10 @@ class_exists('Twig\Loader\ChainLoader'); -if (\false) { +@trigger_error('Using the "Twig_Loader_Chain" class is deprecated since Twig version 2.7, use "Twig\Loader\ChainLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\ChainLoader" instead */ class Twig_Loader_Chain extends ChainLoader { } diff --git a/system/libs/Twig/Twig/Loader/Filesystem.php b/system/libs/Twig/Twig/Loader/Filesystem.php index c3eae7d840..e528fc25a1 100644 --- a/system/libs/Twig/Twig/Loader/Filesystem.php +++ b/system/libs/Twig/Twig/Loader/Filesystem.php @@ -4,7 +4,10 @@ class_exists('Twig\Loader\FilesystemLoader'); -if (\false) { +@trigger_error('Using the "Twig_Loader_Filesystem" class is deprecated since Twig version 2.7, use "Twig\Loader\FilesystemLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\FilesystemLoader" instead */ class Twig_Loader_Filesystem extends FilesystemLoader { } diff --git a/system/libs/Twig/Twig/LoaderInterface.php b/system/libs/Twig/Twig/LoaderInterface.php index db515bbdf4..835cf1e3ba 100644 --- a/system/libs/Twig/Twig/LoaderInterface.php +++ b/system/libs/Twig/Twig/LoaderInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Loader\LoaderInterface'); -if (\false) { +@trigger_error('Using the "Twig_LoaderInterface" class is deprecated since Twig version 2.7, use "Twig\Loader\LoaderInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\LoaderInterface" instead */ class Twig_LoaderInterface extends LoaderInterface { } diff --git a/system/libs/Twig/Twig/Markup.php b/system/libs/Twig/Twig/Markup.php index 9a38046654..2902ffd640 100644 --- a/system/libs/Twig/Twig/Markup.php +++ b/system/libs/Twig/Twig/Markup.php @@ -4,7 +4,10 @@ class_exists('Twig\Markup'); -if (\false) { +@trigger_error('Using the "Twig_Markup" class is deprecated since Twig version 2.7, use "Twig\Markup" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Markup" instead */ class Twig_Markup extends Markup { } diff --git a/system/libs/Twig/Twig/Node.php b/system/libs/Twig/Twig/Node.php index 78cc271198..7aa38a8078 100644 --- a/system/libs/Twig/Twig/Node.php +++ b/system/libs/Twig/Twig/Node.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Node'); -if (\false) { +@trigger_error('Using the "Twig_Node" class is deprecated since Twig version 2.7, use "Twig\Node\Node" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Node" instead */ class Twig_Node extends Node { } diff --git a/system/libs/Twig/Twig/Node/AutoEscape.php b/system/libs/Twig/Twig/Node/AutoEscape.php index 7d308fff5c..5fe0e38087 100644 --- a/system/libs/Twig/Twig/Node/AutoEscape.php +++ b/system/libs/Twig/Twig/Node/AutoEscape.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\AutoEscapeNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_AutoEscape" class is deprecated since Twig version 2.7, use "Twig\Node\AutoEscapeNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\AutoEscapeNode" instead */ class Twig_Node_AutoEscape extends AutoEscapeNode { } diff --git a/system/libs/Twig/Twig/Node/Block.php b/system/libs/Twig/Twig/Node/Block.php index 33cd088f3b..f9c10d6b19 100644 --- a/system/libs/Twig/Twig/Node/Block.php +++ b/system/libs/Twig/Twig/Node/Block.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\BlockNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Block" class is deprecated since Twig version 2.7, use "Twig\Node\BlockNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\BlockNode" instead */ class Twig_Node_Block extends BlockNode { } diff --git a/system/libs/Twig/Twig/Node/BlockReference.php b/system/libs/Twig/Twig/Node/BlockReference.php index 55d2d00b2b..9cd18d31e2 100644 --- a/system/libs/Twig/Twig/Node/BlockReference.php +++ b/system/libs/Twig/Twig/Node/BlockReference.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\BlockReferenceNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_BlockReference" class is deprecated since Twig version 2.7, use "Twig\Node\BlockReferenceNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\BlockReferenceNode" instead */ class Twig_Node_BlockReference extends BlockReferenceNode { } diff --git a/system/libs/Twig/Twig/Node/Body.php b/system/libs/Twig/Twig/Node/Body.php index 0874364d19..54523c4128 100644 --- a/system/libs/Twig/Twig/Node/Body.php +++ b/system/libs/Twig/Twig/Node/Body.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\BodyNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Body" class is deprecated since Twig version 2.7, use "Twig\Node\BodyNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\BodyNode" instead */ class Twig_Node_Body extends BodyNode { } diff --git a/system/libs/Twig/Twig/Node/CheckSecurity.php b/system/libs/Twig/Twig/Node/CheckSecurity.php index e42ce689a8..a9cd58a633 100644 --- a/system/libs/Twig/Twig/Node/CheckSecurity.php +++ b/system/libs/Twig/Twig/Node/CheckSecurity.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\CheckSecurityNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_CheckSecurity" class is deprecated since Twig version 2.7, use "Twig\Node\CheckSecurityNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\CheckSecurityNode" instead */ class Twig_Node_CheckSecurity extends CheckSecurityNode { } diff --git a/system/libs/Twig/Twig/Node/Deprecated.php b/system/libs/Twig/Twig/Node/Deprecated.php index 19b7f8b4aa..02c5a335f6 100644 --- a/system/libs/Twig/Twig/Node/Deprecated.php +++ b/system/libs/Twig/Twig/Node/Deprecated.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\DeprecatedNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Deprecated" class is deprecated since Twig version 2.7, use "Twig\Node\DeprecatedNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\DeprecatedNode" instead */ class Twig_Node_Deprecated extends DeprecatedNode { } diff --git a/system/libs/Twig/Twig/Node/Do.php b/system/libs/Twig/Twig/Node/Do.php index f538be2f05..eb831aa44d 100644 --- a/system/libs/Twig/Twig/Node/Do.php +++ b/system/libs/Twig/Twig/Node/Do.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\DoNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Do" class is deprecated since Twig version 2.7, use "Twig\Node\DoNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\DoNode" instead */ class Twig_Node_Do extends DoNode { } diff --git a/system/libs/Twig/Twig/Node/Embed.php b/system/libs/Twig/Twig/Node/Embed.php index 2dfe266a31..1458749ba5 100644 --- a/system/libs/Twig/Twig/Node/Embed.php +++ b/system/libs/Twig/Twig/Node/Embed.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\EmbedNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Embed" class is deprecated since Twig version 2.7, use "Twig\Node\EmbedNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\EmbedNode" instead */ class Twig_Node_Embed extends EmbedNode { } diff --git a/system/libs/Twig/Twig/Node/Expression.php b/system/libs/Twig/Twig/Node/Expression.php index 9775df02f8..384db48494 100644 --- a/system/libs/Twig/Twig/Node/Expression.php +++ b/system/libs/Twig/Twig/Node/Expression.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\AbstractExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\AbstractExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\AbstractExpression" instead */ class Twig_Node_Expression extends AbstractExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Array.php b/system/libs/Twig/Twig/Node/Expression/Array.php index dec28df7bf..71c8764c15 100644 --- a/system/libs/Twig/Twig/Node/Expression/Array.php +++ b/system/libs/Twig/Twig/Node/Expression/Array.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\ArrayExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Array" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ArrayExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ArrayExpression" instead */ class Twig_Node_Expression_Array extends ArrayExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/AssignName.php b/system/libs/Twig/Twig/Node/Expression/AssignName.php index cf2e91cf0f..92aca63dd2 100644 --- a/system/libs/Twig/Twig/Node/Expression/AssignName.php +++ b/system/libs/Twig/Twig/Node/Expression/AssignName.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\AssignNameExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_AssignName" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\AssignNameExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\AssignNameExpression" instead */ class Twig_Node_Expression_AssignName extends AssignNameExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary.php b/system/libs/Twig/Twig/Node/Expression/Binary.php index 6591c4223f..f1446b9308 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\AbstractBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\AbstractBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\AbstractBinary" instead */ class Twig_Node_Expression_Binary extends AbstractBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Add.php b/system/libs/Twig/Twig/Node/Expression/Binary/Add.php index 895a2fce3b..8adc266749 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Add.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Add.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\AddBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Add" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\AddBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\AddBinary" instead */ class Twig_Node_Expression_Binary_Add extends AddBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/And.php b/system/libs/Twig/Twig/Node/Expression/Binary/And.php index 738c6aa178..9471956e13 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/And.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/And.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\AndBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_And" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\AndBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\AndBinary" instead */ class Twig_Node_Expression_Binary_And extends AndBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php index 8649e899b2..04e4be7a2a 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\BitwiseAndBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_BitwiseAnd" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\BitwiseAndBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\BitwiseAndBinary" instead */ class Twig_Node_Expression_Binary_BitwiseAnd extends BitwiseAndBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php index 473fba270a..866b00b128 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\BitwiseOrBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_BitwiseOr" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\BitwiseOrBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\BitwiseOrBinary" instead */ class Twig_Node_Expression_Binary_BitwiseOr extends BitwiseOrBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php index 3fedc369ec..9e6a88e45d 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\BitwiseXorBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_BitwiseXor" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\BitwiseXorBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\BitwiseXorBinary" instead */ class Twig_Node_Expression_Binary_BitwiseXor extends BitwiseXorBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php b/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php index 8d7b723c1f..b7595c24bf 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\ConcatBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Concat" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\ConcatBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\ConcatBinary" instead */ class Twig_Node_Expression_Binary_Concat extends ConcatBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Div.php b/system/libs/Twig/Twig/Node/Expression/Binary/Div.php index ce19322f02..a485e0d9b8 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Div.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Div.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\DivBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Div" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\DivBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\DivBinary" instead */ class Twig_Node_Expression_Binary_Div extends DivBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php b/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php index b6d3e3c430..c0c233225e 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\EndsWithBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_EndsWith" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\EndsWithBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\EndsWithBinary" instead */ class Twig_Node_Expression_Binary_EndsWith extends EndsWithBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php b/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php index e737b61e8a..7a26c0976c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\EqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Equal" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\EqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\EqualBinary" instead */ class Twig_Node_Expression_Binary_Equal extends EqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php b/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php index 7119351fcf..c4e1ee9c3e 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\FloorDivBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_FloorDiv" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\FloorDivBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\FloorDivBinary" instead */ class Twig_Node_Expression_Binary_FloorDiv extends FloorDivBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php b/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php index 183301d7e0..90af5fb017 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\GreaterBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Greater" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\GreaterBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\GreaterBinary" instead */ class Twig_Node_Expression_Binary_Greater extends GreaterBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php b/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php index f47999bd84..5eadde8d98 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\GreaterEqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_GreaterEqual" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\GreaterEqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\GreaterEqualBinary" instead */ class Twig_Node_Expression_Binary_GreaterEqual extends GreaterEqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/In.php b/system/libs/Twig/Twig/Node/Expression/Binary/In.php index 7a13d9544b..bfec34779f 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/In.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/In.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\InBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_In" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\InBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\InBinary" instead */ class Twig_Node_Expression_Binary_In extends InBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Less.php b/system/libs/Twig/Twig/Node/Expression/Binary/Less.php index 7295179a4c..564997879c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Less.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Less.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\LessBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Less" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\LessBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\LessBinary" instead */ class Twig_Node_Expression_Binary_Less extends LessBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php b/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php index cbfbc8c7ad..c05fe647b7 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\LessEqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_LessEqual" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\LessEqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\LessEqualBinary" instead */ class Twig_Node_Expression_Binary_LessEqual extends LessEqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php b/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php index 5209083ebd..d646190c10 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\MatchesBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Matches" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\MatchesBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\MatchesBinary" instead */ class Twig_Node_Expression_Binary_Matches extends MatchesBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php b/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php index aec59e3bae..f806d38d39 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\ModBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Mod" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\ModBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\ModBinary" instead */ class Twig_Node_Expression_Binary_Mod extends ModBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php b/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php index 850934a100..4a4528285d 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\MulBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Mul" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\MulBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\MulBinary" instead */ class Twig_Node_Expression_Binary_Mul extends MulBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php b/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php index 842c8bc8b8..d59708f03f 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\NotEqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_NotEqual" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\NotEqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\NotEqualBinary" instead */ class Twig_Node_Expression_Binary_NotEqual extends NotEqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php b/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php index 7d3c1288f3..cb830e9ae1 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\NotInBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_NotIn" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\NotInBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\NotInBinary" instead */ class Twig_Node_Expression_Binary_NotIn extends NotInBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Or.php b/system/libs/Twig/Twig/Node/Expression/Binary/Or.php index 3a38faed6b..edd2058c58 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Or.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Or.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\OrBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Or" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\OrBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\OrBinary" instead */ class Twig_Node_Expression_Binary_Or extends OrBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Power.php b/system/libs/Twig/Twig/Node/Expression/Binary/Power.php index 7eafca80f2..71986ca631 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Power.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Power.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\PowerBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Power" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\PowerBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\PowerBinary" instead */ class Twig_Node_Expression_Binary_Power extends PowerBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Range.php b/system/libs/Twig/Twig/Node/Expression/Binary/Range.php index 01564142af..4197cdf948 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Range.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Range.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\RangeBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Range" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\RangeBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\RangeBinary" instead */ class Twig_Node_Expression_Binary_Range extends RangeBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php b/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php index f72ea49ca9..8bf8b37428 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\StartsWithBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_StartsWith" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\StartsWithBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\StartsWithBinary" instead */ class Twig_Node_Expression_Binary_StartsWith extends StartsWithBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php b/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php index f596da703c..a1832765db 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Binary\SubBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Sub" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\SubBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\SubBinary" instead */ class Twig_Node_Expression_Binary_Sub extends SubBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/BlockReference.php b/system/libs/Twig/Twig/Node/Expression/BlockReference.php index 8ea2350a39..fc8441f271 100644 --- a/system/libs/Twig/Twig/Node/Expression/BlockReference.php +++ b/system/libs/Twig/Twig/Node/Expression/BlockReference.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\BlockReferenceExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_BlockReference" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\BlockReferenceExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\BlockReferenceExpression" instead */ class Twig_Node_Expression_BlockReference extends BlockReferenceExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Call.php b/system/libs/Twig/Twig/Node/Expression/Call.php index 019ddf7b85..ddb5741c54 100644 --- a/system/libs/Twig/Twig/Node/Expression/Call.php +++ b/system/libs/Twig/Twig/Node/Expression/Call.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\CallExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Call" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\CallExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\CallExpression" instead */ class Twig_Node_Expression_Call extends CallExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Conditional.php b/system/libs/Twig/Twig/Node/Expression/Conditional.php index 308df26f0f..a50ed3a100 100644 --- a/system/libs/Twig/Twig/Node/Expression/Conditional.php +++ b/system/libs/Twig/Twig/Node/Expression/Conditional.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\ConditionalExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Conditional" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ConditionalExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ConditionalExpression" instead */ class Twig_Node_Expression_Conditional extends ConditionalExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Constant.php b/system/libs/Twig/Twig/Node/Expression/Constant.php index 435ccdd79f..9141e25895 100644 --- a/system/libs/Twig/Twig/Node/Expression/Constant.php +++ b/system/libs/Twig/Twig/Node/Expression/Constant.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\ConstantExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Constant" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ConstantExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ConstantExpression" instead */ class Twig_Node_Expression_Constant extends ConstantExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Filter.php b/system/libs/Twig/Twig/Node/Expression/Filter.php index 85705715e9..f8be806ec7 100644 --- a/system/libs/Twig/Twig/Node/Expression/Filter.php +++ b/system/libs/Twig/Twig/Node/Expression/Filter.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\FilterExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Filter" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\FilterExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\FilterExpression" instead */ class Twig_Node_Expression_Filter extends FilterExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Filter/Default.php b/system/libs/Twig/Twig/Node/Expression/Filter/Default.php index 9688743f28..d00151e2ae 100644 --- a/system/libs/Twig/Twig/Node/Expression/Filter/Default.php +++ b/system/libs/Twig/Twig/Node/Expression/Filter/Default.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Filter\DefaultFilter'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Filter_Default" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Filter\DefaultFilter" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Filter\DefaultFilter" instead */ class Twig_Node_Expression_Filter_Default extends DefaultFilter { } diff --git a/system/libs/Twig/Twig/Node/Expression/Function.php b/system/libs/Twig/Twig/Node/Expression/Function.php index 5d408e46ae..42886119aa 100644 --- a/system/libs/Twig/Twig/Node/Expression/Function.php +++ b/system/libs/Twig/Twig/Node/Expression/Function.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\FunctionExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Function" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\FunctionExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\FunctionExpression" instead */ class Twig_Node_Expression_Function extends FunctionExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/GetAttr.php b/system/libs/Twig/Twig/Node/Expression/GetAttr.php index 7b99eb376d..1a69bede00 100644 --- a/system/libs/Twig/Twig/Node/Expression/GetAttr.php +++ b/system/libs/Twig/Twig/Node/Expression/GetAttr.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\GetAttrExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_GetAttr" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\GetAttrExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\GetAttrExpression" instead */ class Twig_Node_Expression_GetAttr extends GetAttrExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/MethodCall.php b/system/libs/Twig/Twig/Node/Expression/MethodCall.php index 5b0cef8c43..6e7718cef7 100644 --- a/system/libs/Twig/Twig/Node/Expression/MethodCall.php +++ b/system/libs/Twig/Twig/Node/Expression/MethodCall.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\MethodCallExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_MethodCall" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\MethodCallExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\MethodCallExpression" instead */ class Twig_Node_Expression_MethodCall extends MethodCallExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Name.php b/system/libs/Twig/Twig/Node/Expression/Name.php index 3b41ff9fc7..0cdc45bf51 100644 --- a/system/libs/Twig/Twig/Node/Expression/Name.php +++ b/system/libs/Twig/Twig/Node/Expression/Name.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\NameExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Name" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\NameExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\NameExpression" instead */ class Twig_Node_Expression_Name extends NameExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php b/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php index 89d6bf6a50..2905cdb4fe 100644 --- a/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php +++ b/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\NullCoalesceExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_NullCoalesce" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\NullCoalesceExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\NullCoalesceExpression" instead */ class Twig_Node_Expression_NullCoalesce extends NullCoalesceExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Parent.php b/system/libs/Twig/Twig/Node/Expression/Parent.php index 236c79fd4d..8e9c860399 100644 --- a/system/libs/Twig/Twig/Node/Expression/Parent.php +++ b/system/libs/Twig/Twig/Node/Expression/Parent.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\ParentExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Parent" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ParentExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ParentExpression" instead */ class Twig_Node_Expression_Parent extends ParentExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/TempName.php b/system/libs/Twig/Twig/Node/Expression/TempName.php index e77ebe06bb..93b4226897 100644 --- a/system/libs/Twig/Twig/Node/Expression/TempName.php +++ b/system/libs/Twig/Twig/Node/Expression/TempName.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\TempNameExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_TempName" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\TempNameExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\TempNameExpression" instead */ class Twig_Node_Expression_TempName extends TempNameExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test.php b/system/libs/Twig/Twig/Node/Expression/Test.php index 9c300ba3f5..d91340feef 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test.php +++ b/system/libs/Twig/Twig/Node/Expression/Test.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\TestExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\TestExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\TestExpression" instead */ class Twig_Node_Expression_Test extends TestExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Constant.php b/system/libs/Twig/Twig/Node/Expression/Test/Constant.php index bc796ec356..d02d901606 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Constant.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Constant.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Test\ConstantTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Constant" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\ConstantTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\ConstantTest" instead */ class Twig_Node_Expression_Test_Constant extends ConstantTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Defined.php b/system/libs/Twig/Twig/Node/Expression/Test/Defined.php index 759cb491a3..739621325f 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Defined.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Defined.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Test\DefinedTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Defined" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\DefinedTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\DefinedTest" instead */ class Twig_Node_Expression_Test_Defined extends DefinedTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php b/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php index c999e9e174..ba6dc32cdf 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Test\DivisiblebyTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Divisibleby" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\DivisiblebyTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\DivisiblebyTest" instead */ class Twig_Node_Expression_Test_Divisibleby extends DivisiblebyTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Even.php b/system/libs/Twig/Twig/Node/Expression/Test/Even.php index a751079dba..267563328e 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Even.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Even.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Test\EvenTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Even" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\EvenTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\EvenTest" instead */ class Twig_Node_Expression_Test_Even extends EvenTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Null.php b/system/libs/Twig/Twig/Node/Expression/Test/Null.php index 404360ee2e..b948cd8c0c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Null.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Null.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Test\NullTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Null" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\NullTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\NullTest" instead */ class Twig_Node_Expression_Test_Null extends NullTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Odd.php b/system/libs/Twig/Twig/Node/Expression/Test/Odd.php index 7a06ac59a5..bd6f69d5fe 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Odd.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Odd.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Test\OddTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Odd" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\OddTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\OddTest" instead */ class Twig_Node_Expression_Test_Odd extends OddTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php b/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php index c937d71215..5e73d10f94 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Test\SameasTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Sameas" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\SameasTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\SameasTest" instead */ class Twig_Node_Expression_Test_Sameas extends SameasTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary.php b/system/libs/Twig/Twig/Node/Expression/Unary.php index 1969d2c766..56f01cf0cc 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Unary\AbstractUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\AbstractUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\AbstractUnary" instead */ class Twig_Node_Expression_Unary extends AbstractUnary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php b/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php index e6c25a01c4..34d14a675d 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Unary\NegUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary_Neg" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\NegUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\NegUnary" instead */ class Twig_Node_Expression_Unary_Neg extends NegUnary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary/Not.php b/system/libs/Twig/Twig/Node/Expression/Unary/Not.php index 669105f368..1cdb6867ef 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary/Not.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary/Not.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Unary\NotUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary_Not" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\NotUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\NotUnary" instead */ class Twig_Node_Expression_Unary_Not extends NotUnary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php b/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php index 4e2bb504df..bbd33e0d0b 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\Expression\Unary\PosUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary_Pos" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\PosUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\PosUnary" instead */ class Twig_Node_Expression_Unary_Pos extends PosUnary { } diff --git a/system/libs/Twig/Twig/Node/Flush.php b/system/libs/Twig/Twig/Node/Flush.php index 92af475b74..57ac85bb06 100644 --- a/system/libs/Twig/Twig/Node/Flush.php +++ b/system/libs/Twig/Twig/Node/Flush.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\FlushNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Flush" class is deprecated since Twig version 2.7, use "Twig\Node\FlushNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\FlushNode" instead */ class Twig_Node_Flush extends FlushNode { } diff --git a/system/libs/Twig/Twig/Node/For.php b/system/libs/Twig/Twig/Node/For.php index c72aa782b1..21add730c2 100644 --- a/system/libs/Twig/Twig/Node/For.php +++ b/system/libs/Twig/Twig/Node/For.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\ForNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_For" class is deprecated since Twig version 2.7, use "Twig\Node\ForNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ForNode" instead */ class Twig_Node_For extends ForNode { } diff --git a/system/libs/Twig/Twig/Node/ForLoop.php b/system/libs/Twig/Twig/Node/ForLoop.php index 5b21005270..e7a01d0054 100644 --- a/system/libs/Twig/Twig/Node/ForLoop.php +++ b/system/libs/Twig/Twig/Node/ForLoop.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\ForLoopNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_ForLoop" class is deprecated since Twig version 2.7, use "Twig\Node\ForLoopNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ForLoopNode" instead */ class Twig_Node_ForLoop extends ForLoopNode { } diff --git a/system/libs/Twig/Twig/Node/If.php b/system/libs/Twig/Twig/Node/If.php index de884b345d..9df299640e 100644 --- a/system/libs/Twig/Twig/Node/If.php +++ b/system/libs/Twig/Twig/Node/If.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\IfNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_If" class is deprecated since Twig version 2.7, use "Twig\Node\IfNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\IfNode" instead */ class Twig_Node_If extends IfNode { } diff --git a/system/libs/Twig/Twig/Node/Import.php b/system/libs/Twig/Twig/Node/Import.php index 9d3892a68c..98cf162469 100644 --- a/system/libs/Twig/Twig/Node/Import.php +++ b/system/libs/Twig/Twig/Node/Import.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\ImportNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Import" class is deprecated since Twig version 2.7, use "Twig\Node\ImportNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ImportNode" instead */ class Twig_Node_Import extends ImportNode { } diff --git a/system/libs/Twig/Twig/Node/Include.php b/system/libs/Twig/Twig/Node/Include.php index f43d203bc1..87f7307ccc 100644 --- a/system/libs/Twig/Twig/Node/Include.php +++ b/system/libs/Twig/Twig/Node/Include.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\IncludeNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Include" class is deprecated since Twig version 2.7, use "Twig\Node\IncludeNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\IncludeNode" instead */ class Twig_Node_Include extends IncludeNode { } diff --git a/system/libs/Twig/Twig/Node/Macro.php b/system/libs/Twig/Twig/Node/Macro.php index 8d2389dfcf..ccff374e25 100644 --- a/system/libs/Twig/Twig/Node/Macro.php +++ b/system/libs/Twig/Twig/Node/Macro.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\MacroNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Macro" class is deprecated since Twig version 2.7, use "Twig\Node\MacroNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\MacroNode" instead */ class Twig_Node_Macro extends MacroNode { } diff --git a/system/libs/Twig/Twig/Node/Module.php b/system/libs/Twig/Twig/Node/Module.php index ca5276750f..b488ddebc6 100644 --- a/system/libs/Twig/Twig/Node/Module.php +++ b/system/libs/Twig/Twig/Node/Module.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\ModuleNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Module" class is deprecated since Twig version 2.7, use "Twig\Node\ModuleNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ModuleNode" instead */ class Twig_Node_Module extends ModuleNode { } diff --git a/system/libs/Twig/Twig/Node/Print.php b/system/libs/Twig/Twig/Node/Print.php index 65a605e7e7..c2487ef15a 100644 --- a/system/libs/Twig/Twig/Node/Print.php +++ b/system/libs/Twig/Twig/Node/Print.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\PrintNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Print" class is deprecated since Twig version 2.7, use "Twig\Node\PrintNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\PrintNode" instead */ class Twig_Node_Print extends PrintNode { } diff --git a/system/libs/Twig/Twig/Node/Sandbox.php b/system/libs/Twig/Twig/Node/Sandbox.php index 3ff57ff7d9..6acbd7c6be 100644 --- a/system/libs/Twig/Twig/Node/Sandbox.php +++ b/system/libs/Twig/Twig/Node/Sandbox.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\SandboxNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Sandbox" class is deprecated since Twig version 2.7, use "Twig\Node\SandboxNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SandboxNode" instead */ class Twig_Node_Sandbox extends SandboxNode { } diff --git a/system/libs/Twig/Twig/Node/SandboxedPrint.php b/system/libs/Twig/Twig/Node/SandboxedPrint.php index a223eeb2ca..050138930d 100644 --- a/system/libs/Twig/Twig/Node/SandboxedPrint.php +++ b/system/libs/Twig/Twig/Node/SandboxedPrint.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\SandboxedPrintNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_SandboxedPrint" class is deprecated since Twig version 2.7, use "Twig\Node\SandboxedPrintNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SandboxedPrintNode" instead */ class Twig_Node_SandboxedPrint extends SandboxedPrintNode { } diff --git a/system/libs/Twig/Twig/Node/Set.php b/system/libs/Twig/Twig/Node/Set.php index 5b0a6d4f1c..e0ec5feba6 100644 --- a/system/libs/Twig/Twig/Node/Set.php +++ b/system/libs/Twig/Twig/Node/Set.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\SetNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Set" class is deprecated since Twig version 2.7, use "Twig\Node\SetNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SetNode" instead */ class Twig_Node_Set extends SetNode { } diff --git a/system/libs/Twig/Twig/Node/Spaceless.php b/system/libs/Twig/Twig/Node/Spaceless.php index 0ae024c3f5..b0fb4b28dc 100644 --- a/system/libs/Twig/Twig/Node/Spaceless.php +++ b/system/libs/Twig/Twig/Node/Spaceless.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\SpacelessNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Spaceless" class is deprecated since Twig version 2.7, use "Twig\Node\SpacelessNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SpacelessNode" instead */ class Twig_Node_Spaceless extends SpacelessNode { } diff --git a/system/libs/Twig/Twig/Node/Text.php b/system/libs/Twig/Twig/Node/Text.php index 1a3f956fff..d9237f9912 100644 --- a/system/libs/Twig/Twig/Node/Text.php +++ b/system/libs/Twig/Twig/Node/Text.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\TextNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Text" class is deprecated since Twig version 2.7, use "Twig\Node\TextNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\TextNode" instead */ class Twig_Node_Text extends TextNode { } diff --git a/system/libs/Twig/Twig/Node/With.php b/system/libs/Twig/Twig/Node/With.php index 266240d6ac..599cb61f6f 100644 --- a/system/libs/Twig/Twig/Node/With.php +++ b/system/libs/Twig/Twig/Node/With.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\WithNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_With" class is deprecated since Twig version 2.7, use "Twig\Node\WithNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\WithNode" instead */ class Twig_Node_With extends WithNode { } diff --git a/system/libs/Twig/Twig/NodeCaptureInterface.php b/system/libs/Twig/Twig/NodeCaptureInterface.php index 696f4a59f8..2335eb88e9 100644 --- a/system/libs/Twig/Twig/NodeCaptureInterface.php +++ b/system/libs/Twig/Twig/NodeCaptureInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\NodeCaptureInterface'); -if (\false) { +@trigger_error('Using the "Twig_NodeCaptureInterface" class is deprecated since Twig version 2.7, use "Twig\Node\NodeCaptureInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\NodeCaptureInterface" instead */ class Twig_NodeCaptureInterface extends NodeCaptureInterface { } diff --git a/system/libs/Twig/Twig/NodeOutputInterface.php b/system/libs/Twig/Twig/NodeOutputInterface.php index 54009c0a67..a9da48ed2f 100644 --- a/system/libs/Twig/Twig/NodeOutputInterface.php +++ b/system/libs/Twig/Twig/NodeOutputInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Node\NodeOutputInterface'); -if (\false) { +@trigger_error('Using the "Twig_NodeOutputInterface" class is deprecated since Twig version 2.7, use "Twig\Node\NodeOutputInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\NodeOutputInterface" instead */ class Twig_NodeOutputInterface extends NodeOutputInterface { } diff --git a/system/libs/Twig/Twig/NodeTraverser.php b/system/libs/Twig/Twig/NodeTraverser.php index 1e52a6a271..bd76ca87a2 100644 --- a/system/libs/Twig/Twig/NodeTraverser.php +++ b/system/libs/Twig/Twig/NodeTraverser.php @@ -4,7 +4,10 @@ class_exists('Twig\NodeTraverser'); -if (\false) { +@trigger_error('Using the "Twig_NodeTraverser" class is deprecated since Twig version 2.7, use "Twig\NodeTraverser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeTraverser" instead */ class Twig_NodeTraverser extends NodeTraverser { } diff --git a/system/libs/Twig/Twig/NodeVisitor/Escaper.php b/system/libs/Twig/Twig/NodeVisitor/Escaper.php index d8b877ed16..0eb91c415a 100644 --- a/system/libs/Twig/Twig/NodeVisitor/Escaper.php +++ b/system/libs/Twig/Twig/NodeVisitor/Escaper.php @@ -4,7 +4,10 @@ class_exists('Twig\NodeVisitor\EscaperNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_Escaper" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\EscaperNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\EscaperNodeVisitor" instead */ class Twig_NodeVisitor_Escaper extends EscaperNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitor/Optimizer.php b/system/libs/Twig/Twig/NodeVisitor/Optimizer.php index 7e6a77ae4d..173e2a5841 100644 --- a/system/libs/Twig/Twig/NodeVisitor/Optimizer.php +++ b/system/libs/Twig/Twig/NodeVisitor/Optimizer.php @@ -4,7 +4,10 @@ class_exists('Twig\NodeVisitor\OptimizerNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_Optimizer" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\OptimizerNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\OptimizerNodeVisitor" instead */ class Twig_NodeVisitor_Optimizer extends OptimizerNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php b/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php index bee2523026..28750c93c9 100644 --- a/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php +++ b/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php @@ -4,7 +4,10 @@ class_exists('Twig\NodeVisitor\SafeAnalysisNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_SafeAnalysis" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\SafeAnalysisNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\SafeAnalysisNodeVisitor" instead */ class Twig_NodeVisitor_SafeAnalysis extends SafeAnalysisNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitor/Sandbox.php b/system/libs/Twig/Twig/NodeVisitor/Sandbox.php index 1f21c2d258..c259a5688e 100644 --- a/system/libs/Twig/Twig/NodeVisitor/Sandbox.php +++ b/system/libs/Twig/Twig/NodeVisitor/Sandbox.php @@ -4,7 +4,10 @@ class_exists('Twig\NodeVisitor\SandboxNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_Sandbox" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\SandboxNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\SandboxNodeVisitor" instead */ class Twig_NodeVisitor_Sandbox extends SandboxNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitorInterface.php b/system/libs/Twig/Twig/NodeVisitorInterface.php index 809b4176eb..d0127b5994 100644 --- a/system/libs/Twig/Twig/NodeVisitorInterface.php +++ b/system/libs/Twig/Twig/NodeVisitorInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\NodeVisitor\NodeVisitorInterface'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitorInterface" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\NodeVisitorInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\NodeVisitorInterface" instead */ class Twig_NodeVisitorInterface extends NodeVisitorInterface { } diff --git a/system/libs/Twig/Twig/Parser.php b/system/libs/Twig/Twig/Parser.php index cf56f69688..2254e2d028 100644 --- a/system/libs/Twig/Twig/Parser.php +++ b/system/libs/Twig/Twig/Parser.php @@ -4,7 +4,10 @@ class_exists('Twig\Parser'); -if (\false) { +@trigger_error('Using the "Twig_Parser" class is deprecated since Twig version 2.7, use "Twig\Parser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Parser" instead */ class Twig_Parser extends Parser { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Base.php b/system/libs/Twig/Twig/Profiler/Dumper/Base.php index 5bcb1ba633..2db69b29de 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Base.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Base.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\Dumper\BaseDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Base" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\BaseDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\BaseDumper" instead */ class Twig_Profiler_Dumper_Base extends BaseDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php b/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php index cf09413fce..bc7814b2f7 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\Dumper\BlackfireDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Blackfire" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\BlackfireDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\BlackfireDumper" instead */ class Twig_Profiler_Dumper_Blackfire extends BlackfireDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Html.php b/system/libs/Twig/Twig/Profiler/Dumper/Html.php index 36dc573a5b..5d20aefa8c 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Html.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Html.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\Dumper\HtmlDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Html" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\HtmlDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\HtmlDumper" instead */ class Twig_Profiler_Dumper_Html extends HtmlDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Text.php b/system/libs/Twig/Twig/Profiler/Dumper/Text.php index 3ff1395363..5f8a12ec84 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Text.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Text.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\Dumper\TextDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Text" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\TextDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\TextDumper" instead */ class Twig_Profiler_Dumper_Text extends TextDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php b/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php index ce25ec4b5d..d37f6872dc 100644 --- a/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php +++ b/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\Node\EnterProfileNode'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Node_EnterProfile" class is deprecated since Twig version 2.7, use "Twig\Profiler\Node\EnterProfileNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Node\EnterProfileNode" instead */ class Twig_Profiler_Node_EnterProfile extends EnterProfileNode { } diff --git a/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php b/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php index 31cc7231c8..2a46cd43a8 100644 --- a/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php +++ b/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\Node\LeaveProfileNode'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Node_LeaveProfile" class is deprecated since Twig version 2.7, use "Twig\Profiler\Node\LeaveProfileNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Node\LeaveProfileNode" instead */ class Twig_Profiler_Node_LeaveProfile extends LeaveProfileNode { } diff --git a/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php b/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php index 463a96bd3a..106be1f2a6 100644 --- a/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php +++ b/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\NodeVisitor\ProfilerNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_NodeVisitor_Profiler" class is deprecated since Twig version 2.7, use "Twig\Profiler\NodeVisitor\ProfilerNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\NodeVisitor\ProfilerNodeVisitor" instead */ class Twig_Profiler_NodeVisitor_Profiler extends ProfilerNodeVisitor { } diff --git a/system/libs/Twig/Twig/Profiler/Profile.php b/system/libs/Twig/Twig/Profiler/Profile.php index bb13c7a11d..421d951503 100644 --- a/system/libs/Twig/Twig/Profiler/Profile.php +++ b/system/libs/Twig/Twig/Profiler/Profile.php @@ -4,7 +4,10 @@ class_exists('Twig\Profiler\Profile'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Profile" class is deprecated since Twig version 2.7, use "Twig\Profiler\Profile" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Profile" instead */ class Twig_Profiler_Profile extends Profile { } diff --git a/system/libs/Twig/Twig/RuntimeLoaderInterface.php b/system/libs/Twig/Twig/RuntimeLoaderInterface.php index f21cde5a90..2e24fb22f6 100644 --- a/system/libs/Twig/Twig/RuntimeLoaderInterface.php +++ b/system/libs/Twig/Twig/RuntimeLoaderInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\RuntimeLoader\RuntimeLoaderInterface'); -if (\false) { +@trigger_error('Using the "Twig_RuntimeLoaderInterface" class is deprecated since Twig version 2.7, use "Twig\RuntimeLoader\RuntimeLoaderInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\RuntimeLoader\RuntimeLoaderInterface" instead */ class Twig_RuntimeLoaderInterface extends RuntimeLoaderInterface { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityError.php b/system/libs/Twig/Twig/Sandbox/SecurityError.php index d018ece1cb..aa588259e9 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityError.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityError" instead */ class Twig_Sandbox_SecurityError extends SecurityError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php index 1a5f9eb2a5..cf3a756c67 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityNotAllowedFilterError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedFilterError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedFilterError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedFilterError" instead */ class Twig_Sandbox_SecurityNotAllowedFilterError extends SecurityNotAllowedFilterError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php index 34e2b2b9a3..ba9976d73f 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityNotAllowedFunctionError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedFunctionError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedFunctionError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedFunctionError" instead */ class Twig_Sandbox_SecurityNotAllowedFunctionError extends SecurityNotAllowedFunctionError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php index c776b1011c..a0bd36fd6b 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityNotAllowedMethodError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedMethodError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedMethodError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedMethodError" instead */ class Twig_Sandbox_SecurityNotAllowedMethodError extends SecurityNotAllowedMethodError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php index a99efeb24e..d970bae968 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityNotAllowedPropertyError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedPropertyError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedPropertyError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedPropertyError" instead */ class Twig_Sandbox_SecurityNotAllowedPropertyError extends SecurityNotAllowedPropertyError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php index 0ffd0f849a..48412c9ea3 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityNotAllowedTagError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedTagError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedTagError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedTagError" instead */ class Twig_Sandbox_SecurityNotAllowedTagError extends SecurityNotAllowedTagError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php b/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php index 41038c430f..3a1223e0c9 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityPolicy'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityPolicy" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityPolicy" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityPolicy" instead */ class Twig_Sandbox_SecurityPolicy extends SecurityPolicy { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php b/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php index f17e6a5e99..aae29910e5 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\Sandbox\SecurityPolicyInterface'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityPolicyInterface" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityPolicyInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityPolicyInterface" instead */ class Twig_Sandbox_SecurityPolicyInterface extends SecurityPolicyInterface { } diff --git a/system/libs/Twig/Twig/SimpleFilter.php b/system/libs/Twig/Twig/SimpleFilter.php index bb830e0f03..d7afd8094b 100644 --- a/system/libs/Twig/Twig/SimpleFilter.php +++ b/system/libs/Twig/Twig/SimpleFilter.php @@ -1,11 +1,26 @@ - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface -{ - protected $options; - protected $arguments = []; +@trigger_error('Using the "Twig_Test" class is deprecated since Twig version 2.7, use "Twig\TwigTest" instead.', \E_USER_DEPRECATED); - public function __construct(array $options = []) +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TwigTest" instead */ + class Twig_Test extends TwigTest { - $this->options = array_merge([ - 'callable' => null, - ], $options); - } - - public function getCallable() - { - return $this->options['callable']; } } diff --git a/system/libs/Twig/Twig/Test/IntegrationTestCase.php b/system/libs/Twig/Twig/Test/IntegrationTestCase.php index e302bdbaf8..f2178f3fb1 100644 --- a/system/libs/Twig/Twig/Test/IntegrationTestCase.php +++ b/system/libs/Twig/Twig/Test/IntegrationTestCase.php @@ -4,7 +4,10 @@ class_exists('Twig\Test\IntegrationTestCase'); -if (\false) { +@trigger_error('Using the "Twig_Test_IntegrationTestCase" class is deprecated since Twig version 2.7, use "Twig\Test\IntegrationTestCase" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Test\IntegrationTestCase" instead */ class Twig_Test_IntegrationTestCase extends IntegrationTestCase { } diff --git a/system/libs/Twig/Twig/Test/NodeTestCase.php b/system/libs/Twig/Twig/Test/NodeTestCase.php index 62aaaaff7d..75a7754992 100644 --- a/system/libs/Twig/Twig/Test/NodeTestCase.php +++ b/system/libs/Twig/Twig/Test/NodeTestCase.php @@ -4,7 +4,10 @@ class_exists('Twig\Test\NodeTestCase'); -if (\false) { +@trigger_error('Using the "Twig_Test_NodeTestCase" class is deprecated since Twig version 2.7, use "Twig\Test\NodeTestCase" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Test\NodeTestCase" instead */ class Twig_Test_NodeTestCase extends NodeTestCase { } diff --git a/system/libs/Twig/Twig/Token.php b/system/libs/Twig/Twig/Token.php index e4d18069eb..e14cf9d3fd 100644 --- a/system/libs/Twig/Twig/Token.php +++ b/system/libs/Twig/Twig/Token.php @@ -4,7 +4,10 @@ class_exists('Twig\Token'); -if (\false) { +@trigger_error('Using the "Twig_Token" class is deprecated since Twig version 2.7, use "Twig\Token" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Token" instead */ class Twig_Token extends Token { } diff --git a/system/libs/Twig/Twig/TokenParser.php b/system/libs/Twig/Twig/TokenParser.php index c0595438ab..8e6557a1e1 100644 --- a/system/libs/Twig/Twig/TokenParser.php +++ b/system/libs/Twig/Twig/TokenParser.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\AbstractTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser" class is deprecated since Twig version 2.7, use "Twig\TokenParser\AbstractTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\AbstractTokenParser" instead */ class Twig_TokenParser extends AbstractTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/AutoEscape.php b/system/libs/Twig/Twig/TokenParser/AutoEscape.php index 3f9e528d2e..4c1b731fb1 100644 --- a/system/libs/Twig/Twig/TokenParser/AutoEscape.php +++ b/system/libs/Twig/Twig/TokenParser/AutoEscape.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\AutoEscapeTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_AutoEscape" class is deprecated since Twig version 2.7, use "Twig\TokenParser\AutoEscapeTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\AutoEscapeTokenParser" instead */ class Twig_TokenParser_AutoEscape extends AutoEscapeTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Block.php b/system/libs/Twig/Twig/TokenParser/Block.php index d2f6877023..346241ef41 100644 --- a/system/libs/Twig/Twig/TokenParser/Block.php +++ b/system/libs/Twig/Twig/TokenParser/Block.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\BlockTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Block" class is deprecated since Twig version 2.7, use "Twig\TokenParser\BlockTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\BlockTokenParser" instead */ class Twig_TokenParser_Block extends BlockTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Deprecated.php b/system/libs/Twig/Twig/TokenParser/Deprecated.php index 9a74fe43e1..32a27d1736 100644 --- a/system/libs/Twig/Twig/TokenParser/Deprecated.php +++ b/system/libs/Twig/Twig/TokenParser/Deprecated.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\DeprecatedTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Deprecated" class is deprecated since Twig version 2.7, use "Twig\TokenParser\DeprecatedTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\DeprecatedTokenParser" instead */ class Twig_TokenParser_Deprecated extends DeprecatedTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Do.php b/system/libs/Twig/Twig/TokenParser/Do.php index 0750e471ec..45fb9d5d72 100644 --- a/system/libs/Twig/Twig/TokenParser/Do.php +++ b/system/libs/Twig/Twig/TokenParser/Do.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\DoTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Do" class is deprecated since Twig version 2.7, use "Twig\TokenParser\DoTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\DoTokenParser" instead */ class Twig_TokenParser_Do extends DoTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Embed.php b/system/libs/Twig/Twig/TokenParser/Embed.php index a60c26734f..4ace2c27af 100644 --- a/system/libs/Twig/Twig/TokenParser/Embed.php +++ b/system/libs/Twig/Twig/TokenParser/Embed.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\EmbedTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Embed" class is deprecated since Twig version 2.7, use "Twig\TokenParser\EmbedTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\EmbedTokenParser" instead */ class Twig_TokenParser_Embed extends EmbedTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Extends.php b/system/libs/Twig/Twig/TokenParser/Extends.php index 79cc2d3a3d..7116a28dbd 100644 --- a/system/libs/Twig/Twig/TokenParser/Extends.php +++ b/system/libs/Twig/Twig/TokenParser/Extends.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\ExtendsTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Extends" class is deprecated since Twig version 2.7, use "Twig\TokenParser\ExtendsTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\ExtendsTokenParser" instead */ class Twig_TokenParser_Extends extends ExtendsTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Filter.php b/system/libs/Twig/Twig/TokenParser/Filter.php index 5110c2344f..f6716e73b4 100644 --- a/system/libs/Twig/Twig/TokenParser/Filter.php +++ b/system/libs/Twig/Twig/TokenParser/Filter.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\FilterTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Filter" class is deprecated since Twig version 2.7, use "Twig\TokenParser\FilterTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\FilterTokenParser" instead */ class Twig_TokenParser_Filter extends FilterTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Flush.php b/system/libs/Twig/Twig/TokenParser/Flush.php index df8be30ddf..3a1c329e1b 100644 --- a/system/libs/Twig/Twig/TokenParser/Flush.php +++ b/system/libs/Twig/Twig/TokenParser/Flush.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\FlushTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Flush" class is deprecated since Twig version 2.7, use "Twig\TokenParser\FlushTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\FlushTokenParser" instead */ class Twig_TokenParser_Flush extends FlushTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/For.php b/system/libs/Twig/Twig/TokenParser/For.php index 596dad785b..9d492cd532 100644 --- a/system/libs/Twig/Twig/TokenParser/For.php +++ b/system/libs/Twig/Twig/TokenParser/For.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\ForTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_For" class is deprecated since Twig version 2.7, use "Twig\TokenParser\ForTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\ForTokenParser" instead */ class Twig_TokenParser_For extends ForTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/From.php b/system/libs/Twig/Twig/TokenParser/From.php index af794be889..76bbcfb4c6 100644 --- a/system/libs/Twig/Twig/TokenParser/From.php +++ b/system/libs/Twig/Twig/TokenParser/From.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\FromTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_From" class is deprecated since Twig version 2.7, use "Twig\TokenParser\FromTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\FromTokenParser" instead */ class Twig_TokenParser_From extends FromTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/If.php b/system/libs/Twig/Twig/TokenParser/If.php index e035c5ed5f..f8ec93dd0e 100644 --- a/system/libs/Twig/Twig/TokenParser/If.php +++ b/system/libs/Twig/Twig/TokenParser/If.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\IfTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_If" class is deprecated since Twig version 2.7, use "Twig\TokenParser\IfTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\IfTokenParser" instead */ class Twig_TokenParser_If extends IfTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Import.php b/system/libs/Twig/Twig/TokenParser/Import.php index 2ee0165368..97cdef27b0 100644 --- a/system/libs/Twig/Twig/TokenParser/Import.php +++ b/system/libs/Twig/Twig/TokenParser/Import.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\ImportTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Import" class is deprecated since Twig version 2.7, use "Twig\TokenParser\ImportTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\ImportTokenParser" instead */ class Twig_TokenParser_Import extends ImportTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Include.php b/system/libs/Twig/Twig/TokenParser/Include.php index 6047c615dd..e5ea32873d 100644 --- a/system/libs/Twig/Twig/TokenParser/Include.php +++ b/system/libs/Twig/Twig/TokenParser/Include.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\IncludeTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Include" class is deprecated since Twig version 2.7, use "Twig\TokenParser\IncludeTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\IncludeTokenParser" instead */ class Twig_TokenParser_Include extends IncludeTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Macro.php b/system/libs/Twig/Twig/TokenParser/Macro.php index 523de8c1c7..c7c8d1f88f 100644 --- a/system/libs/Twig/Twig/TokenParser/Macro.php +++ b/system/libs/Twig/Twig/TokenParser/Macro.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\MacroTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Macro" class is deprecated since Twig version 2.7, use "Twig\TokenParser\MacroTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\MacroTokenParser" instead */ class Twig_TokenParser_Macro extends MacroTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Sandbox.php b/system/libs/Twig/Twig/TokenParser/Sandbox.php index 25684343a1..6136378b43 100644 --- a/system/libs/Twig/Twig/TokenParser/Sandbox.php +++ b/system/libs/Twig/Twig/TokenParser/Sandbox.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\SandboxTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Sandbox" class is deprecated since Twig version 2.7, use "Twig\TokenParser\SandboxTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\SandboxTokenParser" instead */ class Twig_TokenParser_Sandbox extends SandboxTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Set.php b/system/libs/Twig/Twig/TokenParser/Set.php index 03139f61ab..8ee59d05e3 100644 --- a/system/libs/Twig/Twig/TokenParser/Set.php +++ b/system/libs/Twig/Twig/TokenParser/Set.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\SetTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Set" class is deprecated since Twig version 2.7, use "Twig\TokenParser\SetTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\SetTokenParser" instead */ class Twig_TokenParser_Set extends SetTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Spaceless.php b/system/libs/Twig/Twig/TokenParser/Spaceless.php index 92444a0d8e..d313cf9fd6 100644 --- a/system/libs/Twig/Twig/TokenParser/Spaceless.php +++ b/system/libs/Twig/Twig/TokenParser/Spaceless.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\SpacelessTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Spaceless" class is deprecated since Twig version 2.7, use "Twig\TokenParser\SpacelessTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\SpacelessTokenParser" instead */ class Twig_TokenParser_Spaceless extends SpacelessTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Use.php b/system/libs/Twig/Twig/TokenParser/Use.php index c588211eea..0ef0d2a863 100644 --- a/system/libs/Twig/Twig/TokenParser/Use.php +++ b/system/libs/Twig/Twig/TokenParser/Use.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\UseTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Use" class is deprecated since Twig version 2.7, use "Twig\TokenParser\UseTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\UseTokenParser" instead */ class Twig_TokenParser_Use extends UseTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/With.php b/system/libs/Twig/Twig/TokenParser/With.php index 8067cbe6cc..e162097a4b 100644 --- a/system/libs/Twig/Twig/TokenParser/With.php +++ b/system/libs/Twig/Twig/TokenParser/With.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\WithTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_With" class is deprecated since Twig version 2.7, use "Twig\TokenParser\WithTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\WithTokenParser" instead */ class Twig_TokenParser_With extends WithTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParserInterface.php b/system/libs/Twig/Twig/TokenParserInterface.php index 800c971943..b7d392fc3b 100644 --- a/system/libs/Twig/Twig/TokenParserInterface.php +++ b/system/libs/Twig/Twig/TokenParserInterface.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenParser\TokenParserInterface'); -if (\false) { +@trigger_error('Using the "Twig_TokenParserInterface" class is deprecated since Twig version 2.7, use "Twig\TokenParser\TokenParserInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\TokenParserInterface" instead */ class Twig_TokenParserInterface extends TokenParserInterface { } diff --git a/system/libs/Twig/Twig/TokenStream.php b/system/libs/Twig/Twig/TokenStream.php index b1abb80720..f5922b50f1 100644 --- a/system/libs/Twig/Twig/TokenStream.php +++ b/system/libs/Twig/Twig/TokenStream.php @@ -4,7 +4,10 @@ class_exists('Twig\TokenStream'); -if (\false) { +@trigger_error('Using the "Twig_TokenStream" class is deprecated since Twig version 2.7, use "Twig\TokenStream" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenStream" instead */ class Twig_TokenStream extends TokenStream { } diff --git a/system/libs/Twig/Twig/Util/DeprecationCollector.php b/system/libs/Twig/Twig/Util/DeprecationCollector.php index 46fd4ef6bb..62d7506166 100644 --- a/system/libs/Twig/Twig/Util/DeprecationCollector.php +++ b/system/libs/Twig/Twig/Util/DeprecationCollector.php @@ -4,7 +4,10 @@ class_exists('Twig\Util\DeprecationCollector'); -if (\false) { +@trigger_error('Using the "Twig_Util_DeprecationCollector" class is deprecated since Twig version 2.7, use "Twig\Util\DeprecationCollector" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Util\DeprecationCollector" instead */ class Twig_Util_DeprecationCollector extends DeprecationCollector { } diff --git a/system/libs/Twig/Twig/Util/TemplateDirIterator.php b/system/libs/Twig/Twig/Util/TemplateDirIterator.php index f9a1e0be39..d61337e71b 100644 --- a/system/libs/Twig/Twig/Util/TemplateDirIterator.php +++ b/system/libs/Twig/Twig/Util/TemplateDirIterator.php @@ -4,7 +4,10 @@ class_exists('Twig\Util\TemplateDirIterator'); -if (\false) { +@trigger_error('Using the "Twig_Util_TemplateDirIterator" class is deprecated since Twig version 2.7, use "Twig\Util\TemplateDirIterator" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Util\TemplateDirIterator" instead */ class Twig_Util_TemplateDirIterator extends TemplateDirIterator { } diff --git a/system/libs/Twig/TwigFilter.php b/system/libs/Twig/TwigFilter.php index 089a6d1b88..4351cf1397 100644 --- a/system/libs/Twig/TwigFilter.php +++ b/system/libs/Twig/TwigFilter.php @@ -11,24 +11,38 @@ namespace Twig; +use Twig\Node\Expression\FilterExpression; use Twig\Node\Node; /** * Represents a template filter. * - * @final + * @final since Twig 2.4.0 * * @author Fabien Potencier + * + * @see https://twig.symfony.com/doc/templates.html#filters */ class TwigFilter { - protected $name; - protected $callable; - protected $options; - protected $arguments = []; - - public function __construct($name, $callable, array $options = []) + private $name; + private $callable; + private $options; + private $arguments = []; + + /** + * Creates a template filter. + * + * @param string $name Name of this filter + * @param callable|null $callable A callable implementing the filter. If null, you need to overwrite the "node_class" option to customize compilation. + * @param array $options Options array + */ + public function __construct(string $name, $callable = null, array $options = []) { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->name = $name; $this->callable = $callable; $this->options = array_merge([ @@ -39,7 +53,7 @@ public function __construct($name, $callable, array $options = []) 'is_safe_callback' => null, 'pre_escape' => null, 'preserves_safety' => null, - 'node_class' => '\Twig\Node\Expression\FilterExpression', + 'node_class' => FilterExpression::class, 'deprecated' => false, 'alternative' => null, ], $options); @@ -50,6 +64,11 @@ public function getName() return $this->name; } + /** + * Returns the callable to execute for this filter. + * + * @return callable|null + */ public function getCallable() { return $this->callable; @@ -87,7 +106,7 @@ public function getSafe(Node $filterArgs) } if (null !== $this->options['is_safe_callback']) { - return \call_user_func($this->options['is_safe_callback'], $filterArgs); + return $this->options['is_safe_callback']($filterArgs); } } @@ -122,7 +141,10 @@ public function getAlternative() } } -class_alias('Twig\TwigFilter', 'Twig_SimpleFilter'); +// For Twig 1.x compatibility +class_alias('Twig\TwigFilter', 'Twig_SimpleFilter', false); + +class_alias('Twig\TwigFilter', 'Twig_Filter'); // Ensure that the aliased name is loaded to keep BC for classes implementing the typehint with the old aliased name. class_exists('Twig\Node\Node'); diff --git a/system/libs/Twig/TwigFunction.php b/system/libs/Twig/TwigFunction.php index 374f07071e..e0d961f868 100644 --- a/system/libs/Twig/TwigFunction.php +++ b/system/libs/Twig/TwigFunction.php @@ -11,6 +11,7 @@ namespace Twig; +use Twig\Node\Expression\FunctionExpression; use Twig\Node\Node; /** @@ -19,16 +20,29 @@ * @final * * @author Fabien Potencier + * + * @see https://twig.symfony.com/doc/templates.html#functions */ class TwigFunction { - protected $name; - protected $callable; - protected $options; - protected $arguments = []; - - public function __construct($name, $callable, array $options = []) + private $name; + private $callable; + private $options; + private $arguments = []; + + /** + * Creates a template function. + * + * @param string $name Name of this function + * @param callable|null $callable A callable implementing the function. If null, you need to overwrite the "node_class" option to customize compilation. + * @param array $options Options array + */ + public function __construct(string $name, $callable = null, array $options = []) { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->name = $name; $this->callable = $callable; $this->options = array_merge([ @@ -37,7 +51,7 @@ public function __construct($name, $callable, array $options = []) 'is_variadic' => false, 'is_safe' => null, 'is_safe_callback' => null, - 'node_class' => '\Twig\Node\Expression\FunctionExpression', + 'node_class' => FunctionExpression::class, 'deprecated' => false, 'alternative' => null, ], $options); @@ -48,6 +62,11 @@ public function getName() return $this->name; } + /** + * Returns the callable to execute for this function. + * + * @return callable|null + */ public function getCallable() { return $this->callable; @@ -85,7 +104,7 @@ public function getSafe(Node $functionArgs) } if (null !== $this->options['is_safe_callback']) { - return \call_user_func($this->options['is_safe_callback'], $functionArgs); + return $this->options['is_safe_callback']($functionArgs); } return []; @@ -112,7 +131,10 @@ public function getAlternative() } } -class_alias('Twig\TwigFunction', 'Twig_SimpleFunction'); +// For Twig 1.x compatibility +class_alias('Twig\TwigFunction', 'Twig_SimpleFunction', false); + +class_alias('Twig\TwigFunction', 'Twig_Function'); // Ensure that the aliased name is loaded to keep BC for classes implementing the typehint with the old aliased name. class_exists('Twig\Node\Node'); diff --git a/system/libs/Twig/TwigTest.php b/system/libs/Twig/TwigTest.php index 5054965fe9..6a58a56e3f 100644 --- a/system/libs/Twig/TwigTest.php +++ b/system/libs/Twig/TwigTest.php @@ -11,30 +11,45 @@ namespace Twig; +use Twig\Node\Expression\TestExpression; + /** * Represents a template test. * - * @final + * @final since Twig 2.4.0 * * @author Fabien Potencier + * + * @see https://twig.symfony.com/doc/templates.html#test-operator */ class TwigTest { - protected $name; - protected $callable; - protected $options; - + private $name; + private $callable; + private $options; private $arguments = []; - public function __construct($name, $callable, array $options = []) + /** + * Creates a template test. + * + * @param string $name Name of this test + * @param callable|null $callable A callable implementing the test. If null, you need to overwrite the "node_class" option to customize compilation. + * @param array $options Options array + */ + public function __construct(string $name, $callable = null, array $options = []) { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->name = $name; $this->callable = $callable; $this->options = array_merge([ 'is_variadic' => false, - 'node_class' => '\Twig\Node\Expression\TestExpression', + 'node_class' => TestExpression::class, 'deprecated' => false, 'alternative' => null, + 'one_mandatory_argument' => false, ], $options); } @@ -43,6 +58,11 @@ public function getName() return $this->name; } + /** + * Returns the callable to execute for this test. + * + * @return callable|null + */ public function getCallable() { return $this->callable; @@ -53,6 +73,16 @@ public function getNodeClass() return $this->options['node_class']; } + public function setArguments($arguments) + { + $this->arguments = $arguments; + } + + public function getArguments() + { + return $this->arguments; + } + public function isVariadic() { return $this->options['is_variadic']; @@ -73,15 +103,13 @@ public function getAlternative() return $this->options['alternative']; } - public function setArguments($arguments) + public function hasOneMandatoryArgument(): bool { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; + return (bool) $this->options['one_mandatory_argument']; } } -class_alias('Twig\TwigTest', 'Twig_SimpleTest'); +// For Twig 1.x compatibility +class_alias('Twig\TwigTest', 'Twig_SimpleTest', false); + +class_alias('Twig\TwigTest', 'Twig_Test'); diff --git a/system/libs/Twig/Util/DeprecationCollector.php b/system/libs/Twig/Util/DeprecationCollector.php index 09917e927c..17c169f74c 100644 --- a/system/libs/Twig/Util/DeprecationCollector.php +++ b/system/libs/Twig/Util/DeprecationCollector.php @@ -17,13 +17,10 @@ /** * @author Fabien Potencier - * - * @final */ -class DeprecationCollector +final class DeprecationCollector { private $twig; - private $deprecations; public function __construct(Environment $twig) { @@ -58,9 +55,12 @@ public function collectDir($dir, $ext = '.twig') */ public function collect(\Traversable $iterator) { - $this->deprecations = []; - - set_error_handler([$this, 'errorHandler']); + $deprecations = []; + set_error_handler(function ($type, $msg) use (&$deprecations) { + if (\E_USER_DEPRECATED === $type) { + $deprecations[] = $msg; + } + }); foreach ($iterator as $name => $contents) { try { @@ -72,21 +72,8 @@ public function collect(\Traversable $iterator) restore_error_handler(); - $deprecations = $this->deprecations; - $this->deprecations = []; - return $deprecations; } - - /** - * @internal - */ - public function errorHandler($type, $msg) - { - if (E_USER_DEPRECATED === $type) { - $this->deprecations[] = $msg; - } - } } class_alias('Twig\Util\DeprecationCollector', 'Twig_Util_DeprecationCollector'); diff --git a/system/libs/Twig/Util/TemplateDirIterator.php b/system/libs/Twig/Util/TemplateDirIterator.php index 1ab0dac59d..b0356d4c2f 100644 --- a/system/libs/Twig/Util/TemplateDirIterator.php +++ b/system/libs/Twig/Util/TemplateDirIterator.php @@ -16,11 +16,19 @@ */ class TemplateDirIterator extends \IteratorIterator { + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function current() { return file_get_contents(parent::current()); } + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function key() { return (string) parent::key(); diff --git a/system/libs/creatures.php b/system/libs/creatures.php index 84f934d38c..707795cb2f 100644 --- a/system/libs/creatures.php +++ b/system/libs/creatures.php @@ -36,11 +36,23 @@ public static function loadFromXML($show = false) { return false; } - $items = array(); - Items::load(); - foreach((array)Items::$items as $id => $item) { - $items[$item['name']] = $id; - } + $items = []; + Items::load(); + if (empty(Items::$items)) { + if (Items::loadFromXML()) { + success('Successfully loaded items.'); + // load again + Items::load(); + } + } + + if (empty(Items::$items)) { + error('Fatal error. Please report to https://github.com/opentibiabr/myaac/issues'); + return false; + } + foreach ((array)Items::$items as $id => $item) { + $items[$item['name']] = $id; + } //$names_added must be an array $names_added[] = ''; @@ -136,4 +148,4 @@ public static function getMonstersList() { public static function getLastError() { return self::$lastError; } -} \ No newline at end of file +} diff --git a/system/libs/forum.php b/system/libs/forum.php index 648a9d9990..750cb5fb6e 100644 --- a/system/libs/forum.php +++ b/system/libs/forum.php @@ -11,7 +11,7 @@ defined('MYAAC') or die('Direct access not allowed!'); $configForumTablePrefix = config('forum_table_prefix'); -if(!empty(trim($configForumTablePrefix))) { +if ($configForumTablePrefix !== null && !empty(trim($configForumTablePrefix))) { if(!in_array($configForumTablePrefix, array('myaac_', 'z_'))) { throw new RuntimeException('Invalid value for forum_table_prefix in config.php. Can be only: "myaac_" or "z_".'); } @@ -322,4 +322,4 @@ public static function hasAccess($board_id) { return $hasAccess; } } -?> \ No newline at end of file +?> diff --git a/system/libs/plugins.php b/system/libs/plugins.php index 04dfaf527c..629a9a5782 100644 --- a/system/libs/plugins.php +++ b/system/libs/plugins.php @@ -66,10 +66,10 @@ public static function getHooks() continue; } - if(isset($plugin['enabled']) && $plugin['enabled'] === 0) { - self::$warnings[] = 'Skipping ' . $filename . '... The plugin is disabled.'; - continue; - } + if (isset($plugin['enabled']) && !getBoolean($plugin['enabled'])) { + self::$warnings[] = 'Skipping ' . $filename . '... The plugin is disabled.'; + continue; + } if (isset($plugin['hooks'])) { foreach ($plugin['hooks'] as $_name => $info) { diff --git a/system/libs/polyfill-mbstring/LICENSE b/system/libs/polyfill-mbstring/LICENSE new file mode 100644 index 0000000000..4cd8bdd300 --- /dev/null +++ b/system/libs/polyfill-mbstring/LICENSE @@ -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. diff --git a/system/libs/polyfill-mbstring/Mbstring.php b/system/libs/polyfill-mbstring/Mbstring.php new file mode 100644 index 0000000000..bce5c4a84a --- /dev/null +++ b/system/libs/polyfill-mbstring/Mbstring.php @@ -0,0 +1,874 @@ + + * + * 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 + * + * @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; + } +} diff --git a/system/libs/polyfill-mbstring/README.md b/system/libs/polyfill-mbstring/README.md new file mode 100644 index 0000000000..478b40da25 --- /dev/null +++ b/system/libs/polyfill-mbstring/README.md @@ -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). diff --git a/system/libs/polyfill-mbstring/Resources/unidata/lowerCase.php b/system/libs/polyfill-mbstring/Resources/unidata/lowerCase.php new file mode 100644 index 0000000000..fac60b081a --- /dev/null +++ b/system/libs/polyfill-mbstring/Resources/unidata/lowerCase.php @@ -0,0 +1,1397 @@ + 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + 'À' => 'à', + 'Á' => 'á', + 'Â' => 'â', + 'Ã' => 'ã', + 'Ä' => 'ä', + 'Å' => 'å', + 'Æ' => 'æ', + 'Ç' => 'ç', + 'È' => 'è', + 'É' => 'é', + 'Ê' => 'ê', + 'Ë' => 'ë', + 'Ì' => 'ì', + 'Í' => 'í', + 'Î' => 'î', + 'Ï' => 'ï', + 'Ð' => 'ð', + 'Ñ' => 'ñ', + 'Ò' => 'ò', + 'Ó' => 'ó', + 'Ô' => 'ô', + 'Õ' => 'õ', + 'Ö' => 'ö', + 'Ø' => 'ø', + 'Ù' => 'ù', + 'Ú' => 'ú', + 'Û' => 'û', + 'Ü' => 'ü', + 'Ý' => 'ý', + 'Þ' => 'þ', + 'Ā' => 'ā', + 'Ă' => 'ă', + 'Ą' => 'ą', + 'Ć' => 'ć', + 'Ĉ' => 'ĉ', + 'Ċ' => 'ċ', + 'Č' => 'č', + 'Ď' => 'ď', + 'Đ' => 'đ', + 'Ē' => 'ē', + 'Ĕ' => 'ĕ', + 'Ė' => 'ė', + 'Ę' => 'ę', + 'Ě' => 'ě', + 'Ĝ' => 'ĝ', + 'Ğ' => 'ğ', + 'Ġ' => 'ġ', + 'Ģ' => 'ģ', + 'Ĥ' => 'ĥ', + 'Ħ' => 'ħ', + 'Ĩ' => 'ĩ', + 'Ī' => 'ī', + 'Ĭ' => 'ĭ', + 'Į' => 'į', + 'İ' => 'i̇', + 'IJ' => 'ij', + 'Ĵ' => 'ĵ', + 'Ķ' => 'ķ', + 'Ĺ' => 'ĺ', + 'Ļ' => 'ļ', + 'Ľ' => 'ľ', + 'Ŀ' => 'ŀ', + 'Ł' => 'ł', + 'Ń' => 'ń', + 'Ņ' => 'ņ', + 'Ň' => 'ň', + 'Ŋ' => 'ŋ', + 'Ō' => 'ō', + 'Ŏ' => 'ŏ', + 'Ő' => 'ő', + 'Œ' => 'œ', + 'Ŕ' => 'ŕ', + 'Ŗ' => 'ŗ', + 'Ř' => 'ř', + 'Ś' => 'ś', + 'Ŝ' => 'ŝ', + 'Ş' => 'ş', + 'Š' => 'š', + 'Ţ' => 'ţ', + 'Ť' => 'ť', + 'Ŧ' => 'ŧ', + 'Ũ' => 'ũ', + 'Ū' => 'ū', + 'Ŭ' => 'ŭ', + 'Ů' => 'ů', + 'Ű' => 'ű', + 'Ų' => 'ų', + 'Ŵ' => 'ŵ', + 'Ŷ' => 'ŷ', + 'Ÿ' => 'ÿ', + 'Ź' => 'ź', + 'Ż' => 'ż', + 'Ž' => 'ž', + 'Ɓ' => 'ɓ', + 'Ƃ' => 'ƃ', + 'Ƅ' => 'ƅ', + 'Ɔ' => 'ɔ', + 'Ƈ' => 'ƈ', + 'Ɖ' => 'ɖ', + 'Ɗ' => 'ɗ', + 'Ƌ' => 'ƌ', + 'Ǝ' => 'ǝ', + 'Ə' => 'ə', + 'Ɛ' => 'ɛ', + 'Ƒ' => 'ƒ', + 'Ɠ' => 'ɠ', + 'Ɣ' => 'ɣ', + 'Ɩ' => 'ɩ', + 'Ɨ' => 'ɨ', + 'Ƙ' => 'ƙ', + 'Ɯ' => 'ɯ', + 'Ɲ' => 'ɲ', + 'Ɵ' => 'ɵ', + 'Ơ' => 'ơ', + 'Ƣ' => 'ƣ', + 'Ƥ' => 'ƥ', + 'Ʀ' => 'ʀ', + 'Ƨ' => 'ƨ', + 'Ʃ' => 'ʃ', + 'Ƭ' => 'ƭ', + 'Ʈ' => 'ʈ', + 'Ư' => 'ư', + 'Ʊ' => 'ʊ', + 'Ʋ' => 'ʋ', + 'Ƴ' => 'ƴ', + 'Ƶ' => 'ƶ', + 'Ʒ' => 'ʒ', + 'Ƹ' => 'ƹ', + 'Ƽ' => 'ƽ', + 'DŽ' => 'dž', + 'Dž' => 'dž', + 'LJ' => 'lj', + 'Lj' => 'lj', + 'NJ' => 'nj', + 'Nj' => 'nj', + 'Ǎ' => 'ǎ', + 'Ǐ' => 'ǐ', + 'Ǒ' => 'ǒ', + 'Ǔ' => 'ǔ', + 'Ǖ' => 'ǖ', + 'Ǘ' => 'ǘ', + 'Ǚ' => 'ǚ', + 'Ǜ' => 'ǜ', + 'Ǟ' => 'ǟ', + 'Ǡ' => 'ǡ', + 'Ǣ' => 'ǣ', + 'Ǥ' => 'ǥ', + 'Ǧ' => 'ǧ', + 'Ǩ' => 'ǩ', + 'Ǫ' => 'ǫ', + 'Ǭ' => 'ǭ', + 'Ǯ' => 'ǯ', + 'DZ' => 'dz', + 'Dz' => 'dz', + 'Ǵ' => 'ǵ', + 'Ƕ' => 'ƕ', + 'Ƿ' => 'ƿ', + 'Ǹ' => 'ǹ', + 'Ǻ' => 'ǻ', + 'Ǽ' => 'ǽ', + 'Ǿ' => 'ǿ', + 'Ȁ' => 'ȁ', + 'Ȃ' => 'ȃ', + 'Ȅ' => 'ȅ', + 'Ȇ' => 'ȇ', + 'Ȉ' => 'ȉ', + 'Ȋ' => 'ȋ', + 'Ȍ' => 'ȍ', + 'Ȏ' => 'ȏ', + 'Ȑ' => 'ȑ', + 'Ȓ' => 'ȓ', + 'Ȕ' => 'ȕ', + 'Ȗ' => 'ȗ', + 'Ș' => 'ș', + 'Ț' => 'ț', + 'Ȝ' => 'ȝ', + 'Ȟ' => 'ȟ', + 'Ƞ' => 'ƞ', + 'Ȣ' => 'ȣ', + 'Ȥ' => 'ȥ', + 'Ȧ' => 'ȧ', + 'Ȩ' => 'ȩ', + 'Ȫ' => 'ȫ', + 'Ȭ' => 'ȭ', + 'Ȯ' => 'ȯ', + 'Ȱ' => 'ȱ', + 'Ȳ' => 'ȳ', + 'Ⱥ' => 'ⱥ', + 'Ȼ' => 'ȼ', + 'Ƚ' => 'ƚ', + 'Ⱦ' => 'ⱦ', + 'Ɂ' => 'ɂ', + 'Ƀ' => 'ƀ', + 'Ʉ' => 'ʉ', + 'Ʌ' => 'ʌ', + 'Ɇ' => 'ɇ', + 'Ɉ' => 'ɉ', + 'Ɋ' => 'ɋ', + 'Ɍ' => 'ɍ', + 'Ɏ' => 'ɏ', + 'Ͱ' => 'ͱ', + 'Ͳ' => 'ͳ', + 'Ͷ' => 'ͷ', + 'Ϳ' => 'ϳ', + 'Ά' => 'ά', + 'Έ' => 'έ', + 'Ή' => 'ή', + 'Ί' => 'ί', + 'Ό' => 'ό', + 'Ύ' => 'ύ', + 'Ώ' => 'ώ', + 'Α' => 'α', + 'Β' => 'β', + 'Γ' => 'γ', + 'Δ' => 'δ', + 'Ε' => 'ε', + 'Ζ' => 'ζ', + 'Η' => 'η', + 'Θ' => 'θ', + 'Ι' => 'ι', + 'Κ' => 'κ', + 'Λ' => 'λ', + 'Μ' => 'μ', + 'Ν' => 'ν', + 'Ξ' => 'ξ', + 'Ο' => 'ο', + 'Π' => 'π', + 'Ρ' => 'ρ', + 'Σ' => 'σ', + 'Τ' => 'τ', + 'Υ' => 'υ', + 'Φ' => 'φ', + 'Χ' => 'χ', + 'Ψ' => 'ψ', + 'Ω' => 'ω', + 'Ϊ' => 'ϊ', + 'Ϋ' => 'ϋ', + 'Ϗ' => 'ϗ', + 'Ϙ' => 'ϙ', + 'Ϛ' => 'ϛ', + 'Ϝ' => 'ϝ', + 'Ϟ' => 'ϟ', + 'Ϡ' => 'ϡ', + 'Ϣ' => 'ϣ', + 'Ϥ' => 'ϥ', + 'Ϧ' => 'ϧ', + 'Ϩ' => 'ϩ', + 'Ϫ' => 'ϫ', + 'Ϭ' => 'ϭ', + 'Ϯ' => 'ϯ', + 'ϴ' => 'θ', + 'Ϸ' => 'ϸ', + 'Ϲ' => 'ϲ', + 'Ϻ' => 'ϻ', + 'Ͻ' => 'ͻ', + 'Ͼ' => 'ͼ', + 'Ͽ' => 'ͽ', + 'Ѐ' => 'ѐ', + 'Ё' => 'ё', + 'Ђ' => 'ђ', + 'Ѓ' => 'ѓ', + 'Є' => 'є', + 'Ѕ' => 'ѕ', + 'І' => 'і', + 'Ї' => 'ї', + 'Ј' => 'ј', + 'Љ' => 'љ', + 'Њ' => 'њ', + 'Ћ' => 'ћ', + 'Ќ' => 'ќ', + 'Ѝ' => 'ѝ', + 'Ў' => 'ў', + 'Џ' => 'џ', + 'А' => 'а', + 'Б' => 'б', + 'В' => 'в', + 'Г' => 'г', + 'Д' => 'д', + 'Е' => 'е', + 'Ж' => 'ж', + 'З' => 'з', + 'И' => 'и', + 'Й' => 'й', + 'К' => 'к', + 'Л' => 'л', + 'М' => 'м', + 'Н' => 'н', + 'О' => 'о', + 'П' => 'п', + 'Р' => 'р', + 'С' => 'с', + 'Т' => 'т', + 'У' => 'у', + 'Ф' => 'ф', + 'Х' => 'х', + 'Ц' => 'ц', + 'Ч' => 'ч', + 'Ш' => 'ш', + 'Щ' => 'щ', + 'Ъ' => 'ъ', + 'Ы' => 'ы', + 'Ь' => 'ь', + 'Э' => 'э', + 'Ю' => 'ю', + 'Я' => 'я', + 'Ѡ' => 'ѡ', + 'Ѣ' => 'ѣ', + 'Ѥ' => 'ѥ', + 'Ѧ' => 'ѧ', + 'Ѩ' => 'ѩ', + 'Ѫ' => 'ѫ', + 'Ѭ' => 'ѭ', + 'Ѯ' => 'ѯ', + 'Ѱ' => 'ѱ', + 'Ѳ' => 'ѳ', + 'Ѵ' => 'ѵ', + 'Ѷ' => 'ѷ', + 'Ѹ' => 'ѹ', + 'Ѻ' => 'ѻ', + 'Ѽ' => 'ѽ', + 'Ѿ' => 'ѿ', + 'Ҁ' => 'ҁ', + 'Ҋ' => 'ҋ', + 'Ҍ' => 'ҍ', + 'Ҏ' => 'ҏ', + 'Ґ' => 'ґ', + 'Ғ' => 'ғ', + 'Ҕ' => 'ҕ', + 'Җ' => 'җ', + 'Ҙ' => 'ҙ', + 'Қ' => 'қ', + 'Ҝ' => 'ҝ', + 'Ҟ' => 'ҟ', + 'Ҡ' => 'ҡ', + 'Ң' => 'ң', + 'Ҥ' => 'ҥ', + 'Ҧ' => 'ҧ', + 'Ҩ' => 'ҩ', + 'Ҫ' => 'ҫ', + 'Ҭ' => 'ҭ', + 'Ү' => 'ү', + 'Ұ' => 'ұ', + 'Ҳ' => 'ҳ', + 'Ҵ' => 'ҵ', + 'Ҷ' => 'ҷ', + 'Ҹ' => 'ҹ', + 'Һ' => 'һ', + 'Ҽ' => 'ҽ', + 'Ҿ' => 'ҿ', + 'Ӏ' => 'ӏ', + 'Ӂ' => 'ӂ', + 'Ӄ' => 'ӄ', + 'Ӆ' => 'ӆ', + 'Ӈ' => 'ӈ', + 'Ӊ' => 'ӊ', + 'Ӌ' => 'ӌ', + 'Ӎ' => 'ӎ', + 'Ӑ' => 'ӑ', + 'Ӓ' => 'ӓ', + 'Ӕ' => 'ӕ', + 'Ӗ' => 'ӗ', + 'Ә' => 'ә', + 'Ӛ' => 'ӛ', + 'Ӝ' => 'ӝ', + 'Ӟ' => 'ӟ', + 'Ӡ' => 'ӡ', + 'Ӣ' => 'ӣ', + 'Ӥ' => 'ӥ', + 'Ӧ' => 'ӧ', + 'Ө' => 'ө', + 'Ӫ' => 'ӫ', + 'Ӭ' => 'ӭ', + 'Ӯ' => 'ӯ', + 'Ӱ' => 'ӱ', + 'Ӳ' => 'ӳ', + 'Ӵ' => 'ӵ', + 'Ӷ' => 'ӷ', + 'Ӹ' => 'ӹ', + 'Ӻ' => 'ӻ', + 'Ӽ' => 'ӽ', + 'Ӿ' => 'ӿ', + 'Ԁ' => 'ԁ', + 'Ԃ' => 'ԃ', + 'Ԅ' => 'ԅ', + 'Ԇ' => 'ԇ', + 'Ԉ' => 'ԉ', + 'Ԋ' => 'ԋ', + 'Ԍ' => 'ԍ', + 'Ԏ' => 'ԏ', + 'Ԑ' => 'ԑ', + 'Ԓ' => 'ԓ', + 'Ԕ' => 'ԕ', + 'Ԗ' => 'ԗ', + 'Ԙ' => 'ԙ', + 'Ԛ' => 'ԛ', + 'Ԝ' => 'ԝ', + 'Ԟ' => 'ԟ', + 'Ԡ' => 'ԡ', + 'Ԣ' => 'ԣ', + 'Ԥ' => 'ԥ', + 'Ԧ' => 'ԧ', + 'Ԩ' => 'ԩ', + 'Ԫ' => 'ԫ', + 'Ԭ' => 'ԭ', + 'Ԯ' => 'ԯ', + 'Ա' => 'ա', + 'Բ' => 'բ', + 'Գ' => 'գ', + 'Դ' => 'դ', + 'Ե' => 'ե', + 'Զ' => 'զ', + 'Է' => 'է', + 'Ը' => 'ը', + 'Թ' => 'թ', + 'Ժ' => 'ժ', + 'Ի' => 'ի', + 'Լ' => 'լ', + 'Խ' => 'խ', + 'Ծ' => 'ծ', + 'Կ' => 'կ', + 'Հ' => 'հ', + 'Ձ' => 'ձ', + 'Ղ' => 'ղ', + 'Ճ' => 'ճ', + 'Մ' => 'մ', + 'Յ' => 'յ', + 'Ն' => 'ն', + 'Շ' => 'շ', + 'Ո' => 'ո', + 'Չ' => 'չ', + 'Պ' => 'պ', + 'Ջ' => 'ջ', + 'Ռ' => 'ռ', + 'Ս' => 'ս', + 'Վ' => 'վ', + 'Տ' => 'տ', + 'Ր' => 'ր', + 'Ց' => 'ց', + 'Ւ' => 'ւ', + 'Փ' => 'փ', + 'Ք' => 'ք', + 'Օ' => 'օ', + 'Ֆ' => 'ֆ', + 'Ⴀ' => 'ⴀ', + 'Ⴁ' => 'ⴁ', + 'Ⴂ' => 'ⴂ', + 'Ⴃ' => 'ⴃ', + 'Ⴄ' => 'ⴄ', + 'Ⴅ' => 'ⴅ', + 'Ⴆ' => 'ⴆ', + 'Ⴇ' => 'ⴇ', + 'Ⴈ' => 'ⴈ', + 'Ⴉ' => 'ⴉ', + 'Ⴊ' => 'ⴊ', + 'Ⴋ' => 'ⴋ', + 'Ⴌ' => 'ⴌ', + 'Ⴍ' => 'ⴍ', + 'Ⴎ' => 'ⴎ', + 'Ⴏ' => 'ⴏ', + 'Ⴐ' => 'ⴐ', + 'Ⴑ' => 'ⴑ', + 'Ⴒ' => 'ⴒ', + 'Ⴓ' => 'ⴓ', + 'Ⴔ' => 'ⴔ', + 'Ⴕ' => 'ⴕ', + 'Ⴖ' => 'ⴖ', + 'Ⴗ' => 'ⴗ', + 'Ⴘ' => 'ⴘ', + 'Ⴙ' => 'ⴙ', + 'Ⴚ' => 'ⴚ', + 'Ⴛ' => 'ⴛ', + 'Ⴜ' => 'ⴜ', + 'Ⴝ' => 'ⴝ', + 'Ⴞ' => 'ⴞ', + 'Ⴟ' => 'ⴟ', + 'Ⴠ' => 'ⴠ', + 'Ⴡ' => 'ⴡ', + 'Ⴢ' => 'ⴢ', + 'Ⴣ' => 'ⴣ', + 'Ⴤ' => 'ⴤ', + 'Ⴥ' => 'ⴥ', + 'Ⴧ' => 'ⴧ', + 'Ⴭ' => 'ⴭ', + 'Ꭰ' => 'ꭰ', + 'Ꭱ' => 'ꭱ', + 'Ꭲ' => 'ꭲ', + 'Ꭳ' => 'ꭳ', + 'Ꭴ' => 'ꭴ', + 'Ꭵ' => 'ꭵ', + 'Ꭶ' => 'ꭶ', + 'Ꭷ' => 'ꭷ', + 'Ꭸ' => 'ꭸ', + 'Ꭹ' => 'ꭹ', + 'Ꭺ' => 'ꭺ', + 'Ꭻ' => 'ꭻ', + 'Ꭼ' => 'ꭼ', + 'Ꭽ' => 'ꭽ', + 'Ꭾ' => 'ꭾ', + 'Ꭿ' => 'ꭿ', + 'Ꮀ' => 'ꮀ', + 'Ꮁ' => 'ꮁ', + 'Ꮂ' => 'ꮂ', + 'Ꮃ' => 'ꮃ', + 'Ꮄ' => 'ꮄ', + 'Ꮅ' => 'ꮅ', + 'Ꮆ' => 'ꮆ', + 'Ꮇ' => 'ꮇ', + 'Ꮈ' => 'ꮈ', + 'Ꮉ' => 'ꮉ', + 'Ꮊ' => 'ꮊ', + 'Ꮋ' => 'ꮋ', + 'Ꮌ' => 'ꮌ', + 'Ꮍ' => 'ꮍ', + 'Ꮎ' => 'ꮎ', + 'Ꮏ' => 'ꮏ', + 'Ꮐ' => 'ꮐ', + 'Ꮑ' => 'ꮑ', + 'Ꮒ' => 'ꮒ', + 'Ꮓ' => 'ꮓ', + 'Ꮔ' => 'ꮔ', + 'Ꮕ' => 'ꮕ', + 'Ꮖ' => 'ꮖ', + 'Ꮗ' => 'ꮗ', + 'Ꮘ' => 'ꮘ', + 'Ꮙ' => 'ꮙ', + 'Ꮚ' => 'ꮚ', + 'Ꮛ' => 'ꮛ', + 'Ꮜ' => 'ꮜ', + 'Ꮝ' => 'ꮝ', + 'Ꮞ' => 'ꮞ', + 'Ꮟ' => 'ꮟ', + 'Ꮠ' => 'ꮠ', + 'Ꮡ' => 'ꮡ', + 'Ꮢ' => 'ꮢ', + 'Ꮣ' => 'ꮣ', + 'Ꮤ' => 'ꮤ', + 'Ꮥ' => 'ꮥ', + 'Ꮦ' => 'ꮦ', + 'Ꮧ' => 'ꮧ', + 'Ꮨ' => 'ꮨ', + 'Ꮩ' => 'ꮩ', + 'Ꮪ' => 'ꮪ', + 'Ꮫ' => 'ꮫ', + 'Ꮬ' => 'ꮬ', + 'Ꮭ' => 'ꮭ', + 'Ꮮ' => 'ꮮ', + 'Ꮯ' => 'ꮯ', + 'Ꮰ' => 'ꮰ', + 'Ꮱ' => 'ꮱ', + 'Ꮲ' => 'ꮲ', + 'Ꮳ' => 'ꮳ', + 'Ꮴ' => 'ꮴ', + 'Ꮵ' => 'ꮵ', + 'Ꮶ' => 'ꮶ', + 'Ꮷ' => 'ꮷ', + 'Ꮸ' => 'ꮸ', + 'Ꮹ' => 'ꮹ', + 'Ꮺ' => 'ꮺ', + 'Ꮻ' => 'ꮻ', + 'Ꮼ' => 'ꮼ', + 'Ꮽ' => 'ꮽ', + 'Ꮾ' => 'ꮾ', + 'Ꮿ' => 'ꮿ', + 'Ᏸ' => 'ᏸ', + 'Ᏹ' => 'ᏹ', + 'Ᏺ' => 'ᏺ', + 'Ᏻ' => 'ᏻ', + 'Ᏼ' => 'ᏼ', + 'Ᏽ' => 'ᏽ', + 'Ა' => 'ა', + 'Ბ' => 'ბ', + 'Გ' => 'გ', + 'Დ' => 'დ', + 'Ე' => 'ე', + 'Ვ' => 'ვ', + 'Ზ' => 'ზ', + 'Თ' => 'თ', + 'Ი' => 'ი', + 'Კ' => 'კ', + 'Ლ' => 'ლ', + 'Მ' => 'მ', + 'Ნ' => 'ნ', + 'Ო' => 'ო', + 'Პ' => 'პ', + 'Ჟ' => 'ჟ', + 'Რ' => 'რ', + 'Ს' => 'ს', + 'Ტ' => 'ტ', + 'Უ' => 'უ', + 'Ფ' => 'ფ', + 'Ქ' => 'ქ', + 'Ღ' => 'ღ', + 'Ყ' => 'ყ', + 'Შ' => 'შ', + 'Ჩ' => 'ჩ', + 'Ც' => 'ც', + 'Ძ' => 'ძ', + 'Წ' => 'წ', + 'Ჭ' => 'ჭ', + 'Ხ' => 'ხ', + 'Ჯ' => 'ჯ', + 'Ჰ' => 'ჰ', + 'Ჱ' => 'ჱ', + 'Ჲ' => 'ჲ', + 'Ჳ' => 'ჳ', + 'Ჴ' => 'ჴ', + 'Ჵ' => 'ჵ', + 'Ჶ' => 'ჶ', + 'Ჷ' => 'ჷ', + 'Ჸ' => 'ჸ', + 'Ჹ' => 'ჹ', + 'Ჺ' => 'ჺ', + 'Ჽ' => 'ჽ', + 'Ჾ' => 'ჾ', + 'Ჿ' => 'ჿ', + 'Ḁ' => 'ḁ', + 'Ḃ' => 'ḃ', + 'Ḅ' => 'ḅ', + 'Ḇ' => 'ḇ', + 'Ḉ' => 'ḉ', + 'Ḋ' => 'ḋ', + 'Ḍ' => 'ḍ', + 'Ḏ' => 'ḏ', + 'Ḑ' => 'ḑ', + 'Ḓ' => 'ḓ', + 'Ḕ' => 'ḕ', + 'Ḗ' => 'ḗ', + 'Ḙ' => 'ḙ', + 'Ḛ' => 'ḛ', + 'Ḝ' => 'ḝ', + 'Ḟ' => 'ḟ', + 'Ḡ' => 'ḡ', + 'Ḣ' => 'ḣ', + 'Ḥ' => 'ḥ', + 'Ḧ' => 'ḧ', + 'Ḩ' => 'ḩ', + 'Ḫ' => 'ḫ', + 'Ḭ' => 'ḭ', + 'Ḯ' => 'ḯ', + 'Ḱ' => 'ḱ', + 'Ḳ' => 'ḳ', + 'Ḵ' => 'ḵ', + 'Ḷ' => 'ḷ', + 'Ḹ' => 'ḹ', + 'Ḻ' => 'ḻ', + 'Ḽ' => 'ḽ', + 'Ḿ' => 'ḿ', + 'Ṁ' => 'ṁ', + 'Ṃ' => 'ṃ', + 'Ṅ' => 'ṅ', + 'Ṇ' => 'ṇ', + 'Ṉ' => 'ṉ', + 'Ṋ' => 'ṋ', + 'Ṍ' => 'ṍ', + 'Ṏ' => 'ṏ', + 'Ṑ' => 'ṑ', + 'Ṓ' => 'ṓ', + 'Ṕ' => 'ṕ', + 'Ṗ' => 'ṗ', + 'Ṙ' => 'ṙ', + 'Ṛ' => 'ṛ', + 'Ṝ' => 'ṝ', + 'Ṟ' => 'ṟ', + 'Ṡ' => 'ṡ', + 'Ṣ' => 'ṣ', + 'Ṥ' => 'ṥ', + 'Ṧ' => 'ṧ', + 'Ṩ' => 'ṩ', + 'Ṫ' => 'ṫ', + 'Ṭ' => 'ṭ', + 'Ṯ' => 'ṯ', + 'Ṱ' => 'ṱ', + 'Ṳ' => 'ṳ', + 'Ṵ' => 'ṵ', + 'Ṷ' => 'ṷ', + 'Ṹ' => 'ṹ', + 'Ṻ' => 'ṻ', + 'Ṽ' => 'ṽ', + 'Ṿ' => 'ṿ', + 'Ẁ' => 'ẁ', + 'Ẃ' => 'ẃ', + 'Ẅ' => 'ẅ', + 'Ẇ' => 'ẇ', + 'Ẉ' => 'ẉ', + 'Ẋ' => 'ẋ', + 'Ẍ' => 'ẍ', + 'Ẏ' => 'ẏ', + 'Ẑ' => 'ẑ', + 'Ẓ' => 'ẓ', + 'Ẕ' => 'ẕ', + 'ẞ' => 'ß', + 'Ạ' => 'ạ', + 'Ả' => 'ả', + 'Ấ' => 'ấ', + 'Ầ' => 'ầ', + 'Ẩ' => 'ẩ', + 'Ẫ' => 'ẫ', + 'Ậ' => 'ậ', + 'Ắ' => 'ắ', + 'Ằ' => 'ằ', + 'Ẳ' => 'ẳ', + 'Ẵ' => 'ẵ', + 'Ặ' => 'ặ', + 'Ẹ' => 'ẹ', + 'Ẻ' => 'ẻ', + 'Ẽ' => 'ẽ', + 'Ế' => 'ế', + 'Ề' => 'ề', + 'Ể' => 'ể', + 'Ễ' => 'ễ', + 'Ệ' => 'ệ', + 'Ỉ' => 'ỉ', + 'Ị' => 'ị', + 'Ọ' => 'ọ', + 'Ỏ' => 'ỏ', + 'Ố' => 'ố', + 'Ồ' => 'ồ', + 'Ổ' => 'ổ', + 'Ỗ' => 'ỗ', + 'Ộ' => 'ộ', + 'Ớ' => 'ớ', + 'Ờ' => 'ờ', + 'Ở' => 'ở', + 'Ỡ' => 'ỡ', + 'Ợ' => 'ợ', + 'Ụ' => 'ụ', + 'Ủ' => 'ủ', + 'Ứ' => 'ứ', + 'Ừ' => 'ừ', + 'Ử' => 'ử', + 'Ữ' => 'ữ', + 'Ự' => 'ự', + 'Ỳ' => 'ỳ', + 'Ỵ' => 'ỵ', + 'Ỷ' => 'ỷ', + 'Ỹ' => 'ỹ', + 'Ỻ' => 'ỻ', + 'Ỽ' => 'ỽ', + 'Ỿ' => 'ỿ', + 'Ἀ' => 'ἀ', + 'Ἁ' => 'ἁ', + 'Ἂ' => 'ἂ', + 'Ἃ' => 'ἃ', + 'Ἄ' => 'ἄ', + 'Ἅ' => 'ἅ', + 'Ἆ' => 'ἆ', + 'Ἇ' => 'ἇ', + 'Ἐ' => 'ἐ', + 'Ἑ' => 'ἑ', + 'Ἒ' => 'ἒ', + 'Ἓ' => 'ἓ', + 'Ἔ' => 'ἔ', + 'Ἕ' => 'ἕ', + 'Ἠ' => 'ἠ', + 'Ἡ' => 'ἡ', + 'Ἢ' => 'ἢ', + 'Ἣ' => 'ἣ', + 'Ἤ' => 'ἤ', + 'Ἥ' => 'ἥ', + 'Ἦ' => 'ἦ', + 'Ἧ' => 'ἧ', + 'Ἰ' => 'ἰ', + 'Ἱ' => 'ἱ', + 'Ἲ' => 'ἲ', + 'Ἳ' => 'ἳ', + 'Ἴ' => 'ἴ', + 'Ἵ' => 'ἵ', + 'Ἶ' => 'ἶ', + 'Ἷ' => 'ἷ', + 'Ὀ' => 'ὀ', + 'Ὁ' => 'ὁ', + 'Ὂ' => 'ὂ', + 'Ὃ' => 'ὃ', + 'Ὄ' => 'ὄ', + 'Ὅ' => 'ὅ', + 'Ὑ' => 'ὑ', + 'Ὓ' => 'ὓ', + 'Ὕ' => 'ὕ', + 'Ὗ' => 'ὗ', + 'Ὠ' => 'ὠ', + 'Ὡ' => 'ὡ', + 'Ὢ' => 'ὢ', + 'Ὣ' => 'ὣ', + 'Ὤ' => 'ὤ', + 'Ὥ' => 'ὥ', + 'Ὦ' => 'ὦ', + 'Ὧ' => 'ὧ', + 'ᾈ' => 'ᾀ', + 'ᾉ' => 'ᾁ', + 'ᾊ' => 'ᾂ', + 'ᾋ' => 'ᾃ', + 'ᾌ' => 'ᾄ', + 'ᾍ' => 'ᾅ', + 'ᾎ' => 'ᾆ', + 'ᾏ' => 'ᾇ', + 'ᾘ' => 'ᾐ', + 'ᾙ' => 'ᾑ', + 'ᾚ' => 'ᾒ', + 'ᾛ' => 'ᾓ', + 'ᾜ' => 'ᾔ', + 'ᾝ' => 'ᾕ', + 'ᾞ' => 'ᾖ', + 'ᾟ' => 'ᾗ', + 'ᾨ' => 'ᾠ', + 'ᾩ' => 'ᾡ', + 'ᾪ' => 'ᾢ', + 'ᾫ' => 'ᾣ', + 'ᾬ' => 'ᾤ', + 'ᾭ' => 'ᾥ', + 'ᾮ' => 'ᾦ', + 'ᾯ' => 'ᾧ', + 'Ᾰ' => 'ᾰ', + 'Ᾱ' => 'ᾱ', + 'Ὰ' => 'ὰ', + 'Ά' => 'ά', + 'ᾼ' => 'ᾳ', + 'Ὲ' => 'ὲ', + 'Έ' => 'έ', + 'Ὴ' => 'ὴ', + 'Ή' => 'ή', + 'ῌ' => 'ῃ', + 'Ῐ' => 'ῐ', + 'Ῑ' => 'ῑ', + 'Ὶ' => 'ὶ', + 'Ί' => 'ί', + 'Ῠ' => 'ῠ', + 'Ῡ' => 'ῡ', + 'Ὺ' => 'ὺ', + 'Ύ' => 'ύ', + 'Ῥ' => 'ῥ', + 'Ὸ' => 'ὸ', + 'Ό' => 'ό', + 'Ὼ' => 'ὼ', + 'Ώ' => 'ώ', + 'ῼ' => 'ῳ', + 'Ω' => 'ω', + 'K' => 'k', + 'Å' => 'å', + 'Ⅎ' => 'ⅎ', + 'Ⅰ' => 'ⅰ', + 'Ⅱ' => 'ⅱ', + 'Ⅲ' => 'ⅲ', + 'Ⅳ' => 'ⅳ', + 'Ⅴ' => 'ⅴ', + 'Ⅵ' => 'ⅵ', + 'Ⅶ' => 'ⅶ', + 'Ⅷ' => 'ⅷ', + 'Ⅸ' => 'ⅸ', + 'Ⅹ' => 'ⅹ', + 'Ⅺ' => 'ⅺ', + 'Ⅻ' => 'ⅻ', + 'Ⅼ' => 'ⅼ', + 'Ⅽ' => 'ⅽ', + 'Ⅾ' => 'ⅾ', + 'Ⅿ' => 'ⅿ', + 'Ↄ' => 'ↄ', + 'Ⓐ' => 'ⓐ', + 'Ⓑ' => 'ⓑ', + 'Ⓒ' => 'ⓒ', + 'Ⓓ' => 'ⓓ', + 'Ⓔ' => 'ⓔ', + 'Ⓕ' => 'ⓕ', + 'Ⓖ' => 'ⓖ', + 'Ⓗ' => 'ⓗ', + 'Ⓘ' => 'ⓘ', + 'Ⓙ' => 'ⓙ', + 'Ⓚ' => 'ⓚ', + 'Ⓛ' => 'ⓛ', + 'Ⓜ' => 'ⓜ', + 'Ⓝ' => 'ⓝ', + 'Ⓞ' => 'ⓞ', + 'Ⓟ' => 'ⓟ', + 'Ⓠ' => 'ⓠ', + 'Ⓡ' => 'ⓡ', + 'Ⓢ' => 'ⓢ', + 'Ⓣ' => 'ⓣ', + 'Ⓤ' => 'ⓤ', + 'Ⓥ' => 'ⓥ', + 'Ⓦ' => 'ⓦ', + 'Ⓧ' => 'ⓧ', + 'Ⓨ' => 'ⓨ', + 'Ⓩ' => 'ⓩ', + 'Ⰰ' => 'ⰰ', + 'Ⰱ' => 'ⰱ', + 'Ⰲ' => 'ⰲ', + 'Ⰳ' => 'ⰳ', + 'Ⰴ' => 'ⰴ', + 'Ⰵ' => 'ⰵ', + 'Ⰶ' => 'ⰶ', + 'Ⰷ' => 'ⰷ', + 'Ⰸ' => 'ⰸ', + 'Ⰹ' => 'ⰹ', + 'Ⰺ' => 'ⰺ', + 'Ⰻ' => 'ⰻ', + 'Ⰼ' => 'ⰼ', + 'Ⰽ' => 'ⰽ', + 'Ⰾ' => 'ⰾ', + 'Ⰿ' => 'ⰿ', + 'Ⱀ' => 'ⱀ', + 'Ⱁ' => 'ⱁ', + 'Ⱂ' => 'ⱂ', + 'Ⱃ' => 'ⱃ', + 'Ⱄ' => 'ⱄ', + 'Ⱅ' => 'ⱅ', + 'Ⱆ' => 'ⱆ', + 'Ⱇ' => 'ⱇ', + 'Ⱈ' => 'ⱈ', + 'Ⱉ' => 'ⱉ', + 'Ⱊ' => 'ⱊ', + 'Ⱋ' => 'ⱋ', + 'Ⱌ' => 'ⱌ', + 'Ⱍ' => 'ⱍ', + 'Ⱎ' => 'ⱎ', + 'Ⱏ' => 'ⱏ', + 'Ⱐ' => 'ⱐ', + 'Ⱑ' => 'ⱑ', + 'Ⱒ' => 'ⱒ', + 'Ⱓ' => 'ⱓ', + 'Ⱔ' => 'ⱔ', + 'Ⱕ' => 'ⱕ', + 'Ⱖ' => 'ⱖ', + 'Ⱗ' => 'ⱗ', + 'Ⱘ' => 'ⱘ', + 'Ⱙ' => 'ⱙ', + 'Ⱚ' => 'ⱚ', + 'Ⱛ' => 'ⱛ', + 'Ⱜ' => 'ⱜ', + 'Ⱝ' => 'ⱝ', + 'Ⱞ' => 'ⱞ', + 'Ⱡ' => 'ⱡ', + 'Ɫ' => 'ɫ', + 'Ᵽ' => 'ᵽ', + 'Ɽ' => 'ɽ', + 'Ⱨ' => 'ⱨ', + 'Ⱪ' => 'ⱪ', + 'Ⱬ' => 'ⱬ', + 'Ɑ' => 'ɑ', + 'Ɱ' => 'ɱ', + 'Ɐ' => 'ɐ', + 'Ɒ' => 'ɒ', + 'Ⱳ' => 'ⱳ', + 'Ⱶ' => 'ⱶ', + 'Ȿ' => 'ȿ', + 'Ɀ' => 'ɀ', + 'Ⲁ' => 'ⲁ', + 'Ⲃ' => 'ⲃ', + 'Ⲅ' => 'ⲅ', + 'Ⲇ' => 'ⲇ', + 'Ⲉ' => 'ⲉ', + 'Ⲋ' => 'ⲋ', + 'Ⲍ' => 'ⲍ', + 'Ⲏ' => 'ⲏ', + 'Ⲑ' => 'ⲑ', + 'Ⲓ' => 'ⲓ', + 'Ⲕ' => 'ⲕ', + 'Ⲗ' => 'ⲗ', + 'Ⲙ' => 'ⲙ', + 'Ⲛ' => 'ⲛ', + 'Ⲝ' => 'ⲝ', + 'Ⲟ' => 'ⲟ', + 'Ⲡ' => 'ⲡ', + 'Ⲣ' => 'ⲣ', + 'Ⲥ' => 'ⲥ', + 'Ⲧ' => 'ⲧ', + 'Ⲩ' => 'ⲩ', + 'Ⲫ' => 'ⲫ', + 'Ⲭ' => 'ⲭ', + 'Ⲯ' => 'ⲯ', + 'Ⲱ' => 'ⲱ', + 'Ⲳ' => 'ⲳ', + 'Ⲵ' => 'ⲵ', + 'Ⲷ' => 'ⲷ', + 'Ⲹ' => 'ⲹ', + 'Ⲻ' => 'ⲻ', + 'Ⲽ' => 'ⲽ', + 'Ⲿ' => 'ⲿ', + 'Ⳁ' => 'ⳁ', + 'Ⳃ' => 'ⳃ', + 'Ⳅ' => 'ⳅ', + 'Ⳇ' => 'ⳇ', + 'Ⳉ' => 'ⳉ', + 'Ⳋ' => 'ⳋ', + 'Ⳍ' => 'ⳍ', + 'Ⳏ' => 'ⳏ', + 'Ⳑ' => 'ⳑ', + 'Ⳓ' => 'ⳓ', + 'Ⳕ' => 'ⳕ', + 'Ⳗ' => 'ⳗ', + 'Ⳙ' => 'ⳙ', + 'Ⳛ' => 'ⳛ', + 'Ⳝ' => 'ⳝ', + 'Ⳟ' => 'ⳟ', + 'Ⳡ' => 'ⳡ', + 'Ⳣ' => 'ⳣ', + 'Ⳬ' => 'ⳬ', + 'Ⳮ' => 'ⳮ', + 'Ⳳ' => 'ⳳ', + 'Ꙁ' => 'ꙁ', + 'Ꙃ' => 'ꙃ', + 'Ꙅ' => 'ꙅ', + 'Ꙇ' => 'ꙇ', + 'Ꙉ' => 'ꙉ', + 'Ꙋ' => 'ꙋ', + 'Ꙍ' => 'ꙍ', + 'Ꙏ' => 'ꙏ', + 'Ꙑ' => 'ꙑ', + 'Ꙓ' => 'ꙓ', + 'Ꙕ' => 'ꙕ', + 'Ꙗ' => 'ꙗ', + 'Ꙙ' => 'ꙙ', + 'Ꙛ' => 'ꙛ', + 'Ꙝ' => 'ꙝ', + 'Ꙟ' => 'ꙟ', + 'Ꙡ' => 'ꙡ', + 'Ꙣ' => 'ꙣ', + 'Ꙥ' => 'ꙥ', + 'Ꙧ' => 'ꙧ', + 'Ꙩ' => 'ꙩ', + 'Ꙫ' => 'ꙫ', + 'Ꙭ' => 'ꙭ', + 'Ꚁ' => 'ꚁ', + 'Ꚃ' => 'ꚃ', + 'Ꚅ' => 'ꚅ', + 'Ꚇ' => 'ꚇ', + 'Ꚉ' => 'ꚉ', + 'Ꚋ' => 'ꚋ', + 'Ꚍ' => 'ꚍ', + 'Ꚏ' => 'ꚏ', + 'Ꚑ' => 'ꚑ', + 'Ꚓ' => 'ꚓ', + 'Ꚕ' => 'ꚕ', + 'Ꚗ' => 'ꚗ', + 'Ꚙ' => 'ꚙ', + 'Ꚛ' => 'ꚛ', + 'Ꜣ' => 'ꜣ', + 'Ꜥ' => 'ꜥ', + 'Ꜧ' => 'ꜧ', + 'Ꜩ' => 'ꜩ', + 'Ꜫ' => 'ꜫ', + 'Ꜭ' => 'ꜭ', + 'Ꜯ' => 'ꜯ', + 'Ꜳ' => 'ꜳ', + 'Ꜵ' => 'ꜵ', + 'Ꜷ' => 'ꜷ', + 'Ꜹ' => 'ꜹ', + 'Ꜻ' => 'ꜻ', + 'Ꜽ' => 'ꜽ', + 'Ꜿ' => 'ꜿ', + 'Ꝁ' => 'ꝁ', + 'Ꝃ' => 'ꝃ', + 'Ꝅ' => 'ꝅ', + 'Ꝇ' => 'ꝇ', + 'Ꝉ' => 'ꝉ', + 'Ꝋ' => 'ꝋ', + 'Ꝍ' => 'ꝍ', + 'Ꝏ' => 'ꝏ', + 'Ꝑ' => 'ꝑ', + 'Ꝓ' => 'ꝓ', + 'Ꝕ' => 'ꝕ', + 'Ꝗ' => 'ꝗ', + 'Ꝙ' => 'ꝙ', + 'Ꝛ' => 'ꝛ', + 'Ꝝ' => 'ꝝ', + 'Ꝟ' => 'ꝟ', + 'Ꝡ' => 'ꝡ', + 'Ꝣ' => 'ꝣ', + 'Ꝥ' => 'ꝥ', + 'Ꝧ' => 'ꝧ', + 'Ꝩ' => 'ꝩ', + 'Ꝫ' => 'ꝫ', + 'Ꝭ' => 'ꝭ', + 'Ꝯ' => 'ꝯ', + 'Ꝺ' => 'ꝺ', + 'Ꝼ' => 'ꝼ', + 'Ᵹ' => 'ᵹ', + 'Ꝿ' => 'ꝿ', + 'Ꞁ' => 'ꞁ', + 'Ꞃ' => 'ꞃ', + 'Ꞅ' => 'ꞅ', + 'Ꞇ' => 'ꞇ', + 'Ꞌ' => 'ꞌ', + 'Ɥ' => 'ɥ', + 'Ꞑ' => 'ꞑ', + 'Ꞓ' => 'ꞓ', + 'Ꞗ' => 'ꞗ', + 'Ꞙ' => 'ꞙ', + 'Ꞛ' => 'ꞛ', + 'Ꞝ' => 'ꞝ', + 'Ꞟ' => 'ꞟ', + 'Ꞡ' => 'ꞡ', + 'Ꞣ' => 'ꞣ', + 'Ꞥ' => 'ꞥ', + 'Ꞧ' => 'ꞧ', + 'Ꞩ' => 'ꞩ', + 'Ɦ' => 'ɦ', + 'Ɜ' => 'ɜ', + 'Ɡ' => 'ɡ', + 'Ɬ' => 'ɬ', + 'Ɪ' => 'ɪ', + 'Ʞ' => 'ʞ', + 'Ʇ' => 'ʇ', + 'Ʝ' => 'ʝ', + 'Ꭓ' => 'ꭓ', + 'Ꞵ' => 'ꞵ', + 'Ꞷ' => 'ꞷ', + 'Ꞹ' => 'ꞹ', + 'Ꞻ' => 'ꞻ', + 'Ꞽ' => 'ꞽ', + 'Ꞿ' => 'ꞿ', + 'Ꟃ' => 'ꟃ', + 'Ꞔ' => 'ꞔ', + 'Ʂ' => 'ʂ', + 'Ᶎ' => 'ᶎ', + 'Ꟈ' => 'ꟈ', + 'Ꟊ' => 'ꟊ', + 'Ꟶ' => 'ꟶ', + 'A' => 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + '𐐀' => '𐐨', + '𐐁' => '𐐩', + '𐐂' => '𐐪', + '𐐃' => '𐐫', + '𐐄' => '𐐬', + '𐐅' => '𐐭', + '𐐆' => '𐐮', + '𐐇' => '𐐯', + '𐐈' => '𐐰', + '𐐉' => '𐐱', + '𐐊' => '𐐲', + '𐐋' => '𐐳', + '𐐌' => '𐐴', + '𐐍' => '𐐵', + '𐐎' => '𐐶', + '𐐏' => '𐐷', + '𐐐' => '𐐸', + '𐐑' => '𐐹', + '𐐒' => '𐐺', + '𐐓' => '𐐻', + '𐐔' => '𐐼', + '𐐕' => '𐐽', + '𐐖' => '𐐾', + '𐐗' => '𐐿', + '𐐘' => '𐑀', + '𐐙' => '𐑁', + '𐐚' => '𐑂', + '𐐛' => '𐑃', + '𐐜' => '𐑄', + '𐐝' => '𐑅', + '𐐞' => '𐑆', + '𐐟' => '𐑇', + '𐐠' => '𐑈', + '𐐡' => '𐑉', + '𐐢' => '𐑊', + '𐐣' => '𐑋', + '𐐤' => '𐑌', + '𐐥' => '𐑍', + '𐐦' => '𐑎', + '𐐧' => '𐑏', + '𐒰' => '𐓘', + '𐒱' => '𐓙', + '𐒲' => '𐓚', + '𐒳' => '𐓛', + '𐒴' => '𐓜', + '𐒵' => '𐓝', + '𐒶' => '𐓞', + '𐒷' => '𐓟', + '𐒸' => '𐓠', + '𐒹' => '𐓡', + '𐒺' => '𐓢', + '𐒻' => '𐓣', + '𐒼' => '𐓤', + '𐒽' => '𐓥', + '𐒾' => '𐓦', + '𐒿' => '𐓧', + '𐓀' => '𐓨', + '𐓁' => '𐓩', + '𐓂' => '𐓪', + '𐓃' => '𐓫', + '𐓄' => '𐓬', + '𐓅' => '𐓭', + '𐓆' => '𐓮', + '𐓇' => '𐓯', + '𐓈' => '𐓰', + '𐓉' => '𐓱', + '𐓊' => '𐓲', + '𐓋' => '𐓳', + '𐓌' => '𐓴', + '𐓍' => '𐓵', + '𐓎' => '𐓶', + '𐓏' => '𐓷', + '𐓐' => '𐓸', + '𐓑' => '𐓹', + '𐓒' => '𐓺', + '𐓓' => '𐓻', + '𐲀' => '𐳀', + '𐲁' => '𐳁', + '𐲂' => '𐳂', + '𐲃' => '𐳃', + '𐲄' => '𐳄', + '𐲅' => '𐳅', + '𐲆' => '𐳆', + '𐲇' => '𐳇', + '𐲈' => '𐳈', + '𐲉' => '𐳉', + '𐲊' => '𐳊', + '𐲋' => '𐳋', + '𐲌' => '𐳌', + '𐲍' => '𐳍', + '𐲎' => '𐳎', + '𐲏' => '𐳏', + '𐲐' => '𐳐', + '𐲑' => '𐳑', + '𐲒' => '𐳒', + '𐲓' => '𐳓', + '𐲔' => '𐳔', + '𐲕' => '𐳕', + '𐲖' => '𐳖', + '𐲗' => '𐳗', + '𐲘' => '𐳘', + '𐲙' => '𐳙', + '𐲚' => '𐳚', + '𐲛' => '𐳛', + '𐲜' => '𐳜', + '𐲝' => '𐳝', + '𐲞' => '𐳞', + '𐲟' => '𐳟', + '𐲠' => '𐳠', + '𐲡' => '𐳡', + '𐲢' => '𐳢', + '𐲣' => '𐳣', + '𐲤' => '𐳤', + '𐲥' => '𐳥', + '𐲦' => '𐳦', + '𐲧' => '𐳧', + '𐲨' => '𐳨', + '𐲩' => '𐳩', + '𐲪' => '𐳪', + '𐲫' => '𐳫', + '𐲬' => '𐳬', + '𐲭' => '𐳭', + '𐲮' => '𐳮', + '𐲯' => '𐳯', + '𐲰' => '𐳰', + '𐲱' => '𐳱', + '𐲲' => '𐳲', + '𑢠' => '𑣀', + '𑢡' => '𑣁', + '𑢢' => '𑣂', + '𑢣' => '𑣃', + '𑢤' => '𑣄', + '𑢥' => '𑣅', + '𑢦' => '𑣆', + '𑢧' => '𑣇', + '𑢨' => '𑣈', + '𑢩' => '𑣉', + '𑢪' => '𑣊', + '𑢫' => '𑣋', + '𑢬' => '𑣌', + '𑢭' => '𑣍', + '𑢮' => '𑣎', + '𑢯' => '𑣏', + '𑢰' => '𑣐', + '𑢱' => '𑣑', + '𑢲' => '𑣒', + '𑢳' => '𑣓', + '𑢴' => '𑣔', + '𑢵' => '𑣕', + '𑢶' => '𑣖', + '𑢷' => '𑣗', + '𑢸' => '𑣘', + '𑢹' => '𑣙', + '𑢺' => '𑣚', + '𑢻' => '𑣛', + '𑢼' => '𑣜', + '𑢽' => '𑣝', + '𑢾' => '𑣞', + '𑢿' => '𑣟', + '𖹀' => '𖹠', + '𖹁' => '𖹡', + '𖹂' => '𖹢', + '𖹃' => '𖹣', + '𖹄' => '𖹤', + '𖹅' => '𖹥', + '𖹆' => '𖹦', + '𖹇' => '𖹧', + '𖹈' => '𖹨', + '𖹉' => '𖹩', + '𖹊' => '𖹪', + '𖹋' => '𖹫', + '𖹌' => '𖹬', + '𖹍' => '𖹭', + '𖹎' => '𖹮', + '𖹏' => '𖹯', + '𖹐' => '𖹰', + '𖹑' => '𖹱', + '𖹒' => '𖹲', + '𖹓' => '𖹳', + '𖹔' => '𖹴', + '𖹕' => '𖹵', + '𖹖' => '𖹶', + '𖹗' => '𖹷', + '𖹘' => '𖹸', + '𖹙' => '𖹹', + '𖹚' => '𖹺', + '𖹛' => '𖹻', + '𖹜' => '𖹼', + '𖹝' => '𖹽', + '𖹞' => '𖹾', + '𖹟' => '𖹿', + '𞤀' => '𞤢', + '𞤁' => '𞤣', + '𞤂' => '𞤤', + '𞤃' => '𞤥', + '𞤄' => '𞤦', + '𞤅' => '𞤧', + '𞤆' => '𞤨', + '𞤇' => '𞤩', + '𞤈' => '𞤪', + '𞤉' => '𞤫', + '𞤊' => '𞤬', + '𞤋' => '𞤭', + '𞤌' => '𞤮', + '𞤍' => '𞤯', + '𞤎' => '𞤰', + '𞤏' => '𞤱', + '𞤐' => '𞤲', + '𞤑' => '𞤳', + '𞤒' => '𞤴', + '𞤓' => '𞤵', + '𞤔' => '𞤶', + '𞤕' => '𞤷', + '𞤖' => '𞤸', + '𞤗' => '𞤹', + '𞤘' => '𞤺', + '𞤙' => '𞤻', + '𞤚' => '𞤼', + '𞤛' => '𞤽', + '𞤜' => '𞤾', + '𞤝' => '𞤿', + '𞤞' => '𞥀', + '𞤟' => '𞥁', + '𞤠' => '𞥂', + '𞤡' => '𞥃', +); diff --git a/system/libs/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php b/system/libs/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php new file mode 100644 index 0000000000..2a8f6e73b9 --- /dev/null +++ b/system/libs/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php @@ -0,0 +1,5 @@ + 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + 'µ' => 'Μ', + 'à' => 'À', + 'á' => 'Á', + 'â' => 'Â', + 'ã' => 'Ã', + 'ä' => 'Ä', + 'å' => 'Å', + 'æ' => 'Æ', + 'ç' => 'Ç', + 'è' => 'È', + 'é' => 'É', + 'ê' => 'Ê', + 'ë' => 'Ë', + 'ì' => 'Ì', + 'í' => 'Í', + 'î' => 'Î', + 'ï' => 'Ï', + 'ð' => 'Ð', + 'ñ' => 'Ñ', + 'ò' => 'Ò', + 'ó' => 'Ó', + 'ô' => 'Ô', + 'õ' => 'Õ', + 'ö' => 'Ö', + 'ø' => 'Ø', + 'ù' => 'Ù', + 'ú' => 'Ú', + 'û' => 'Û', + 'ü' => 'Ü', + 'ý' => 'Ý', + 'þ' => 'Þ', + 'ÿ' => 'Ÿ', + 'ā' => 'Ā', + 'ă' => 'Ă', + 'ą' => 'Ą', + 'ć' => 'Ć', + 'ĉ' => 'Ĉ', + 'ċ' => 'Ċ', + 'č' => 'Č', + 'ď' => 'Ď', + 'đ' => 'Đ', + 'ē' => 'Ē', + 'ĕ' => 'Ĕ', + 'ė' => 'Ė', + 'ę' => 'Ę', + 'ě' => 'Ě', + 'ĝ' => 'Ĝ', + 'ğ' => 'Ğ', + 'ġ' => 'Ġ', + 'ģ' => 'Ģ', + 'ĥ' => 'Ĥ', + 'ħ' => 'Ħ', + 'ĩ' => 'Ĩ', + 'ī' => 'Ī', + 'ĭ' => 'Ĭ', + 'į' => 'Į', + 'ı' => 'I', + 'ij' => 'IJ', + 'ĵ' => 'Ĵ', + 'ķ' => 'Ķ', + 'ĺ' => 'Ĺ', + 'ļ' => 'Ļ', + 'ľ' => 'Ľ', + 'ŀ' => 'Ŀ', + 'ł' => 'Ł', + 'ń' => 'Ń', + 'ņ' => 'Ņ', + 'ň' => 'Ň', + 'ŋ' => 'Ŋ', + 'ō' => 'Ō', + 'ŏ' => 'Ŏ', + 'ő' => 'Ő', + 'œ' => 'Œ', + 'ŕ' => 'Ŕ', + 'ŗ' => 'Ŗ', + 'ř' => 'Ř', + 'ś' => 'Ś', + 'ŝ' => 'Ŝ', + 'ş' => 'Ş', + 'š' => 'Š', + 'ţ' => 'Ţ', + 'ť' => 'Ť', + 'ŧ' => 'Ŧ', + 'ũ' => 'Ũ', + 'ū' => 'Ū', + 'ŭ' => 'Ŭ', + 'ů' => 'Ů', + 'ű' => 'Ű', + 'ų' => 'Ų', + 'ŵ' => 'Ŵ', + 'ŷ' => 'Ŷ', + 'ź' => 'Ź', + 'ż' => 'Ż', + 'ž' => 'Ž', + 'ſ' => 'S', + 'ƀ' => 'Ƀ', + 'ƃ' => 'Ƃ', + 'ƅ' => 'Ƅ', + 'ƈ' => 'Ƈ', + 'ƌ' => 'Ƌ', + 'ƒ' => 'Ƒ', + 'ƕ' => 'Ƕ', + 'ƙ' => 'Ƙ', + 'ƚ' => 'Ƚ', + 'ƞ' => 'Ƞ', + 'ơ' => 'Ơ', + 'ƣ' => 'Ƣ', + 'ƥ' => 'Ƥ', + 'ƨ' => 'Ƨ', + 'ƭ' => 'Ƭ', + 'ư' => 'Ư', + 'ƴ' => 'Ƴ', + 'ƶ' => 'Ƶ', + 'ƹ' => 'Ƹ', + 'ƽ' => 'Ƽ', + 'ƿ' => 'Ƿ', + 'Dž' => 'DŽ', + 'dž' => 'DŽ', + 'Lj' => 'LJ', + 'lj' => 'LJ', + 'Nj' => 'NJ', + 'nj' => 'NJ', + 'ǎ' => 'Ǎ', + 'ǐ' => 'Ǐ', + 'ǒ' => 'Ǒ', + 'ǔ' => 'Ǔ', + 'ǖ' => 'Ǖ', + 'ǘ' => 'Ǘ', + 'ǚ' => 'Ǚ', + 'ǜ' => 'Ǜ', + 'ǝ' => 'Ǝ', + 'ǟ' => 'Ǟ', + 'ǡ' => 'Ǡ', + 'ǣ' => 'Ǣ', + 'ǥ' => 'Ǥ', + 'ǧ' => 'Ǧ', + 'ǩ' => 'Ǩ', + 'ǫ' => 'Ǫ', + 'ǭ' => 'Ǭ', + 'ǯ' => 'Ǯ', + 'Dz' => 'DZ', + 'dz' => 'DZ', + 'ǵ' => 'Ǵ', + 'ǹ' => 'Ǹ', + 'ǻ' => 'Ǻ', + 'ǽ' => 'Ǽ', + 'ǿ' => 'Ǿ', + 'ȁ' => 'Ȁ', + 'ȃ' => 'Ȃ', + 'ȅ' => 'Ȅ', + 'ȇ' => 'Ȇ', + 'ȉ' => 'Ȉ', + 'ȋ' => 'Ȋ', + 'ȍ' => 'Ȍ', + 'ȏ' => 'Ȏ', + 'ȑ' => 'Ȑ', + 'ȓ' => 'Ȓ', + 'ȕ' => 'Ȕ', + 'ȗ' => 'Ȗ', + 'ș' => 'Ș', + 'ț' => 'Ț', + 'ȝ' => 'Ȝ', + 'ȟ' => 'Ȟ', + 'ȣ' => 'Ȣ', + 'ȥ' => 'Ȥ', + 'ȧ' => 'Ȧ', + 'ȩ' => 'Ȩ', + 'ȫ' => 'Ȫ', + 'ȭ' => 'Ȭ', + 'ȯ' => 'Ȯ', + 'ȱ' => 'Ȱ', + 'ȳ' => 'Ȳ', + 'ȼ' => 'Ȼ', + 'ȿ' => 'Ȿ', + 'ɀ' => 'Ɀ', + 'ɂ' => 'Ɂ', + 'ɇ' => 'Ɇ', + 'ɉ' => 'Ɉ', + 'ɋ' => 'Ɋ', + 'ɍ' => 'Ɍ', + 'ɏ' => 'Ɏ', + 'ɐ' => 'Ɐ', + 'ɑ' => 'Ɑ', + 'ɒ' => 'Ɒ', + 'ɓ' => 'Ɓ', + 'ɔ' => 'Ɔ', + 'ɖ' => 'Ɖ', + 'ɗ' => 'Ɗ', + 'ə' => 'Ə', + 'ɛ' => 'Ɛ', + 'ɜ' => 'Ɜ', + 'ɠ' => 'Ɠ', + 'ɡ' => 'Ɡ', + 'ɣ' => 'Ɣ', + 'ɥ' => 'Ɥ', + 'ɦ' => 'Ɦ', + 'ɨ' => 'Ɨ', + 'ɩ' => 'Ɩ', + 'ɪ' => 'Ɪ', + 'ɫ' => 'Ɫ', + 'ɬ' => 'Ɬ', + 'ɯ' => 'Ɯ', + 'ɱ' => 'Ɱ', + 'ɲ' => 'Ɲ', + 'ɵ' => 'Ɵ', + 'ɽ' => 'Ɽ', + 'ʀ' => 'Ʀ', + 'ʂ' => 'Ʂ', + 'ʃ' => 'Ʃ', + 'ʇ' => 'Ʇ', + 'ʈ' => 'Ʈ', + 'ʉ' => 'Ʉ', + 'ʊ' => 'Ʊ', + 'ʋ' => 'Ʋ', + 'ʌ' => 'Ʌ', + 'ʒ' => 'Ʒ', + 'ʝ' => 'Ʝ', + 'ʞ' => 'Ʞ', + 'ͅ' => 'Ι', + 'ͱ' => 'Ͱ', + 'ͳ' => 'Ͳ', + 'ͷ' => 'Ͷ', + 'ͻ' => 'Ͻ', + 'ͼ' => 'Ͼ', + 'ͽ' => 'Ͽ', + 'ά' => 'Ά', + 'έ' => 'Έ', + 'ή' => 'Ή', + 'ί' => 'Ί', + 'α' => 'Α', + 'β' => 'Β', + 'γ' => 'Γ', + 'δ' => 'Δ', + 'ε' => 'Ε', + 'ζ' => 'Ζ', + 'η' => 'Η', + 'θ' => 'Θ', + 'ι' => 'Ι', + 'κ' => 'Κ', + 'λ' => 'Λ', + 'μ' => 'Μ', + 'ν' => 'Ν', + 'ξ' => 'Ξ', + 'ο' => 'Ο', + 'π' => 'Π', + 'ρ' => 'Ρ', + 'ς' => 'Σ', + 'σ' => 'Σ', + 'τ' => 'Τ', + 'υ' => 'Υ', + 'φ' => 'Φ', + 'χ' => 'Χ', + 'ψ' => 'Ψ', + 'ω' => 'Ω', + 'ϊ' => 'Ϊ', + 'ϋ' => 'Ϋ', + 'ό' => 'Ό', + 'ύ' => 'Ύ', + 'ώ' => 'Ώ', + 'ϐ' => 'Β', + 'ϑ' => 'Θ', + 'ϕ' => 'Φ', + 'ϖ' => 'Π', + 'ϗ' => 'Ϗ', + 'ϙ' => 'Ϙ', + 'ϛ' => 'Ϛ', + 'ϝ' => 'Ϝ', + 'ϟ' => 'Ϟ', + 'ϡ' => 'Ϡ', + 'ϣ' => 'Ϣ', + 'ϥ' => 'Ϥ', + 'ϧ' => 'Ϧ', + 'ϩ' => 'Ϩ', + 'ϫ' => 'Ϫ', + 'ϭ' => 'Ϭ', + 'ϯ' => 'Ϯ', + 'ϰ' => 'Κ', + 'ϱ' => 'Ρ', + 'ϲ' => 'Ϲ', + 'ϳ' => 'Ϳ', + 'ϵ' => 'Ε', + 'ϸ' => 'Ϸ', + 'ϻ' => 'Ϻ', + 'а' => 'А', + 'б' => 'Б', + 'в' => 'В', + 'г' => 'Г', + 'д' => 'Д', + 'е' => 'Е', + 'ж' => 'Ж', + 'з' => 'З', + 'и' => 'И', + 'й' => 'Й', + 'к' => 'К', + 'л' => 'Л', + 'м' => 'М', + 'н' => 'Н', + 'о' => 'О', + 'п' => 'П', + 'р' => 'Р', + 'с' => 'С', + 'т' => 'Т', + 'у' => 'У', + 'ф' => 'Ф', + 'х' => 'Х', + 'ц' => 'Ц', + 'ч' => 'Ч', + 'ш' => 'Ш', + 'щ' => 'Щ', + 'ъ' => 'Ъ', + 'ы' => 'Ы', + 'ь' => 'Ь', + 'э' => 'Э', + 'ю' => 'Ю', + 'я' => 'Я', + 'ѐ' => 'Ѐ', + 'ё' => 'Ё', + 'ђ' => 'Ђ', + 'ѓ' => 'Ѓ', + 'є' => 'Є', + 'ѕ' => 'Ѕ', + 'і' => 'І', + 'ї' => 'Ї', + 'ј' => 'Ј', + 'љ' => 'Љ', + 'њ' => 'Њ', + 'ћ' => 'Ћ', + 'ќ' => 'Ќ', + 'ѝ' => 'Ѝ', + 'ў' => 'Ў', + 'џ' => 'Џ', + 'ѡ' => 'Ѡ', + 'ѣ' => 'Ѣ', + 'ѥ' => 'Ѥ', + 'ѧ' => 'Ѧ', + 'ѩ' => 'Ѩ', + 'ѫ' => 'Ѫ', + 'ѭ' => 'Ѭ', + 'ѯ' => 'Ѯ', + 'ѱ' => 'Ѱ', + 'ѳ' => 'Ѳ', + 'ѵ' => 'Ѵ', + 'ѷ' => 'Ѷ', + 'ѹ' => 'Ѹ', + 'ѻ' => 'Ѻ', + 'ѽ' => 'Ѽ', + 'ѿ' => 'Ѿ', + 'ҁ' => 'Ҁ', + 'ҋ' => 'Ҋ', + 'ҍ' => 'Ҍ', + 'ҏ' => 'Ҏ', + 'ґ' => 'Ґ', + 'ғ' => 'Ғ', + 'ҕ' => 'Ҕ', + 'җ' => 'Җ', + 'ҙ' => 'Ҙ', + 'қ' => 'Қ', + 'ҝ' => 'Ҝ', + 'ҟ' => 'Ҟ', + 'ҡ' => 'Ҡ', + 'ң' => 'Ң', + 'ҥ' => 'Ҥ', + 'ҧ' => 'Ҧ', + 'ҩ' => 'Ҩ', + 'ҫ' => 'Ҫ', + 'ҭ' => 'Ҭ', + 'ү' => 'Ү', + 'ұ' => 'Ұ', + 'ҳ' => 'Ҳ', + 'ҵ' => 'Ҵ', + 'ҷ' => 'Ҷ', + 'ҹ' => 'Ҹ', + 'һ' => 'Һ', + 'ҽ' => 'Ҽ', + 'ҿ' => 'Ҿ', + 'ӂ' => 'Ӂ', + 'ӄ' => 'Ӄ', + 'ӆ' => 'Ӆ', + 'ӈ' => 'Ӈ', + 'ӊ' => 'Ӊ', + 'ӌ' => 'Ӌ', + 'ӎ' => 'Ӎ', + 'ӏ' => 'Ӏ', + 'ӑ' => 'Ӑ', + 'ӓ' => 'Ӓ', + 'ӕ' => 'Ӕ', + 'ӗ' => 'Ӗ', + 'ә' => 'Ә', + 'ӛ' => 'Ӛ', + 'ӝ' => 'Ӝ', + 'ӟ' => 'Ӟ', + 'ӡ' => 'Ӡ', + 'ӣ' => 'Ӣ', + 'ӥ' => 'Ӥ', + 'ӧ' => 'Ӧ', + 'ө' => 'Ө', + 'ӫ' => 'Ӫ', + 'ӭ' => 'Ӭ', + 'ӯ' => 'Ӯ', + 'ӱ' => 'Ӱ', + 'ӳ' => 'Ӳ', + 'ӵ' => 'Ӵ', + 'ӷ' => 'Ӷ', + 'ӹ' => 'Ӹ', + 'ӻ' => 'Ӻ', + 'ӽ' => 'Ӽ', + 'ӿ' => 'Ӿ', + 'ԁ' => 'Ԁ', + 'ԃ' => 'Ԃ', + 'ԅ' => 'Ԅ', + 'ԇ' => 'Ԇ', + 'ԉ' => 'Ԉ', + 'ԋ' => 'Ԋ', + 'ԍ' => 'Ԍ', + 'ԏ' => 'Ԏ', + 'ԑ' => 'Ԑ', + 'ԓ' => 'Ԓ', + 'ԕ' => 'Ԕ', + 'ԗ' => 'Ԗ', + 'ԙ' => 'Ԙ', + 'ԛ' => 'Ԛ', + 'ԝ' => 'Ԝ', + 'ԟ' => 'Ԟ', + 'ԡ' => 'Ԡ', + 'ԣ' => 'Ԣ', + 'ԥ' => 'Ԥ', + 'ԧ' => 'Ԧ', + 'ԩ' => 'Ԩ', + 'ԫ' => 'Ԫ', + 'ԭ' => 'Ԭ', + 'ԯ' => 'Ԯ', + 'ա' => 'Ա', + 'բ' => 'Բ', + 'գ' => 'Գ', + 'դ' => 'Դ', + 'ե' => 'Ե', + 'զ' => 'Զ', + 'է' => 'Է', + 'ը' => 'Ը', + 'թ' => 'Թ', + 'ժ' => 'Ժ', + 'ի' => 'Ի', + 'լ' => 'Լ', + 'խ' => 'Խ', + 'ծ' => 'Ծ', + 'կ' => 'Կ', + 'հ' => 'Հ', + 'ձ' => 'Ձ', + 'ղ' => 'Ղ', + 'ճ' => 'Ճ', + 'մ' => 'Մ', + 'յ' => 'Յ', + 'ն' => 'Ն', + 'շ' => 'Շ', + 'ո' => 'Ո', + 'չ' => 'Չ', + 'պ' => 'Պ', + 'ջ' => 'Ջ', + 'ռ' => 'Ռ', + 'ս' => 'Ս', + 'վ' => 'Վ', + 'տ' => 'Տ', + 'ր' => 'Ր', + 'ց' => 'Ց', + 'ւ' => 'Ւ', + 'փ' => 'Փ', + 'ք' => 'Ք', + 'օ' => 'Օ', + 'ֆ' => 'Ֆ', + 'ა' => 'Ა', + 'ბ' => 'Ბ', + 'გ' => 'Გ', + 'დ' => 'Დ', + 'ე' => 'Ე', + 'ვ' => 'Ვ', + 'ზ' => 'Ზ', + 'თ' => 'Თ', + 'ი' => 'Ი', + 'კ' => 'Კ', + 'ლ' => 'Ლ', + 'მ' => 'Მ', + 'ნ' => 'Ნ', + 'ო' => 'Ო', + 'პ' => 'Პ', + 'ჟ' => 'Ჟ', + 'რ' => 'Რ', + 'ს' => 'Ს', + 'ტ' => 'Ტ', + 'უ' => 'Უ', + 'ფ' => 'Ფ', + 'ქ' => 'Ქ', + 'ღ' => 'Ღ', + 'ყ' => 'Ყ', + 'შ' => 'Შ', + 'ჩ' => 'Ჩ', + 'ც' => 'Ც', + 'ძ' => 'Ძ', + 'წ' => 'Წ', + 'ჭ' => 'Ჭ', + 'ხ' => 'Ხ', + 'ჯ' => 'Ჯ', + 'ჰ' => 'Ჰ', + 'ჱ' => 'Ჱ', + 'ჲ' => 'Ჲ', + 'ჳ' => 'Ჳ', + 'ჴ' => 'Ჴ', + 'ჵ' => 'Ჵ', + 'ჶ' => 'Ჶ', + 'ჷ' => 'Ჷ', + 'ჸ' => 'Ჸ', + 'ჹ' => 'Ჹ', + 'ჺ' => 'Ჺ', + 'ჽ' => 'Ჽ', + 'ჾ' => 'Ჾ', + 'ჿ' => 'Ჿ', + 'ᏸ' => 'Ᏸ', + 'ᏹ' => 'Ᏹ', + 'ᏺ' => 'Ᏺ', + 'ᏻ' => 'Ᏻ', + 'ᏼ' => 'Ᏼ', + 'ᏽ' => 'Ᏽ', + 'ᲀ' => 'В', + 'ᲁ' => 'Д', + 'ᲂ' => 'О', + 'ᲃ' => 'С', + 'ᲄ' => 'Т', + 'ᲅ' => 'Т', + 'ᲆ' => 'Ъ', + 'ᲇ' => 'Ѣ', + 'ᲈ' => 'Ꙋ', + 'ᵹ' => 'Ᵹ', + 'ᵽ' => 'Ᵽ', + 'ᶎ' => 'Ᶎ', + 'ḁ' => 'Ḁ', + 'ḃ' => 'Ḃ', + 'ḅ' => 'Ḅ', + 'ḇ' => 'Ḇ', + 'ḉ' => 'Ḉ', + 'ḋ' => 'Ḋ', + 'ḍ' => 'Ḍ', + 'ḏ' => 'Ḏ', + 'ḑ' => 'Ḑ', + 'ḓ' => 'Ḓ', + 'ḕ' => 'Ḕ', + 'ḗ' => 'Ḗ', + 'ḙ' => 'Ḙ', + 'ḛ' => 'Ḛ', + 'ḝ' => 'Ḝ', + 'ḟ' => 'Ḟ', + 'ḡ' => 'Ḡ', + 'ḣ' => 'Ḣ', + 'ḥ' => 'Ḥ', + 'ḧ' => 'Ḧ', + 'ḩ' => 'Ḩ', + 'ḫ' => 'Ḫ', + 'ḭ' => 'Ḭ', + 'ḯ' => 'Ḯ', + 'ḱ' => 'Ḱ', + 'ḳ' => 'Ḳ', + 'ḵ' => 'Ḵ', + 'ḷ' => 'Ḷ', + 'ḹ' => 'Ḹ', + 'ḻ' => 'Ḻ', + 'ḽ' => 'Ḽ', + 'ḿ' => 'Ḿ', + 'ṁ' => 'Ṁ', + 'ṃ' => 'Ṃ', + 'ṅ' => 'Ṅ', + 'ṇ' => 'Ṇ', + 'ṉ' => 'Ṉ', + 'ṋ' => 'Ṋ', + 'ṍ' => 'Ṍ', + 'ṏ' => 'Ṏ', + 'ṑ' => 'Ṑ', + 'ṓ' => 'Ṓ', + 'ṕ' => 'Ṕ', + 'ṗ' => 'Ṗ', + 'ṙ' => 'Ṙ', + 'ṛ' => 'Ṛ', + 'ṝ' => 'Ṝ', + 'ṟ' => 'Ṟ', + 'ṡ' => 'Ṡ', + 'ṣ' => 'Ṣ', + 'ṥ' => 'Ṥ', + 'ṧ' => 'Ṧ', + 'ṩ' => 'Ṩ', + 'ṫ' => 'Ṫ', + 'ṭ' => 'Ṭ', + 'ṯ' => 'Ṯ', + 'ṱ' => 'Ṱ', + 'ṳ' => 'Ṳ', + 'ṵ' => 'Ṵ', + 'ṷ' => 'Ṷ', + 'ṹ' => 'Ṹ', + 'ṻ' => 'Ṻ', + 'ṽ' => 'Ṽ', + 'ṿ' => 'Ṿ', + 'ẁ' => 'Ẁ', + 'ẃ' => 'Ẃ', + 'ẅ' => 'Ẅ', + 'ẇ' => 'Ẇ', + 'ẉ' => 'Ẉ', + 'ẋ' => 'Ẋ', + 'ẍ' => 'Ẍ', + 'ẏ' => 'Ẏ', + 'ẑ' => 'Ẑ', + 'ẓ' => 'Ẓ', + 'ẕ' => 'Ẕ', + 'ẛ' => 'Ṡ', + 'ạ' => 'Ạ', + 'ả' => 'Ả', + 'ấ' => 'Ấ', + 'ầ' => 'Ầ', + 'ẩ' => 'Ẩ', + 'ẫ' => 'Ẫ', + 'ậ' => 'Ậ', + 'ắ' => 'Ắ', + 'ằ' => 'Ằ', + 'ẳ' => 'Ẳ', + 'ẵ' => 'Ẵ', + 'ặ' => 'Ặ', + 'ẹ' => 'Ẹ', + 'ẻ' => 'Ẻ', + 'ẽ' => 'Ẽ', + 'ế' => 'Ế', + 'ề' => 'Ề', + 'ể' => 'Ể', + 'ễ' => 'Ễ', + 'ệ' => 'Ệ', + 'ỉ' => 'Ỉ', + 'ị' => 'Ị', + 'ọ' => 'Ọ', + 'ỏ' => 'Ỏ', + 'ố' => 'Ố', + 'ồ' => 'Ồ', + 'ổ' => 'Ổ', + 'ỗ' => 'Ỗ', + 'ộ' => 'Ộ', + 'ớ' => 'Ớ', + 'ờ' => 'Ờ', + 'ở' => 'Ở', + 'ỡ' => 'Ỡ', + 'ợ' => 'Ợ', + 'ụ' => 'Ụ', + 'ủ' => 'Ủ', + 'ứ' => 'Ứ', + 'ừ' => 'Ừ', + 'ử' => 'Ử', + 'ữ' => 'Ữ', + 'ự' => 'Ự', + 'ỳ' => 'Ỳ', + 'ỵ' => 'Ỵ', + 'ỷ' => 'Ỷ', + 'ỹ' => 'Ỹ', + 'ỻ' => 'Ỻ', + 'ỽ' => 'Ỽ', + 'ỿ' => 'Ỿ', + 'ἀ' => 'Ἀ', + 'ἁ' => 'Ἁ', + 'ἂ' => 'Ἂ', + 'ἃ' => 'Ἃ', + 'ἄ' => 'Ἄ', + 'ἅ' => 'Ἅ', + 'ἆ' => 'Ἆ', + 'ἇ' => 'Ἇ', + 'ἐ' => 'Ἐ', + 'ἑ' => 'Ἑ', + 'ἒ' => 'Ἒ', + 'ἓ' => 'Ἓ', + 'ἔ' => 'Ἔ', + 'ἕ' => 'Ἕ', + 'ἠ' => 'Ἠ', + 'ἡ' => 'Ἡ', + 'ἢ' => 'Ἢ', + 'ἣ' => 'Ἣ', + 'ἤ' => 'Ἤ', + 'ἥ' => 'Ἥ', + 'ἦ' => 'Ἦ', + 'ἧ' => 'Ἧ', + 'ἰ' => 'Ἰ', + 'ἱ' => 'Ἱ', + 'ἲ' => 'Ἲ', + 'ἳ' => 'Ἳ', + 'ἴ' => 'Ἴ', + 'ἵ' => 'Ἵ', + 'ἶ' => 'Ἶ', + 'ἷ' => 'Ἷ', + 'ὀ' => 'Ὀ', + 'ὁ' => 'Ὁ', + 'ὂ' => 'Ὂ', + 'ὃ' => 'Ὃ', + 'ὄ' => 'Ὄ', + 'ὅ' => 'Ὅ', + 'ὑ' => 'Ὑ', + 'ὓ' => 'Ὓ', + 'ὕ' => 'Ὕ', + 'ὗ' => 'Ὗ', + 'ὠ' => 'Ὠ', + 'ὡ' => 'Ὡ', + 'ὢ' => 'Ὢ', + 'ὣ' => 'Ὣ', + 'ὤ' => 'Ὤ', + 'ὥ' => 'Ὥ', + 'ὦ' => 'Ὦ', + 'ὧ' => 'Ὧ', + 'ὰ' => 'Ὰ', + 'ά' => 'Ά', + 'ὲ' => 'Ὲ', + 'έ' => 'Έ', + 'ὴ' => 'Ὴ', + 'ή' => 'Ή', + 'ὶ' => 'Ὶ', + 'ί' => 'Ί', + 'ὸ' => 'Ὸ', + 'ό' => 'Ό', + 'ὺ' => 'Ὺ', + 'ύ' => 'Ύ', + 'ὼ' => 'Ὼ', + 'ώ' => 'Ώ', + 'ᾀ' => 'ἈΙ', + 'ᾁ' => 'ἉΙ', + 'ᾂ' => 'ἊΙ', + 'ᾃ' => 'ἋΙ', + 'ᾄ' => 'ἌΙ', + 'ᾅ' => 'ἍΙ', + 'ᾆ' => 'ἎΙ', + 'ᾇ' => 'ἏΙ', + 'ᾐ' => 'ἨΙ', + 'ᾑ' => 'ἩΙ', + 'ᾒ' => 'ἪΙ', + 'ᾓ' => 'ἫΙ', + 'ᾔ' => 'ἬΙ', + 'ᾕ' => 'ἭΙ', + 'ᾖ' => 'ἮΙ', + 'ᾗ' => 'ἯΙ', + 'ᾠ' => 'ὨΙ', + 'ᾡ' => 'ὩΙ', + 'ᾢ' => 'ὪΙ', + 'ᾣ' => 'ὫΙ', + 'ᾤ' => 'ὬΙ', + 'ᾥ' => 'ὭΙ', + 'ᾦ' => 'ὮΙ', + 'ᾧ' => 'ὯΙ', + 'ᾰ' => 'Ᾰ', + 'ᾱ' => 'Ᾱ', + 'ᾳ' => 'ΑΙ', + 'ι' => 'Ι', + 'ῃ' => 'ΗΙ', + 'ῐ' => 'Ῐ', + 'ῑ' => 'Ῑ', + 'ῠ' => 'Ῠ', + 'ῡ' => 'Ῡ', + 'ῥ' => 'Ῥ', + 'ῳ' => 'ΩΙ', + 'ⅎ' => 'Ⅎ', + 'ⅰ' => 'Ⅰ', + 'ⅱ' => 'Ⅱ', + 'ⅲ' => 'Ⅲ', + 'ⅳ' => 'Ⅳ', + 'ⅴ' => 'Ⅴ', + 'ⅵ' => 'Ⅵ', + 'ⅶ' => 'Ⅶ', + 'ⅷ' => 'Ⅷ', + 'ⅸ' => 'Ⅸ', + 'ⅹ' => 'Ⅹ', + 'ⅺ' => 'Ⅺ', + 'ⅻ' => 'Ⅻ', + 'ⅼ' => 'Ⅼ', + 'ⅽ' => 'Ⅽ', + 'ⅾ' => 'Ⅾ', + 'ⅿ' => 'Ⅿ', + 'ↄ' => 'Ↄ', + 'ⓐ' => 'Ⓐ', + 'ⓑ' => 'Ⓑ', + 'ⓒ' => 'Ⓒ', + 'ⓓ' => 'Ⓓ', + 'ⓔ' => 'Ⓔ', + 'ⓕ' => 'Ⓕ', + 'ⓖ' => 'Ⓖ', + 'ⓗ' => 'Ⓗ', + 'ⓘ' => 'Ⓘ', + 'ⓙ' => 'Ⓙ', + 'ⓚ' => 'Ⓚ', + 'ⓛ' => 'Ⓛ', + 'ⓜ' => 'Ⓜ', + 'ⓝ' => 'Ⓝ', + 'ⓞ' => 'Ⓞ', + 'ⓟ' => 'Ⓟ', + 'ⓠ' => 'Ⓠ', + 'ⓡ' => 'Ⓡ', + 'ⓢ' => 'Ⓢ', + 'ⓣ' => 'Ⓣ', + 'ⓤ' => 'Ⓤ', + 'ⓥ' => 'Ⓥ', + 'ⓦ' => 'Ⓦ', + 'ⓧ' => 'Ⓧ', + 'ⓨ' => 'Ⓨ', + 'ⓩ' => 'Ⓩ', + 'ⰰ' => 'Ⰰ', + 'ⰱ' => 'Ⰱ', + 'ⰲ' => 'Ⰲ', + 'ⰳ' => 'Ⰳ', + 'ⰴ' => 'Ⰴ', + 'ⰵ' => 'Ⰵ', + 'ⰶ' => 'Ⰶ', + 'ⰷ' => 'Ⰷ', + 'ⰸ' => 'Ⰸ', + 'ⰹ' => 'Ⰹ', + 'ⰺ' => 'Ⰺ', + 'ⰻ' => 'Ⰻ', + 'ⰼ' => 'Ⰼ', + 'ⰽ' => 'Ⰽ', + 'ⰾ' => 'Ⰾ', + 'ⰿ' => 'Ⰿ', + 'ⱀ' => 'Ⱀ', + 'ⱁ' => 'Ⱁ', + 'ⱂ' => 'Ⱂ', + 'ⱃ' => 'Ⱃ', + 'ⱄ' => 'Ⱄ', + 'ⱅ' => 'Ⱅ', + 'ⱆ' => 'Ⱆ', + 'ⱇ' => 'Ⱇ', + 'ⱈ' => 'Ⱈ', + 'ⱉ' => 'Ⱉ', + 'ⱊ' => 'Ⱊ', + 'ⱋ' => 'Ⱋ', + 'ⱌ' => 'Ⱌ', + 'ⱍ' => 'Ⱍ', + 'ⱎ' => 'Ⱎ', + 'ⱏ' => 'Ⱏ', + 'ⱐ' => 'Ⱐ', + 'ⱑ' => 'Ⱑ', + 'ⱒ' => 'Ⱒ', + 'ⱓ' => 'Ⱓ', + 'ⱔ' => 'Ⱔ', + 'ⱕ' => 'Ⱕ', + 'ⱖ' => 'Ⱖ', + 'ⱗ' => 'Ⱗ', + 'ⱘ' => 'Ⱘ', + 'ⱙ' => 'Ⱙ', + 'ⱚ' => 'Ⱚ', + 'ⱛ' => 'Ⱛ', + 'ⱜ' => 'Ⱜ', + 'ⱝ' => 'Ⱝ', + 'ⱞ' => 'Ⱞ', + 'ⱡ' => 'Ⱡ', + 'ⱥ' => 'Ⱥ', + 'ⱦ' => 'Ⱦ', + 'ⱨ' => 'Ⱨ', + 'ⱪ' => 'Ⱪ', + 'ⱬ' => 'Ⱬ', + 'ⱳ' => 'Ⱳ', + 'ⱶ' => 'Ⱶ', + 'ⲁ' => 'Ⲁ', + 'ⲃ' => 'Ⲃ', + 'ⲅ' => 'Ⲅ', + 'ⲇ' => 'Ⲇ', + 'ⲉ' => 'Ⲉ', + 'ⲋ' => 'Ⲋ', + 'ⲍ' => 'Ⲍ', + 'ⲏ' => 'Ⲏ', + 'ⲑ' => 'Ⲑ', + 'ⲓ' => 'Ⲓ', + 'ⲕ' => 'Ⲕ', + 'ⲗ' => 'Ⲗ', + 'ⲙ' => 'Ⲙ', + 'ⲛ' => 'Ⲛ', + 'ⲝ' => 'Ⲝ', + 'ⲟ' => 'Ⲟ', + 'ⲡ' => 'Ⲡ', + 'ⲣ' => 'Ⲣ', + 'ⲥ' => 'Ⲥ', + 'ⲧ' => 'Ⲧ', + 'ⲩ' => 'Ⲩ', + 'ⲫ' => 'Ⲫ', + 'ⲭ' => 'Ⲭ', + 'ⲯ' => 'Ⲯ', + 'ⲱ' => 'Ⲱ', + 'ⲳ' => 'Ⲳ', + 'ⲵ' => 'Ⲵ', + 'ⲷ' => 'Ⲷ', + 'ⲹ' => 'Ⲹ', + 'ⲻ' => 'Ⲻ', + 'ⲽ' => 'Ⲽ', + 'ⲿ' => 'Ⲿ', + 'ⳁ' => 'Ⳁ', + 'ⳃ' => 'Ⳃ', + 'ⳅ' => 'Ⳅ', + 'ⳇ' => 'Ⳇ', + 'ⳉ' => 'Ⳉ', + 'ⳋ' => 'Ⳋ', + 'ⳍ' => 'Ⳍ', + 'ⳏ' => 'Ⳏ', + 'ⳑ' => 'Ⳑ', + 'ⳓ' => 'Ⳓ', + 'ⳕ' => 'Ⳕ', + 'ⳗ' => 'Ⳗ', + 'ⳙ' => 'Ⳙ', + 'ⳛ' => 'Ⳛ', + 'ⳝ' => 'Ⳝ', + 'ⳟ' => 'Ⳟ', + 'ⳡ' => 'Ⳡ', + 'ⳣ' => 'Ⳣ', + 'ⳬ' => 'Ⳬ', + 'ⳮ' => 'Ⳮ', + 'ⳳ' => 'Ⳳ', + 'ⴀ' => 'Ⴀ', + 'ⴁ' => 'Ⴁ', + 'ⴂ' => 'Ⴂ', + 'ⴃ' => 'Ⴃ', + 'ⴄ' => 'Ⴄ', + 'ⴅ' => 'Ⴅ', + 'ⴆ' => 'Ⴆ', + 'ⴇ' => 'Ⴇ', + 'ⴈ' => 'Ⴈ', + 'ⴉ' => 'Ⴉ', + 'ⴊ' => 'Ⴊ', + 'ⴋ' => 'Ⴋ', + 'ⴌ' => 'Ⴌ', + 'ⴍ' => 'Ⴍ', + 'ⴎ' => 'Ⴎ', + 'ⴏ' => 'Ⴏ', + 'ⴐ' => 'Ⴐ', + 'ⴑ' => 'Ⴑ', + 'ⴒ' => 'Ⴒ', + 'ⴓ' => 'Ⴓ', + 'ⴔ' => 'Ⴔ', + 'ⴕ' => 'Ⴕ', + 'ⴖ' => 'Ⴖ', + 'ⴗ' => 'Ⴗ', + 'ⴘ' => 'Ⴘ', + 'ⴙ' => 'Ⴙ', + 'ⴚ' => 'Ⴚ', + 'ⴛ' => 'Ⴛ', + 'ⴜ' => 'Ⴜ', + 'ⴝ' => 'Ⴝ', + 'ⴞ' => 'Ⴞ', + 'ⴟ' => 'Ⴟ', + 'ⴠ' => 'Ⴠ', + 'ⴡ' => 'Ⴡ', + 'ⴢ' => 'Ⴢ', + 'ⴣ' => 'Ⴣ', + 'ⴤ' => 'Ⴤ', + 'ⴥ' => 'Ⴥ', + 'ⴧ' => 'Ⴧ', + 'ⴭ' => 'Ⴭ', + 'ꙁ' => 'Ꙁ', + 'ꙃ' => 'Ꙃ', + 'ꙅ' => 'Ꙅ', + 'ꙇ' => 'Ꙇ', + 'ꙉ' => 'Ꙉ', + 'ꙋ' => 'Ꙋ', + 'ꙍ' => 'Ꙍ', + 'ꙏ' => 'Ꙏ', + 'ꙑ' => 'Ꙑ', + 'ꙓ' => 'Ꙓ', + 'ꙕ' => 'Ꙕ', + 'ꙗ' => 'Ꙗ', + 'ꙙ' => 'Ꙙ', + 'ꙛ' => 'Ꙛ', + 'ꙝ' => 'Ꙝ', + 'ꙟ' => 'Ꙟ', + 'ꙡ' => 'Ꙡ', + 'ꙣ' => 'Ꙣ', + 'ꙥ' => 'Ꙥ', + 'ꙧ' => 'Ꙧ', + 'ꙩ' => 'Ꙩ', + 'ꙫ' => 'Ꙫ', + 'ꙭ' => 'Ꙭ', + 'ꚁ' => 'Ꚁ', + 'ꚃ' => 'Ꚃ', + 'ꚅ' => 'Ꚅ', + 'ꚇ' => 'Ꚇ', + 'ꚉ' => 'Ꚉ', + 'ꚋ' => 'Ꚋ', + 'ꚍ' => 'Ꚍ', + 'ꚏ' => 'Ꚏ', + 'ꚑ' => 'Ꚑ', + 'ꚓ' => 'Ꚓ', + 'ꚕ' => 'Ꚕ', + 'ꚗ' => 'Ꚗ', + 'ꚙ' => 'Ꚙ', + 'ꚛ' => 'Ꚛ', + 'ꜣ' => 'Ꜣ', + 'ꜥ' => 'Ꜥ', + 'ꜧ' => 'Ꜧ', + 'ꜩ' => 'Ꜩ', + 'ꜫ' => 'Ꜫ', + 'ꜭ' => 'Ꜭ', + 'ꜯ' => 'Ꜯ', + 'ꜳ' => 'Ꜳ', + 'ꜵ' => 'Ꜵ', + 'ꜷ' => 'Ꜷ', + 'ꜹ' => 'Ꜹ', + 'ꜻ' => 'Ꜻ', + 'ꜽ' => 'Ꜽ', + 'ꜿ' => 'Ꜿ', + 'ꝁ' => 'Ꝁ', + 'ꝃ' => 'Ꝃ', + 'ꝅ' => 'Ꝅ', + 'ꝇ' => 'Ꝇ', + 'ꝉ' => 'Ꝉ', + 'ꝋ' => 'Ꝋ', + 'ꝍ' => 'Ꝍ', + 'ꝏ' => 'Ꝏ', + 'ꝑ' => 'Ꝑ', + 'ꝓ' => 'Ꝓ', + 'ꝕ' => 'Ꝕ', + 'ꝗ' => 'Ꝗ', + 'ꝙ' => 'Ꝙ', + 'ꝛ' => 'Ꝛ', + 'ꝝ' => 'Ꝝ', + 'ꝟ' => 'Ꝟ', + 'ꝡ' => 'Ꝡ', + 'ꝣ' => 'Ꝣ', + 'ꝥ' => 'Ꝥ', + 'ꝧ' => 'Ꝧ', + 'ꝩ' => 'Ꝩ', + 'ꝫ' => 'Ꝫ', + 'ꝭ' => 'Ꝭ', + 'ꝯ' => 'Ꝯ', + 'ꝺ' => 'Ꝺ', + 'ꝼ' => 'Ꝼ', + 'ꝿ' => 'Ꝿ', + 'ꞁ' => 'Ꞁ', + 'ꞃ' => 'Ꞃ', + 'ꞅ' => 'Ꞅ', + 'ꞇ' => 'Ꞇ', + 'ꞌ' => 'Ꞌ', + 'ꞑ' => 'Ꞑ', + 'ꞓ' => 'Ꞓ', + 'ꞔ' => 'Ꞔ', + 'ꞗ' => 'Ꞗ', + 'ꞙ' => 'Ꞙ', + 'ꞛ' => 'Ꞛ', + 'ꞝ' => 'Ꞝ', + 'ꞟ' => 'Ꞟ', + 'ꞡ' => 'Ꞡ', + 'ꞣ' => 'Ꞣ', + 'ꞥ' => 'Ꞥ', + 'ꞧ' => 'Ꞧ', + 'ꞩ' => 'Ꞩ', + 'ꞵ' => 'Ꞵ', + 'ꞷ' => 'Ꞷ', + 'ꞹ' => 'Ꞹ', + 'ꞻ' => 'Ꞻ', + 'ꞽ' => 'Ꞽ', + 'ꞿ' => 'Ꞿ', + 'ꟃ' => 'Ꟃ', + 'ꟈ' => 'Ꟈ', + 'ꟊ' => 'Ꟊ', + 'ꟶ' => 'Ꟶ', + 'ꭓ' => 'Ꭓ', + 'ꭰ' => 'Ꭰ', + 'ꭱ' => 'Ꭱ', + 'ꭲ' => 'Ꭲ', + 'ꭳ' => 'Ꭳ', + 'ꭴ' => 'Ꭴ', + 'ꭵ' => 'Ꭵ', + 'ꭶ' => 'Ꭶ', + 'ꭷ' => 'Ꭷ', + 'ꭸ' => 'Ꭸ', + 'ꭹ' => 'Ꭹ', + 'ꭺ' => 'Ꭺ', + 'ꭻ' => 'Ꭻ', + 'ꭼ' => 'Ꭼ', + 'ꭽ' => 'Ꭽ', + 'ꭾ' => 'Ꭾ', + 'ꭿ' => 'Ꭿ', + 'ꮀ' => 'Ꮀ', + 'ꮁ' => 'Ꮁ', + 'ꮂ' => 'Ꮂ', + 'ꮃ' => 'Ꮃ', + 'ꮄ' => 'Ꮄ', + 'ꮅ' => 'Ꮅ', + 'ꮆ' => 'Ꮆ', + 'ꮇ' => 'Ꮇ', + 'ꮈ' => 'Ꮈ', + 'ꮉ' => 'Ꮉ', + 'ꮊ' => 'Ꮊ', + 'ꮋ' => 'Ꮋ', + 'ꮌ' => 'Ꮌ', + 'ꮍ' => 'Ꮍ', + 'ꮎ' => 'Ꮎ', + 'ꮏ' => 'Ꮏ', + 'ꮐ' => 'Ꮐ', + 'ꮑ' => 'Ꮑ', + 'ꮒ' => 'Ꮒ', + 'ꮓ' => 'Ꮓ', + 'ꮔ' => 'Ꮔ', + 'ꮕ' => 'Ꮕ', + 'ꮖ' => 'Ꮖ', + 'ꮗ' => 'Ꮗ', + 'ꮘ' => 'Ꮘ', + 'ꮙ' => 'Ꮙ', + 'ꮚ' => 'Ꮚ', + 'ꮛ' => 'Ꮛ', + 'ꮜ' => 'Ꮜ', + 'ꮝ' => 'Ꮝ', + 'ꮞ' => 'Ꮞ', + 'ꮟ' => 'Ꮟ', + 'ꮠ' => 'Ꮠ', + 'ꮡ' => 'Ꮡ', + 'ꮢ' => 'Ꮢ', + 'ꮣ' => 'Ꮣ', + 'ꮤ' => 'Ꮤ', + 'ꮥ' => 'Ꮥ', + 'ꮦ' => 'Ꮦ', + 'ꮧ' => 'Ꮧ', + 'ꮨ' => 'Ꮨ', + 'ꮩ' => 'Ꮩ', + 'ꮪ' => 'Ꮪ', + 'ꮫ' => 'Ꮫ', + 'ꮬ' => 'Ꮬ', + 'ꮭ' => 'Ꮭ', + 'ꮮ' => 'Ꮮ', + 'ꮯ' => 'Ꮯ', + 'ꮰ' => 'Ꮰ', + 'ꮱ' => 'Ꮱ', + 'ꮲ' => 'Ꮲ', + 'ꮳ' => 'Ꮳ', + 'ꮴ' => 'Ꮴ', + 'ꮵ' => 'Ꮵ', + 'ꮶ' => 'Ꮶ', + 'ꮷ' => 'Ꮷ', + 'ꮸ' => 'Ꮸ', + 'ꮹ' => 'Ꮹ', + 'ꮺ' => 'Ꮺ', + 'ꮻ' => 'Ꮻ', + 'ꮼ' => 'Ꮼ', + 'ꮽ' => 'Ꮽ', + 'ꮾ' => 'Ꮾ', + 'ꮿ' => 'Ꮿ', + 'a' => 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + '𐐨' => '𐐀', + '𐐩' => '𐐁', + '𐐪' => '𐐂', + '𐐫' => '𐐃', + '𐐬' => '𐐄', + '𐐭' => '𐐅', + '𐐮' => '𐐆', + '𐐯' => '𐐇', + '𐐰' => '𐐈', + '𐐱' => '𐐉', + '𐐲' => '𐐊', + '𐐳' => '𐐋', + '𐐴' => '𐐌', + '𐐵' => '𐐍', + '𐐶' => '𐐎', + '𐐷' => '𐐏', + '𐐸' => '𐐐', + '𐐹' => '𐐑', + '𐐺' => '𐐒', + '𐐻' => '𐐓', + '𐐼' => '𐐔', + '𐐽' => '𐐕', + '𐐾' => '𐐖', + '𐐿' => '𐐗', + '𐑀' => '𐐘', + '𐑁' => '𐐙', + '𐑂' => '𐐚', + '𐑃' => '𐐛', + '𐑄' => '𐐜', + '𐑅' => '𐐝', + '𐑆' => '𐐞', + '𐑇' => '𐐟', + '𐑈' => '𐐠', + '𐑉' => '𐐡', + '𐑊' => '𐐢', + '𐑋' => '𐐣', + '𐑌' => '𐐤', + '𐑍' => '𐐥', + '𐑎' => '𐐦', + '𐑏' => '𐐧', + '𐓘' => '𐒰', + '𐓙' => '𐒱', + '𐓚' => '𐒲', + '𐓛' => '𐒳', + '𐓜' => '𐒴', + '𐓝' => '𐒵', + '𐓞' => '𐒶', + '𐓟' => '𐒷', + '𐓠' => '𐒸', + '𐓡' => '𐒹', + '𐓢' => '𐒺', + '𐓣' => '𐒻', + '𐓤' => '𐒼', + '𐓥' => '𐒽', + '𐓦' => '𐒾', + '𐓧' => '𐒿', + '𐓨' => '𐓀', + '𐓩' => '𐓁', + '𐓪' => '𐓂', + '𐓫' => '𐓃', + '𐓬' => '𐓄', + '𐓭' => '𐓅', + '𐓮' => '𐓆', + '𐓯' => '𐓇', + '𐓰' => '𐓈', + '𐓱' => '𐓉', + '𐓲' => '𐓊', + '𐓳' => '𐓋', + '𐓴' => '𐓌', + '𐓵' => '𐓍', + '𐓶' => '𐓎', + '𐓷' => '𐓏', + '𐓸' => '𐓐', + '𐓹' => '𐓑', + '𐓺' => '𐓒', + '𐓻' => '𐓓', + '𐳀' => '𐲀', + '𐳁' => '𐲁', + '𐳂' => '𐲂', + '𐳃' => '𐲃', + '𐳄' => '𐲄', + '𐳅' => '𐲅', + '𐳆' => '𐲆', + '𐳇' => '𐲇', + '𐳈' => '𐲈', + '𐳉' => '𐲉', + '𐳊' => '𐲊', + '𐳋' => '𐲋', + '𐳌' => '𐲌', + '𐳍' => '𐲍', + '𐳎' => '𐲎', + '𐳏' => '𐲏', + '𐳐' => '𐲐', + '𐳑' => '𐲑', + '𐳒' => '𐲒', + '𐳓' => '𐲓', + '𐳔' => '𐲔', + '𐳕' => '𐲕', + '𐳖' => '𐲖', + '𐳗' => '𐲗', + '𐳘' => '𐲘', + '𐳙' => '𐲙', + '𐳚' => '𐲚', + '𐳛' => '𐲛', + '𐳜' => '𐲜', + '𐳝' => '𐲝', + '𐳞' => '𐲞', + '𐳟' => '𐲟', + '𐳠' => '𐲠', + '𐳡' => '𐲡', + '𐳢' => '𐲢', + '𐳣' => '𐲣', + '𐳤' => '𐲤', + '𐳥' => '𐲥', + '𐳦' => '𐲦', + '𐳧' => '𐲧', + '𐳨' => '𐲨', + '𐳩' => '𐲩', + '𐳪' => '𐲪', + '𐳫' => '𐲫', + '𐳬' => '𐲬', + '𐳭' => '𐲭', + '𐳮' => '𐲮', + '𐳯' => '𐲯', + '𐳰' => '𐲰', + '𐳱' => '𐲱', + '𐳲' => '𐲲', + '𑣀' => '𑢠', + '𑣁' => '𑢡', + '𑣂' => '𑢢', + '𑣃' => '𑢣', + '𑣄' => '𑢤', + '𑣅' => '𑢥', + '𑣆' => '𑢦', + '𑣇' => '𑢧', + '𑣈' => '𑢨', + '𑣉' => '𑢩', + '𑣊' => '𑢪', + '𑣋' => '𑢫', + '𑣌' => '𑢬', + '𑣍' => '𑢭', + '𑣎' => '𑢮', + '𑣏' => '𑢯', + '𑣐' => '𑢰', + '𑣑' => '𑢱', + '𑣒' => '𑢲', + '𑣓' => '𑢳', + '𑣔' => '𑢴', + '𑣕' => '𑢵', + '𑣖' => '𑢶', + '𑣗' => '𑢷', + '𑣘' => '𑢸', + '𑣙' => '𑢹', + '𑣚' => '𑢺', + '𑣛' => '𑢻', + '𑣜' => '𑢼', + '𑣝' => '𑢽', + '𑣞' => '𑢾', + '𑣟' => '𑢿', + '𖹠' => '𖹀', + '𖹡' => '𖹁', + '𖹢' => '𖹂', + '𖹣' => '𖹃', + '𖹤' => '𖹄', + '𖹥' => '𖹅', + '𖹦' => '𖹆', + '𖹧' => '𖹇', + '𖹨' => '𖹈', + '𖹩' => '𖹉', + '𖹪' => '𖹊', + '𖹫' => '𖹋', + '𖹬' => '𖹌', + '𖹭' => '𖹍', + '𖹮' => '𖹎', + '𖹯' => '𖹏', + '𖹰' => '𖹐', + '𖹱' => '𖹑', + '𖹲' => '𖹒', + '𖹳' => '𖹓', + '𖹴' => '𖹔', + '𖹵' => '𖹕', + '𖹶' => '𖹖', + '𖹷' => '𖹗', + '𖹸' => '𖹘', + '𖹹' => '𖹙', + '𖹺' => '𖹚', + '𖹻' => '𖹛', + '𖹼' => '𖹜', + '𖹽' => '𖹝', + '𖹾' => '𖹞', + '𖹿' => '𖹟', + '𞤢' => '𞤀', + '𞤣' => '𞤁', + '𞤤' => '𞤂', + '𞤥' => '𞤃', + '𞤦' => '𞤄', + '𞤧' => '𞤅', + '𞤨' => '𞤆', + '𞤩' => '𞤇', + '𞤪' => '𞤈', + '𞤫' => '𞤉', + '𞤬' => '𞤊', + '𞤭' => '𞤋', + '𞤮' => '𞤌', + '𞤯' => '𞤍', + '𞤰' => '𞤎', + '𞤱' => '𞤏', + '𞤲' => '𞤐', + '𞤳' => '𞤑', + '𞤴' => '𞤒', + '𞤵' => '𞤓', + '𞤶' => '𞤔', + '𞤷' => '𞤕', + '𞤸' => '𞤖', + '𞤹' => '𞤗', + '𞤺' => '𞤘', + '𞤻' => '𞤙', + '𞤼' => '𞤚', + '𞤽' => '𞤛', + '𞤾' => '𞤜', + '𞤿' => '𞤝', + '𞥀' => '𞤞', + '𞥁' => '𞤟', + '𞥂' => '𞤠', + '𞥃' => '𞤡', + 'ß' => 'SS', + 'ff' => 'FF', + 'fi' => 'FI', + 'fl' => 'FL', + 'ffi' => 'FFI', + 'ffl' => 'FFL', + 'ſt' => 'ST', + 'st' => 'ST', + 'և' => 'ԵՒ', + 'ﬓ' => 'ՄՆ', + 'ﬔ' => 'ՄԵ', + 'ﬕ' => 'ՄԻ', + 'ﬖ' => 'ՎՆ', + 'ﬗ' => 'ՄԽ', + 'ʼn' => 'ʼN', + 'ΐ' => 'Ϊ́', + 'ΰ' => 'Ϋ́', + 'ǰ' => 'J̌', + 'ẖ' => 'H̱', + 'ẗ' => 'T̈', + 'ẘ' => 'W̊', + 'ẙ' => 'Y̊', + 'ẚ' => 'Aʾ', + 'ὐ' => 'Υ̓', + 'ὒ' => 'Υ̓̀', + 'ὔ' => 'Υ̓́', + 'ὖ' => 'Υ̓͂', + 'ᾶ' => 'Α͂', + 'ῆ' => 'Η͂', + 'ῒ' => 'Ϊ̀', + 'ΐ' => 'Ϊ́', + 'ῖ' => 'Ι͂', + 'ῗ' => 'Ϊ͂', + 'ῢ' => 'Ϋ̀', + 'ΰ' => 'Ϋ́', + 'ῤ' => 'Ρ̓', + 'ῦ' => 'Υ͂', + 'ῧ' => 'Ϋ͂', + 'ῶ' => 'Ω͂', + 'ᾈ' => 'ἈΙ', + 'ᾉ' => 'ἉΙ', + 'ᾊ' => 'ἊΙ', + 'ᾋ' => 'ἋΙ', + 'ᾌ' => 'ἌΙ', + 'ᾍ' => 'ἍΙ', + 'ᾎ' => 'ἎΙ', + 'ᾏ' => 'ἏΙ', + 'ᾘ' => 'ἨΙ', + 'ᾙ' => 'ἩΙ', + 'ᾚ' => 'ἪΙ', + 'ᾛ' => 'ἫΙ', + 'ᾜ' => 'ἬΙ', + 'ᾝ' => 'ἭΙ', + 'ᾞ' => 'ἮΙ', + 'ᾟ' => 'ἯΙ', + 'ᾨ' => 'ὨΙ', + 'ᾩ' => 'ὩΙ', + 'ᾪ' => 'ὪΙ', + 'ᾫ' => 'ὫΙ', + 'ᾬ' => 'ὬΙ', + 'ᾭ' => 'ὭΙ', + 'ᾮ' => 'ὮΙ', + 'ᾯ' => 'ὯΙ', + 'ᾼ' => 'ΑΙ', + 'ῌ' => 'ΗΙ', + 'ῼ' => 'ΩΙ', + 'ᾲ' => 'ᾺΙ', + 'ᾴ' => 'ΆΙ', + 'ῂ' => 'ῊΙ', + 'ῄ' => 'ΉΙ', + 'ῲ' => 'ῺΙ', + 'ῴ' => 'ΏΙ', + 'ᾷ' => 'Α͂Ι', + 'ῇ' => 'Η͂Ι', + 'ῷ' => 'Ω͂Ι', +); diff --git a/system/libs/polyfill-mbstring/bootstrap.php b/system/libs/polyfill-mbstring/bootstrap.php new file mode 100644 index 0000000000..1fedd1f7c8 --- /dev/null +++ b/system/libs/polyfill-mbstring/bootstrap.php @@ -0,0 +1,147 @@ + + * + * 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); +} diff --git a/system/libs/polyfill-mbstring/bootstrap80.php b/system/libs/polyfill-mbstring/bootstrap80.php new file mode 100644 index 0000000000..82f5ac4d0f --- /dev/null +++ b/system/libs/polyfill-mbstring/bootstrap80.php @@ -0,0 +1,143 @@ + + * + * 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); +} diff --git a/system/libs/polyfill-mbstring/composer.json b/system/libs/polyfill-mbstring/composer.json new file mode 100644 index 0000000000..44895536ba --- /dev/null +++ b/system/libs/polyfill-mbstring/composer.json @@ -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" + } + } +} diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index 3aed82112b..4c95997ded 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -21,7 +21,6 @@ * @property string $password Password. * @property string $eMail Email address. * @property int $premiumEnd Timestamp of PACC end. - * @property bool $blocked Blocked flag state. * @property bool $deleted Deleted flag state. * @property bool $warned Warned flag state. * @property bool $banned Ban state. @@ -39,7 +38,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @var array * @version 0.1.5 */ - private $data = array('email' => '', 'blocked' => false, 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0); + private $data = array('email' => '', 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0); public static $cache = array(); @@ -214,7 +213,7 @@ public function load($id, $fresh = false, $searchOnlyById = false) } // SELECT query on database - $this->data = $this->db->query('SELECT `id`, ' . $nameOrNumber . '`password`, `email`, `coins`, `blocked`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `' . $numberColumn . '` = ' . (int) $id)->fetch(); + $this->data = $this->db->query('SELECT `id`, ' . $nameOrNumber . '`password`, `email`, `coins`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `' . $numberColumn . '` = ' . (int) $id)->fetch(); self::$cache[$id] = $this->data; } @@ -308,7 +307,7 @@ public function save() } // UPDATE query on database - $this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `blocked` = ' . (int) $this->data['blocked'] . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']); + $this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']); } /** @@ -331,7 +330,7 @@ public function getId() return $this->data['id']; } - + public function getNumber() { if (isset($this->data['number'])) { @@ -360,7 +359,7 @@ public function getLocation() return $this->data['location']; } - + public function getCoins() { if( !isset($this->data['coins']) ) @@ -623,52 +622,6 @@ public function setEMail($email) $this->data['email'] = (string) $email; } -/** - * Checks if account is blocked. - * - *

    - * Note: Since 0.0.3 version this method throws {@link E_OTS_NotLoaded E_OTS_NotLoaded} exception instead of triggering E_USER_WARNING. - *

    - * - * @version 0.0.3 - * @return bool Blocked state. - * @throws E_OTS_NotLoaded If account is not loaded. - */ - public function isBlocked() - { - if( !isset($this->data['blocked']) ) - { - throw new E_OTS_NotLoaded(); - } - - return $this->data['blocked']; - } - -/** - * Unblocks account. - * - *

    - * This method only updates object state. To save changes in database you need to use {@link OTS_Account::save() save() method} to flush changed to database. - *

    - */ - public function unblock() - { - $this->data['blocked'] = false; - } - -/** - * Blocks account. - * - *

    - * This method only updates object state. To save changes in databaseed to use {@link OTS_Account::save() save() method} to flush changed to database. - *

    - */ - public function block() - { - $this->data['blocked'] = true; - } - - /** * Reads custom field. @@ -778,7 +731,7 @@ public function getPlayers() * @return OTS_Players_List List of players from current account. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getPlayersList() + public function getPlayersList($withDeleted = true) { if( !isset($this->data['id']) ) { @@ -789,6 +742,15 @@ public function getPlayersList() $filter = new OTS_SQLFilter(); $filter->compareField('account_id', (int) $this->data['id']); + if (!$withDeleted) { + global $db; + if ($db->hasColumn('players', 'deletion')) { + $filter->compareField('deletion', 0); + } else { + $filter->compareField('deleted', 0); + } + } + // creates list object $list = new OTS_Players_List(); $list->setFilter($filter); @@ -1055,6 +1017,7 @@ public function getActionsLog($limit1, $limit2) * @throws PDOException On PDO operation error. * @return Iterator List of players. */ + #[\ReturnTypeWillChange] public function getIterator() { return $this->getPlayersList(); @@ -1069,7 +1032,7 @@ public function getIterator() * @throws PDOException On PDO operation error. * @return int Count of players. */ - public function count() + public function count(): int { return $this->getPlayersList()->count(); } @@ -1110,9 +1073,6 @@ public function __get($name) case 'playersList': return $this->getPlayersList(); - case 'blocked': - return $this->isBlocked(); - case 'deleted': return $this->isDeleted(); @@ -1158,17 +1118,6 @@ public function __set($name, $value) $this->setPremiumEnd($value); break; - case 'blocked': - if($value) - { - $this->block(); - } - else - { - $this->unblock(); - } - break; - case 'deleted': if($value) { diff --git a/system/libs/pot/OTS_Base_List.php b/system/libs/pot/OTS_Base_List.php index c3df55df3f..a1f9e9b346 100644 --- a/system/libs/pot/OTS_Base_List.php +++ b/system/libs/pot/OTS_Base_List.php @@ -190,6 +190,7 @@ public function setOffset($offset = false) * @version 0.1.3 * @return OTS_Base_DAO Current row. */ + #[\ReturnTypeWillChange] public function current() { $id = current($this->rows); @@ -203,7 +204,7 @@ public function current() * * @throws PDOException On PDO operation error. */ - public function rewind() + public function rewind(): void { $this->rows = $this->db->query( $this->getSQL() )->fetchAll(); } @@ -211,7 +212,7 @@ public function rewind() /** * Moves to next row. */ - public function next() + public function next(): void { next($this->rows); } @@ -221,6 +222,7 @@ public function next() * * @return mixed Array key. */ + #[\ReturnTypeWillChange] public function key() { return key($this->rows); @@ -231,7 +233,7 @@ public function key() * * @return bool Does next row exist. */ - public function valid() + public function valid(): bool { return key($this->rows) !== null; } @@ -243,7 +245,7 @@ public function valid() * @return int Number of rows. * @throws PDOException On PDO operation error. */ - public function count() + public function count(): int { return $this->db->query( $this->getSQL(true) )->fetchColumn(); } diff --git a/system/libs/pot/OTS_Container.php b/system/libs/pot/OTS_Container.php index 71340d7ca0..0f4c6bee60 100644 --- a/system/libs/pot/OTS_Container.php +++ b/system/libs/pot/OTS_Container.php @@ -15,11 +15,11 @@ /** * Container item representation. - * + * *

    * This class represents items that can contain other items. It's {@link OTS_Container::count() count() method} has been overwritten so it now doesn't return count of current item (if it would even be possible for containers) but amount of items within (not recursively). *

    - * + * * @package POT * @version 0.1.3 */ @@ -27,14 +27,14 @@ class OTS_Container extends OTS_Item implements IteratorAggregate { /** * Contained items. - * + * * @var array */ private $items = array(); /** * Adds item to container. - * + * * @param OTS_Item $item Item. */ public function addItem(OTS_Item $item) @@ -44,11 +44,11 @@ public function addItem(OTS_Item $item) /** * Removes given item from current container. - * + * *

    * Passed item must be exacly instance of item which is stored in container, not it's copy. This method bases on PHP references. *

    - * + * * @param OTS_Item $item Item. * @tutorial POT/Players.pkg#deleting */ @@ -66,16 +66,16 @@ public function removeItem(OTS_Item $item) /** * Number of items inside container. - * + * *

    * OTS_Container implementation of Countable interface differs from {@link OTS_Item OTS_Item} implemention. {@link OTS_Item::count() OTS_Item::count()} returns count of given item, OTS_Container::count() returns number of items inside container. If somehow it would be possible to make container items with more then 1 in one place, you can use {@link OTS_Item::getCount() OTS_Item::getCount()} and {@link OTS_Item::setCount() OTS_Item::setCount()} in code where you are not sure if working with regular item, or container. *

    - * + * * @return int Number of items. */ - public function count() + public function count(): int { - return count($items); + return count($this->items); } /** @@ -123,7 +123,7 @@ public function rewind() /** * Returns iterator handle for loops. - * + * * @version 0.1.0 * @since 0.1.0 * @return ArrayIterator Items iterator. @@ -135,7 +135,7 @@ public function getIterator() /** * Clones all contained items. - * + * * @version 0.1.3 * @since 0.1.3 */ diff --git a/system/libs/pot/OTS_DB_MySQL.php b/system/libs/pot/OTS_DB_MySQL.php index 07c55a6f99..a874439a16 100644 --- a/system/libs/pot/OTS_DB_MySQL.php +++ b/system/libs/pot/OTS_DB_MySQL.php @@ -215,6 +215,24 @@ public function hasColumn($table, $column) { return $this->hasColumnInternal($table, $column); } + /** + * Check if table exists and after check all columns passed of table + * + * @param $table + * @param array $columns + * @return bool + */ + public function hasTableAndColumns($table, array $columns = []) + { + if (!$this->hasTable($table)) return false; + foreach ($columns as $column) { + if (!$this->hasColumn($table, $column)) { + return false; + } + } + return true; + } + private function hasColumnInternal($table, $column) { return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE '" . $column . "'")->fetchAll()) > 0); } diff --git a/system/libs/pot/OTS_DB_PDOQuery_PHP71.php b/system/libs/pot/OTS_DB_PDOQuery_PHP71.php index 3bb91a4690..b6406b9af5 100644 --- a/system/libs/pot/OTS_DB_PDOQuery_PHP71.php +++ b/system/libs/pot/OTS_DB_PDOQuery_PHP71.php @@ -5,7 +5,7 @@ trait OTS_DB_PDOQuery /** * @return PDOStatement */ - public function query(?string $query = null, ?int $fetchMode = null, mixed ...$fetchModeArgs) + public function query(?string $query = null, ?int $fetchMode = null, mixed ...$fetchModeArgs): PDOStatement { return $this->doQuery($query, $fetchMode, ...$fetchModeArgs); } diff --git a/system/libs/pot/OTS_Group.php b/system/libs/pot/OTS_Group.php index 819d8b50aa..765db5a4fe 100644 --- a/system/libs/pot/OTS_Group.php +++ b/system/libs/pot/OTS_Group.php @@ -538,6 +538,7 @@ public function delete() * @throws PDOException On PDO operation error. * @return Iterator List of players. */ + #[\ReturnTypeWillChange] public function getIterator() { return $this->getPlayersList(); @@ -552,7 +553,7 @@ public function getIterator() * @throws PDOException On PDO operation error. * @return int Count of players. */ - public function count() + public function count(): int { return $this->getPlayersList()->count(); } diff --git a/system/libs/pot/OTS_Groups_List.php b/system/libs/pot/OTS_Groups_List.php index 083615deb2..4813ab615c 100644 --- a/system/libs/pot/OTS_Groups_List.php +++ b/system/libs/pot/OTS_Groups_List.php @@ -41,7 +41,7 @@ public function __construct($file = '') $info['access'] = $group['name']; $this->groups[$group['id']] = new OTS_Group($info); } - + return; } @@ -50,7 +50,7 @@ public function __construct($file = '') global $config; $file = $config['data_path'] . 'XML/groups.xml'; } - + if(!@file_exists($file)) { error('Error: Cannot load groups.xml. More info in system/logs/error.log file.'); log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). It doesnt exist.'); @@ -99,7 +99,7 @@ public function __construct($file = '') log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). Error: ' . print_r(error_get_last(), true)); return; } - + // loads groups foreach($groups->getElementsByTagName('group') as $group) { @@ -157,7 +157,7 @@ public function getHighestId() if($id > $group_id) $group_id = $id; } - + return $group_id; } @@ -196,6 +196,7 @@ public function __toString() * @since 0.1.5 * @return AppendIterator Iterator for all groups. */ + #[\ReturnTypeWillChange] public function getIterator() { $iterator = new AppendIterator(); @@ -210,7 +211,7 @@ public function getIterator() * @since 0.1.5 * @return int Amount of all groups. */ - public function count() + public function count(): int { return count($this->groups); } diff --git a/system/libs/pot/OTS_Guild.php b/system/libs/pot/OTS_Guild.php index 27e3e10285..d4e01b6e84 100644 --- a/system/libs/pot/OTS_Guild.php +++ b/system/libs/pot/OTS_Guild.php @@ -709,6 +709,7 @@ public function delete() * @throws PDOException On PDO operation error. * @return Iterator List of ranks. */ + #[\ReturnTypeWillChange] public function getIterator() { return $this->getGuildRanksList(); @@ -723,7 +724,7 @@ public function getIterator() * @throws PDOException On PDO operation error. * @return int Count of ranks. */ - public function count() + public function count(): int { return $this->getGuildRanksList()->count(); } diff --git a/system/libs/pot/OTS_GuildRank.php b/system/libs/pot/OTS_GuildRank.php index 24e1478c4a..3422cbe7f8 100644 --- a/system/libs/pot/OTS_GuildRank.php +++ b/system/libs/pot/OTS_GuildRank.php @@ -396,6 +396,7 @@ public function delete() * @throws PDOException On PDO operation error. * @return Iterator List of players. */ + #[\ReturnTypeWillChange] public function getIterator() { return $this->getPlayersList(); @@ -410,7 +411,7 @@ public function getIterator() * @throws PDOException On PDO operation error. * @return int Count of players. */ - public function count() + public function count(): int { return $this->getPlayersList()->count(); } diff --git a/system/libs/pot/OTS_HousesList.php b/system/libs/pot/OTS_HousesList.php index eda74f45ae..722e049f1f 100644 --- a/system/libs/pot/OTS_HousesList.php +++ b/system/libs/pot/OTS_HousesList.php @@ -15,7 +15,7 @@ /** * Wrapper for houses list. - * + * * @package POT * @version 0.1.3 * @tutorial POT/data_directory.pkg#towns.houses @@ -24,14 +24,14 @@ class OTS_HousesList implements IteratorAggregate, Countable, ArrayAccess { /** * List of houses elements. - * + * * @var array */ private $houses = array(); /** * Loads houses information. - * + * * @version 0.1.3 * @param string $path Houses file. * @throws DOMException On DOM operation error. @@ -49,11 +49,11 @@ public function __construct($path) /** * Magic PHP5 method. - * + * *

    * Allows object importing from {@link http://www.php.net/manual/en/function.var-export.php var_export()}. *

    - * + * * @param array $properties List of object properties. * @throws DOMException On DOM operation error. */ @@ -72,7 +72,7 @@ public static function __set_state($properties) /** * Checks if given house exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Name. @@ -94,7 +94,7 @@ public function hasHouse($name) /** * Returns house information. - * + * * @version 0.1.3 * @param int $id House ID. * @return OTS_House House information wrapper. @@ -112,7 +112,7 @@ public function getHouse($id) /** * Checks if given house ID exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param int $id ID. @@ -125,7 +125,7 @@ public function hasHouseId($id) /** * Returns ID of house with given name. - * + * * @version 0.1.3 * @param string $name House name. * @return int House ID. @@ -147,17 +147,17 @@ public function getHouseId($name) /** * Returns amount of houses. - * + * * @return int Count of houses. */ - public function count() + public function count(): int { return count($this->houses); } /** * Returns iterator handle for loops. - * + * * @return ArrayIterator Houses list iterator. */ public function getIterator() @@ -167,7 +167,7 @@ public function getIterator() /** * Checks if given element exists. - * + * * @param string|int $offset Array key. * @return bool True if it's set. */ @@ -185,7 +185,7 @@ public function offsetExists($offset) /** * Returns item from given position. - * + * * @version 0.1.3 * @param string|int $offset Array key. * @return OTS_House|int If key is an integer (type-sensitive!) then returns house instance. If it's a string then return associated ID found by house name. @@ -204,7 +204,7 @@ public function offsetGet($offset) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to houses list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @param string|int $offset Array key. * @param mixed $value Field value. * @throws E_OTS_ReadOnly Always - this class is read-only. @@ -216,7 +216,7 @@ public function offsetSet($offset, $value) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to houses list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @param string|int $offset Array key. * @throws E_OTS_ReadOnly Always - this class is read-only. */ @@ -227,11 +227,11 @@ public function offsetUnset($offset) /** * Returns string representation of object. - * + * *

    * If any display driver is currently loaded then it uses it's method. *

    - * + * * @version 0.1.3 * @since 0.1.3 * @return string String representation of object. diff --git a/system/libs/pot/OTS_Item.php b/system/libs/pot/OTS_Item.php index cbcb2fa9ac..449bf73cf0 100644 --- a/system/libs/pot/OTS_Item.php +++ b/system/libs/pot/OTS_Item.php @@ -15,11 +15,11 @@ /** * Single item representation. - * + * *

    * This class represents item that player has. It has no information about item feature, just it's handle in database. To get information about item type and it's features you have to use {@link OTS_ItemType OTS_ItemType class} - you can get it's object by calling {@link OTS_Item::getItemType() getItemType() method}, however you need to have global item types list loaded. *

    - * + * * @package POT * @version 0.1.0 * @property int $count Amount of item. @@ -31,28 +31,28 @@ class OTS_Item implements Countable { /** * Item ID. - * + * * @var int */ private $id; /** * Item count. - * + * * @var int */ private $count = 0; /** * Additional attributes. - * + * * @var string */ private $attributes; /** * Creates item of given ID. - * + * * @param int $id Item ID. */ public function __construct($id) @@ -62,7 +62,7 @@ public function __construct($id) /** * Returns item type. - * + * * @return int Item ID. */ public function getId() @@ -72,7 +72,7 @@ public function getId() /** * Returns count of item. - * + * * @return int Count of item. */ public function getCount() @@ -82,7 +82,7 @@ public function getCount() /** * Sets count of item. - * + * * @param int $count Count. */ public function setCount($count) @@ -92,7 +92,7 @@ public function setCount($count) /** * Returns item custom attributes. - * + * * @return string Attributes. */ public function getAttributes() @@ -102,7 +102,7 @@ public function getAttributes() /** * Sets item attributes. - * + * * @param string $attributes Item Attributes. */ public function setAttributes($attributes) @@ -112,7 +112,7 @@ public function setAttributes($attributes) /** * Returns type of item. - * + * * @version 0.1.0 * @since 0.1.0 * @return OTS_ItemType Returns item type of item (null if not exists). @@ -125,17 +125,17 @@ public function getItemType() /** * Count value for current item. - * + * * @return int Count of item. */ - public function count() + public function count(): int { return $this->count; } /** * Magic PHP5 method. - * + * * @version 0.1.0 * @since 0.1.0 * @param string $name Property name. @@ -166,7 +166,7 @@ public function __get($name) /** * Magic PHP5 method. - * + * * @version 0.1.0 * @since 0.1.0 * @param string $name Property name. diff --git a/system/libs/pot/OTS_ItemsList.php b/system/libs/pot/OTS_ItemsList.php index a9dcb2dd6d..1865117a8f 100644 --- a/system/libs/pot/OTS_ItemsList.php +++ b/system/libs/pot/OTS_ItemsList.php @@ -7,7 +7,7 @@ /** * Code in this file bases on oryginal OTServ items loading C++ code (itemloader.h, items.cpp, items.h). - * + * * @package POT * @version 0.1.3 * @author Wrzasq @@ -17,7 +17,7 @@ /** * Items list loader. - * + * * @package POT * @version 0.1.3 * @property-read int $otbVersion OTB file version. @@ -88,35 +88,35 @@ class OTS_ItemsList extends OTS_FileLoader implements IteratorAggregate, Countab /** * Temple positions. - * + * * @var array */ private $items = array(); /** * OTB version. - * + * * @var int */ private $otbVersion; /** * Client version. - * + * * @var int */ private $clientVersion; /** * Build version. - * + * * @var int */ private $buildVersion; /** * Magic PHP5 method. - * + * *

    * Allows object unserialisation. *

    @@ -129,11 +129,11 @@ public function __wakeup() /** * Loads items.xml and items.otb files. - * + * *

    * This method loads both items.xml and items.otb files. Both of them has to be in given directory. *

    - * + * * @version 0.1.3 * @param string $path Path to data/items directory. * @throws E_OTS_FileLoaderError When error occurs during file operation. @@ -191,7 +191,7 @@ public function loadItems($path) /** * Parses loaded file. - * + * * @version 0.1.0 * @throws E_OTS_FileLoaderError If file has invalid format. */ @@ -378,7 +378,7 @@ private function parse() /** * Returns OTB file version. - * + * * @return int OTB format version. */ public function getOTBVersion() @@ -388,7 +388,7 @@ public function getOTBVersion() /** * Returns client version. - * + * * @return int Client version. */ public function getClientVersion() @@ -398,7 +398,7 @@ public function getClientVersion() /** * Returns build version. - * + * * @return int Build version. */ public function getBuildVersion() @@ -408,7 +408,7 @@ public function getBuildVersion() /** * Checks if given item type exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Name. @@ -430,7 +430,7 @@ public function hasItemType($name) /** * Returns given item type. - * + * * @version 0.1.3 * @param int $id Item type (server) ID. * @return OTS_ItemType Returns item type of given ID. @@ -448,7 +448,7 @@ public function getItemType($id) /** * Checks if given type ID exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param int $id ID. @@ -461,11 +461,11 @@ public function hasItemTypeId($id) /** * Finds item type by it's name. - * + * *

    * Note: If there are more then one items with same name this function will return first found server ID. It doesn't also mean that it will be the lowest ID - item types are ordered in order that they were loaded from items.xml file. *

    - * + * * @version 0.1.3 * @param string $name Item type name. * @return int Returns item type (server) ID. @@ -497,10 +497,10 @@ public function getItemTypesList() /** * Returns amount of items loaded. - * + * * @return int Count of types. */ - public function count() + public function count(): int { return count($this->items); } @@ -550,7 +550,7 @@ public function rewind() /** * Returns iterator handle for loops. - * + * * @version 0.1.0 * @since 0.1.0 * @return ArrayIterator Items list iterator. @@ -562,7 +562,7 @@ public function getIterator() /** * Checks if given element exists. - * + * * @version 0.1.0 * @since 0.1.0 * @param string|int $offset Array key. @@ -582,7 +582,7 @@ public function offsetExists($offset) /** * Returns item from given position. - * + * * @version 0.1.3 * @since 0.1.0 * @param string|int $offset Array key. @@ -602,7 +602,7 @@ public function offsetGet($offset) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to items list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @version 0.1.0 * @since 0.1.0 * @param string|int $offset Array key. @@ -616,7 +616,7 @@ public function offsetSet($offset, $value) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to items list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @version 0.1.0 * @since 0.1.0 * @param string|int $offset Array key. @@ -629,7 +629,7 @@ public function offsetUnset($offset) /** * Magic PHP5 method. - * + * * @version 0.1.0 * @since 0.1.0 * @param string $name Property name. @@ -652,11 +652,11 @@ public function __get($name) /** * Returns string representation of object. - * + * *

    * If any display driver is currently loaded then it uses it's method. *

    - * + * * @version 0.1.3 * @since 0.1.3 * @return string String representation of object. diff --git a/system/libs/pot/OTS_MonstersList.php b/system/libs/pot/OTS_MonstersList.php index 85d0b3814d..48a0c260f9 100644 --- a/system/libs/pot/OTS_MonstersList.php +++ b/system/libs/pot/OTS_MonstersList.php @@ -15,7 +15,7 @@ /** * Wrapper for monsters list. - * + * * @package POT * @version 0.1.3 * @tutorial POT/data_directory.pkg#monsters @@ -24,66 +24,65 @@ class OTS_MonstersList implements Iterator, Countable, ArrayAccess { /** * Monsters directory. - * + * * @var string */ private $monstersPath; /** * List of loaded monsters. - * + * * @var array */ private $monsters = array(); private $lastMonsterFile = ''; private $hasErrors = false; -/** - * Loads monsters mapping file. - * - *

    - * Note: You pass directory path, not monsters.xml file name itself. - *

    - * - * @param string $path Monsters directory. - * @throws DOMException On DOM operation error. - */ + + /** + * Loads monsters mapping file. + * + *

    + * Note: You pass directory path, not monsters.xml file name itself. + *

    + * + * @param string $path Monsters directory. + * @throws DOMException On DOM operation error. + */ public function __construct($path) { $this->monstersPath = $path; // makes sure it has directory separator at the end $last = substr($this->monstersPath, -1); - if($last != '/' && $last != '\\') - { + if ($last != '/' && $last != '\\') { $this->monstersPath .= '/'; } - // check if monsters.xml exist - if(!@file_exists($this->monstersPath . 'monsters.xml')) { - log_append('error.log', '[OTS_MonstersList.php] Fatal error: Cannot load monsters.xml. File does not exist. (' . $this->monstersPath . 'monsters.xml' . '). Error: ' . print_r(error_get_last(), true)); - throw new Exception('Error: Cannot load monsters.xml. File not found. More info in system/logs/error.log file.'); - } - + // check if monsters.xml exist + if (!@file_exists($this->monstersPath . 'monsters.xml')) { + log_append('error.log', '[OTS_MonstersList.php] Fatal error: Cannot load monsters.xml. File does not exist. (' . $this->monstersPath . 'monsters.xml' . ').'); + throw new Exception('Error: Cannot load monsters.xml. File not found.'); + } + // loads monsters mapping file $monsters = new DOMDocument(); - if(!@$monsters->load($this->monstersPath . 'monsters.xml')) { - log_append('error.log', '[OTS_MonstersList.php] Fatal error: Cannot load monsters.xml (' . $this->monstersPath . 'monsters.xml' . '). Error: ' . print_r(error_get_last(), true)); - throw new Exception('Error: Cannot load monsters.xml. File is invalid. More info in system/logs/error.log file.'); - } + if (!@$monsters->load($this->monstersPath . 'monsters.xml')) { + log_append('error.log', '[OTS_MonstersList.php] Fatal error: Cannot load monsters.xml (' . $this->monstersPath . 'monsters.xml' . '). Error: ' . print_r(error_get_last(), true)); + throw new Exception('Error: Cannot load monsters.xml. File is invalid. More info in system/logs/error.log file.'); + } - foreach( $monsters->getElementsByTagName('monster') as $monster) - { - $this->monsters[ $monster->getAttribute('name') ] = $monster->getAttribute('file'); - //echo $this->monsters[ $monster->getAttribute('name')]; + foreach ($monsters->getElementsByTagName('monster') as $monster) { + $this->monsters[$monster->getAttribute('name')] = $monster->getAttribute('file'); + //echo $this->monsters[ $monster->getAttribute('name')]; } } /** * Magic PHP5 method. - * + * * Allows object importing from {@link http://www.php.net/manual/en/function.var-export.php var_export()}. - * + * * @param array $properties List of object properties. */ public static function __set_state($properties) @@ -101,7 +100,7 @@ public static function __set_state($properties) /** * Checks if given monster ID exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Monster name. @@ -124,7 +123,7 @@ function xmlErrorHandler($errno, $errstr, $errfile, $errline) } /** * Returns loaded data of given monster. - * + * * @version 0.1.3 * @param string $name Monster name. * @return OTS_Monster Monster data. @@ -140,10 +139,10 @@ public function getMonster($name) // loads file $monster = new OTS_Monster(); //echo $this->monstersPath . $this->monsters[$name]; - + // check if monster file exist if(file_exists($this->monstersPath . $this->monsters[$name])) { - set_error_handler(array($this, 'xmlErrorHandler')); + set_error_handler(array($this, 'xmlErrorHandler')); $this->lastMonsterFile = $this->monstersPath . $this->monsters[$name]; @$monster->loadXML(trim(file_get_contents($this->monstersPath . $this->monsters[$name]))); restore_error_handler(); @@ -160,25 +159,26 @@ public function hasErrors() { } /** * Returns amount of monsters loaded. - * + * * @return int Count of monsters. */ - public function count() + public function count(): int { return count($this->monsters); } /** * Returns monster at current position in iterator. - * + * * @return OTS_Monster Monster. * @throws DOMException On DOM operation error. */ + #[\ReturnTypeWillChange] public function current() { return $this->getMonster( key($this->monsters) ); } - + public function currentFile() { return $this->monsters[key($this->monsters)]; @@ -187,16 +187,17 @@ public function currentFile() /** * Moves to next iterator monster. */ - public function next() + public function next(): void { next($this->monsters); } /** * Returns name of current position. - * + * * @return string Current position key. */ + #[\ReturnTypeWillChange] public function key() { return key($this->monsters); @@ -204,10 +205,10 @@ public function key() /** * Checks if there is anything more in interator. - * + * * @return bool If iterator has anything more. */ - public function valid() + public function valid(): bool { return key($this->monsters) !== null; } @@ -215,17 +216,18 @@ public function valid() /** * Resets iterator index. */ - public function rewind() + public function rewind(): void { reset($this->monsters); } /** * Checks if given element exists. - * + * * @param string $offset Array key. * @return bool True if it's set. */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->monsters[$offset]); @@ -233,12 +235,13 @@ public function offsetExists($offset) /** * Returns item from given position. - * + * * @version 0.1.3 * @param string $offset Array key. * @return OTS_Monster Monster instance. * @throws DOMException On DOM operation error. */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->getMonster($offset); @@ -246,11 +249,12 @@ public function offsetGet($offset) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to monsters list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @param string|int $offset Array key. * @param mixed $value Field value. * @throws E_OTS_ReadOnly Always - this class is read-only. */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { throw new E_OTS_ReadOnly(); @@ -258,10 +262,11 @@ public function offsetSet($offset, $value) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to monsters list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @param string|int $offset Array key. * @throws E_OTS_ReadOnly Always - this class is read-only. */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { throw new E_OTS_ReadOnly(); @@ -269,11 +274,11 @@ public function offsetUnset($offset) /** * Returns string representation of object. - * + * *

    * If any display driver is currently loaded then it uses it's method. *

    - * + * * @version 0.1.3 * @since 0.1.3 * @return string String representation of object. diff --git a/system/libs/pot/OTS_OTBMFile.php b/system/libs/pot/OTS_OTBMFile.php index 3469f858f6..3183247f56 100644 --- a/system/libs/pot/OTS_OTBMFile.php +++ b/system/libs/pot/OTS_OTBMFile.php @@ -7,7 +7,7 @@ /** * Code in this file bases on oryginal OTServ OTBM format loading C++ code (iomapotbm.h, iomapotbm.cpp). - * + * * @package POT * @version 0.1.3 * @author Wrzasq @@ -20,11 +20,11 @@ /** * OTBM format reader. - * + * *

    * POT OTBM file parser is less strict then oryginal OTServ one. For instance it will read waypoints from version 1 OTBM file even that there were no waypoints in that format. *

    - * + * * @package POT * @version 0.1.6 * @property-read OTS_HousesList $housesList Houses list loaded from associated houses file. @@ -95,56 +95,56 @@ class OTS_OTBMFile extends OTS_FileLoader implements IteratorAggregate, Countabl const OTBM_ATTR_HOUSEDOORID = 14; /** * Amount. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_ATTR_COUNT = 15; /** * Time interval. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_ATTR_DURATION = 16; /** * Metamorphic stage. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_ATTR_DECAYING_STATE = 17; /** * Date of being written. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_ATTR_WRITTENDATE = 18; /** * Sign author. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_ATTR_WRITTENBY = 19; /** * Sleeping player ID. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_ATTR_SLEEPERGUID = 20; /** * Time of sleep started. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_ATTR_SLEEPSTART = 21; /** * Number of charges. - * + * * @version 0.1.6 * @since 0.1.6 */ @@ -208,14 +208,14 @@ class OTS_OTBMFile extends OTS_FileLoader implements IteratorAggregate, Countabl const OTBM_NODE_HOUSETILE = 14; /** * Waypoints list. - * + * * @version 0.1.6 * @since 0.1.6 */ const OTBM_NODE_WAYPOINTS = 15; /** * Waypoint. - * + * * @version 0.1.6 * @since 0.1.6 */ @@ -223,56 +223,56 @@ class OTS_OTBMFile extends OTS_FileLoader implements IteratorAggregate, Countabl /** * Map width. - * + * * @var int */ private $width; /** * Map height. - * + * * @var int */ private $height; /** * Map description. - * + * * @var string */ private $description = ''; /** * List of towns. - * + * * @var array */ private $towns = array(); /** * Temple positions. - * + * * @var array */ private $temples = array(); /** * Directory path. - * + * * @var string */ private $directory; /** * External houses file. - * + * * @var OTS_HousesList */ private $housesList; /** * List of map tracks. - * + * * @var array * @version 0.1.6 * @since 0.1.6 @@ -281,11 +281,11 @@ class OTS_OTBMFile extends OTS_FileLoader implements IteratorAggregate, Countabl /** * Magic PHP5 method. - * + * *

    * Allows object unserialisation. *

    - * + * * @throws E_OTS_FileLoaderError When error occurs during file operation. */ public function __wakeup() @@ -296,7 +296,7 @@ public function __wakeup() /** * Loads OTBM file content. - * + * * @version 0.1.0 * @param string $file Filename. * @throws E_OTS_FileLoaderError When error occurs during file operation. @@ -316,7 +316,7 @@ public function loadFile($file) /** * Parses loaded file. - * + * * @version 0.1.0 * @throws E_OTS_FileLoaderError When error occurs during file operation. * @throws E_OTS_OutOfBuffer When there is read attemp after end of stream. @@ -476,7 +476,7 @@ private function parse() /** * Loads map's houses list. - * + * * @version 0.1.0 * @since 0.1.0 * @return OTS_HousesList Houses from external file. @@ -488,7 +488,7 @@ public function getHousesList() /** * Returns map width. - * + * * @return int Map width. */ public function getWidth() @@ -498,7 +498,7 @@ public function getWidth() /** * Returns map height. - * + * * @return int Map height. */ public function getHeight() @@ -508,7 +508,7 @@ public function getHeight() /** * Returns map description. - * + * * @return string Map description. */ public function getDescription() @@ -518,11 +518,11 @@ public function getDescription() /** * Returns map waypoints list. - * + * *

    * Each item of returned array is sub-array with list of waypoints. *

    - * + * * @version 0.1.6 * @since 0.1.6 * @return array List of tracks. @@ -534,7 +534,7 @@ public function getWaypointsList() /** * Checks if given town ID exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param int $id ID. @@ -547,7 +547,7 @@ public function hasTownId($id) /** * Returns town's ID. - * + * * @version 0.1.3 * @param string $name Town. * @return int ID. @@ -567,7 +567,7 @@ public function getTownID($name) /** * Checks if given town name exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Town. @@ -580,7 +580,7 @@ public function hasTownName($name) /** * Returns name of given town's ID. - * + * * @version 0.1.3 * @param int $id Town ID. * @return string Name. @@ -607,7 +607,7 @@ public function getTownsList() /** * Returns town's temple position. - * + * * @param int $id Town id. * @return OTS_MapCoords|bool Point on map (false if not found). */ @@ -625,12 +625,12 @@ public function getTownTemple($id) /** * Returns amount of towns loaded. - * + * * @version 0.0.8 * @since 0.0.8 * @return int Count of towns. */ - public function count() + public function count(): int { return count($this->towns); } @@ -690,7 +690,7 @@ public function rewind() /** * Returns iterator handle for loops. - * + * * @version 0.1.0 * @since 0.1.0 * @return ArrayIterator Towns list iterator. @@ -702,7 +702,7 @@ public function getIterator() /** * Checks if given element exists. - * + * * @version 0.1.0 * @since 0.1.0 * @param string|int $offset Array key. @@ -724,7 +724,7 @@ public function offsetExists($offset) /** * Returns item from given position. - * + * * @version 0.1.0 * @since 0.1.0 * @param string|int $offset Array key. @@ -754,7 +754,7 @@ public function offsetGet($offset) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to towns list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @version 0.1.0 * @since 0.1.0 * @param string|int $offset Array key. @@ -768,7 +768,7 @@ public function offsetSet($offset, $value) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to towns list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @version 0.1.0 * @since 0.1.0 * @param string|int $offset Array key. @@ -781,7 +781,7 @@ public function offsetUnset($offset) /** * Magic PHP5 method. - * + * * @version 0.1.0 * @since 0.1.0 * @param string $name Property name. @@ -814,11 +814,11 @@ public function __get($name) /** * Returns string representation of object. - * + * *

    * If any display driver is currently loaded then it uses it's method. *

    - * + * * @version 0.1.3 * @since 0.1.3 * @return string String representation of object. diff --git a/system/libs/pot/OTS_Player.php b/system/libs/pot/OTS_Player.php index 79dd006df2..94d9d2bb8b 100644 --- a/system/libs/pot/OTS_Player.php +++ b/system/libs/pot/OTS_Player.php @@ -405,7 +405,7 @@ public function save() } // UPDATE query on database - $this->db->query('UPDATE ' . $this->db->tableName('players') . ' SET ' . $this->db->fieldName('name') . ' = ' . $this->db->quote($this->data['name']) . ', ' . $this->db->fieldName('account_id') . ' = ' . $this->data['account_id'] . ', ' . $this->db->fieldName('group_id') . ' = ' . $this->data['group_id'] . ', ' . $this->db->fieldName('sex') . ' = ' . $this->data['sex'] . ', ' . $this->db->fieldName('vocation') . ' = ' . $this->data['vocation'] . ', ' . $this->db->fieldName('experience') . ' = ' . $this->data['experience'] . ', ' . $this->db->fieldName('level') . ' = ' . $this->data['level'] . ', ' . $this->db->fieldName('maglevel') . ' = ' . $this->data['maglevel'] . ', ' . $this->db->fieldName('health') . ' = ' . $this->data['health'] . ', ' . $this->db->fieldName('healthmax') . ' = ' . $this->data['healthmax'] . ', ' . $this->db->fieldName('mana') . ' = ' . $this->data['mana'] . ', ' . $this->db->fieldName('manamax') . ' = ' . $this->data['manamax'] . ', ' . $this->db->fieldName('manaspent') . ' = ' . $this->data['manaspent'] . ', ' . $this->db->fieldName('soul') . ' = ' . $this->data['soul'] . ', ' . $this->db->fieldName('lookbody') . ' = ' . $this->data['lookbody'] . ', ' . $this->db->fieldName('lookfeet') . ' = ' . $this->data['lookfeet'] . ', ' . $this->db->fieldName('lookhead') . ' = ' . $this->data['lookhead'] . ', ' . $this->db->fieldName('looklegs') . ' = ' . $this->data['looklegs'] . ', ' . $this->db->fieldName('looktype') . ' = ' . $this->data['looktype'] . $lookaddons . ', ' . $this->db->fieldName('posx') . ' = ' . $this->data['posx'] . ', ' . $this->db->fieldName('posy') . ' = ' . $this->data['posy'] . ', ' . $this->db->fieldName('posz') . ' = ' . $this->data['posz'] . ', ' . $this->db->fieldName('cap') . ' = ' . $this->data['cap'] . ', ' . $this->db->fieldName('lastlogin') . ' = ' . $this->data['lastlogin'] . ', ' . $this->db->fieldName('lastlogout') . ' = ' . $this->data['lastlogout'] . ', ' . $this->db->fieldName('lastip') . ' = ' . $this->data['lastip'] . ', ' . $this->db->fieldName('save') . ' = ' . (int) $this->data['save'] . ', ' . $this->db->fieldName('conditions') . ' = ' . $this->db->quote($this->data['conditions']) . ', `' . $skull_time . '` = ' . $this->data['skulltime'] . ', `' . $skull_type . '` = ' . (int) $this->data['skull'] . $guild_info . ', ' . $this->db->fieldName('town_id') . ' = ' . $this->data['town_id'] . $loss . $loss_items . ', ' . $this->db->fieldName('balance') . ' = ' . $this->data['balance'] . $blessings . $stamina . $direction . $is_main . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); + $this->db->query('UPDATE ' . $this->db->tableName('players') . ' SET ' . $this->db->fieldName('name') . ' = ' . $this->db->quote($this->data['name']) . ', ' . $this->db->fieldName('account_id') . ' = ' . $this->data['account_id'] . ', ' . $this->db->fieldName('group_id') . ' = ' . $this->data['group_id'] . ', ' . $this->db->fieldName('sex') . ' = ' . $this->data['sex'] . ', ' . $this->db->fieldName('vocation') . ' = ' . $this->data['vocation'] . ', ' . $this->db->fieldName('experience') . ' = ' . $this->data['experience'] . ', ' . $this->db->fieldName('level') . ' = ' . $this->data['level'] . ', ' . $this->db->fieldName('maglevel') . ' = ' . $this->data['maglevel'] . ', ' . $this->db->fieldName('health') . ' = ' . $this->data['health'] . ', ' . $this->db->fieldName('healthmax') . ' = ' . $this->data['healthmax'] . ', ' . $this->db->fieldName('mana') . ' = ' . $this->data['mana'] . ', ' . $this->db->fieldName('manamax') . ' = ' . $this->data['manamax'] . ', ' . $this->db->fieldName('manaspent') . ' = ' . $this->data['manaspent'] . ', ' . $this->db->fieldName('soul') . ' = ' . $this->data['soul'] . ', ' . $this->db->fieldName('lookbody') . ' = ' . $this->data['lookbody'] . ', ' . $this->db->fieldName('lookfeet') . ' = ' . $this->data['lookfeet'] . ', ' . $this->db->fieldName('lookhead') . ' = ' . $this->data['lookhead'] . ', ' . $this->db->fieldName('looklegs') . ' = ' . $this->data['looklegs'] . ', ' . $this->db->fieldName('looktype') . ' = ' . $this->data['looktype'] . $lookaddons . ', ' . $this->db->fieldName('posx') . ' = ' . $this->data['posx'] . ', ' . $this->db->fieldName('posy') . ' = ' . $this->data['posy'] . ', ' . $this->db->fieldName('posz') . ' = ' . $this->data['posz'] . ', ' . $this->db->fieldName('cap') . ' = ' . $this->data['cap'] . ', ' . $this->db->fieldName('lastlogin') . ' = ' . $this->data['lastlogin'] . ', ' . $this->db->fieldName('lastlogout') . ' = ' . $this->data['lastlogout'] . ', ' . $this->db->fieldName('lastip') . ' = ' . $this->db->quote($this->data['lastip']) . ', ' . $this->db->fieldName('save') . ' = ' . (int) $this->data['save'] . ', ' . $this->db->fieldName('conditions') . ' = ' . $this->db->quote($this->data['conditions']) . ', `' . $skull_time . '` = ' . $this->data['skulltime'] . ', `' . $skull_type . '` = ' . (int) $this->data['skull'] . $guild_info . ', ' . $this->db->fieldName('town_id') . ' = ' . $this->data['town_id'] . $loss . $loss_items . ', ' . $this->db->fieldName('balance') . ' = ' . $this->data['balance'] . $blessings . $stamina . $direction . $is_main . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); } // creates new player else diff --git a/system/libs/pot/OTS_SpellsList.php b/system/libs/pot/OTS_SpellsList.php index 8f16115aba..bb9b92947c 100644 --- a/system/libs/pot/OTS_SpellsList.php +++ b/system/libs/pot/OTS_SpellsList.php @@ -15,11 +15,11 @@ /** * Wrapper for spells list. - * + * *

    * Note: Unlike other lists classes this one doesn't implement ArrayAccess interface because it contains three kinds of spells grouped into pararell arrays. *

    - * + * * @package POT * @version 0.1.5 * @property-read array $runesList List of rune spells. @@ -44,28 +44,28 @@ class OTS_SpellsList implements IteratorAggregate, Countable /** * Rune spells. - * + * * @var array */ private $runes = array(); /** * Instant spells. - * + * * @var array */ private $instants = array(); /** * Conjure spells. - * + * * @var array */ private $conjures = array(); /** * Magic PHP5 method. - * + * *

    * Allows object importing from {@link http://www.php.net/manual/en/function.var-export.php var_export()}. *

    @@ -85,49 +85,46 @@ public static function __set_state($properties) return $object; } -/** - * Loads spells list. - * - * @param string $file Spells file name. - * @throws DOMException On DOM operation error. - */ + /** + * Loads spells list. + * + * @param string $file Spells file name. + * @throws DOMException On DOM operation error. + */ public function __construct($file) { - // check if spells.xml exist - if(!@file_exists($file)) { - log_append('error.log', '[OTS_SpellsList.php] Fatal error: Cannot load spells.xml. File does not exist. (' . $file . '). Error: ' . print_r(error_get_last(), true)); - throw new Exception('Error: Cannot load spells.xml. File not found. More info in system/logs/error.log file.'); - } - + // check if spells.xml exist + if (!@file_exists($file)) { + log_append('error.log', '[OTS_SpellsList.php] Fatal error: Cannot load spells.xml. File does not exist. (' . $file . ').'); + throw new Exception('Error: Cannot load spells.xml. File not found.'); + } + // loads monsters mapping file $spells = new DOMDocument(); - if(!@$spells->load($file)) { - log_append('error.log', '[OTS_SpellsList.php] Fatal error: Cannot load spells.xml (' . $file . '). Error: ' . print_r(error_get_last(), true)); - throw new Exception('Error: Cannot load spells.xml. File is invalid. More info in system/logs/error.log file.'); - } + if (!@$spells->load($file)) { + log_append('error.log', '[OTS_SpellsList.php] Fatal error: Cannot load spells.xml (' . $file . '). Error: ' . print_r(error_get_last(), true)); + throw new Exception('Error: Cannot load spells.xml. File is invalid. More info in system/logs/error.log file.'); + } // loads runes - foreach( $spells->getElementsByTagName('rune') as $rune) - { - $this->runes[ $rune->getAttribute('name') ] = new OTS_Spell(self::SPELL_RUNE, $rune); + foreach ($spells->getElementsByTagName('rune') as $rune) { + $this->runes[$rune->getAttribute('name')] = new OTS_Spell(self::SPELL_RUNE, $rune); } // loads instants - foreach( $spells->getElementsByTagName('instant') as $instant) - { - $this->instants[ $instant->getAttribute('name') ] = new OTS_Spell(self::SPELL_INSTANT, $instant); + foreach ($spells->getElementsByTagName('instant') as $instant) { + $this->instants[$instant->getAttribute('name')] = new OTS_Spell(self::SPELL_INSTANT, $instant); } // loads conjures - foreach( $spells->getElementsByTagName('conjure') as $conjure) - { - $this->conjures[ $conjure->getAttribute('name') ] = new OTS_Spell(self::SPELL_CONJURE, $conjure); + foreach ($spells->getElementsByTagName('conjure') as $conjure) { + $this->conjures[$conjure->getAttribute('name')] = new OTS_Spell(self::SPELL_CONJURE, $conjure); } } /** * Returns list of runes. - * + * * @return array List of rune names. */ public function getRunesList() @@ -137,7 +134,7 @@ public function getRunesList() /** * Checks if rune exists. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Rune name. @@ -150,7 +147,7 @@ public function hasRune($name) /** * Returns given rune spell. - * + * * @version 0.1.3 * @param string $name Rune name. * @return OTS_Spell Rune spell wrapper. @@ -168,7 +165,7 @@ public function getRune($name) /** * Returns list of instants. - * + * * @return array List of instant spells names. */ public function getInstantsList() @@ -178,7 +175,7 @@ public function getInstantsList() /** * Checks if instant exists. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Instant name. @@ -191,7 +188,7 @@ public function hasInstant($name) /** * Returns given instant spell. - * + * * @version 0.1.3 * @param string $name Spell name. * @return OTS_Spell Instant spell wrapper. @@ -209,7 +206,7 @@ public function getInstant($name) /** * Returns list of conjure spells. - * + * * @return array List of conjure spells names. */ public function getConjuresList() @@ -219,7 +216,7 @@ public function getConjuresList() /** * Checks if conjure exists. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Conjure name. @@ -232,7 +229,7 @@ public function hasConjure($name) /** * Returns given conjure spell. - * + * * @version 0.1.3 * @param string $name Spell name. * @return OTS_Spell Conjure spell wrapper. @@ -250,7 +247,7 @@ public function getConjure($name) /** * Magic PHP5 method. - * + * * @param string $name Property name. * @return mixed Property value. * @throws OutOfBoundsException For non-supported properties. @@ -275,11 +272,11 @@ public function __get($name) /** * Returns string representation of object. - * + * *

    * If any display driver is currently loaded then it uses it's method. *

    - * + * * @version 0.1.3 * @since 0.1.3 * @return string String representation of object. @@ -299,16 +296,16 @@ public function __toString() /** * Iterator for all spells. - * + * *

    * Returned object will continousely iterate through all kind of spells. *

    - * + * * @version 0.1.5 * @since 0.1.5 * @return AppendIterator Iterator for all spells. */ - public function getIterator() + public function getIterator(): Traversable { $iterator = new AppendIterator(); $iterator->append( new ArrayIterator($this->runes) ); @@ -319,12 +316,12 @@ public function getIterator() /** * Number of all loaded spells. - * + * * @version 0.1.5 * @since 0.1.5 * @return int Amount of all spells. */ - public function count() + public function count(): int { return count($this->runes) + count($this->instants) + count($this->conjures); } diff --git a/system/libs/pot/OTS_VocationsList.php b/system/libs/pot/OTS_VocationsList.php index 7dc0e32ef6..368986842f 100644 --- a/system/libs/pot/OTS_VocationsList.php +++ b/system/libs/pot/OTS_VocationsList.php @@ -15,7 +15,7 @@ /** * Wrapper for vocations.xml file. - * + * * @package POT * @version 0.1.3 * @example examples/vocations.php vocations.php @@ -25,14 +25,14 @@ class OTS_VocationsList implements IteratorAggregate, Countable, ArrayAccess { /** * List of vocations. - * + * * @var array */ private $vocations = array(); /** * Loads vocations list from given file. - * + * * @param string $file vocations.xml file location. * @throws DOMException On DOM operation error. */ @@ -51,11 +51,11 @@ public function __construct($file) /** * Magic PHP5 method. - * + * *

    * Allows object importing from {@link http://www.php.net/manual/en/function.var-export.php var_export()}. *

    - * + * * @param array $properties List of object properties. * @throws DOMException On DOM operation error. */ @@ -74,7 +74,7 @@ public static function __set_state($properties) /** * Checks if given vocation ID exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param int $id ID. @@ -87,7 +87,7 @@ public function hasVocationId($id) /** * Returns vocation's ID. - * + * * @version 0.1.3 * @param string $name Vocation. * @return int ID. @@ -108,7 +108,7 @@ public function getVocationId($name) /** * Checks if given vocation name exists on list. - * + * * @version 0.1.3 * @since 0.1.3 * @param string $name Vocation. @@ -121,7 +121,7 @@ public function hasVocationName($name) /** * Returns name of given vocation's ID. - * + * * @version 0.1.3 * @param int $id Vocation ID. * @return string Name. @@ -139,17 +139,17 @@ public function getVocationName($id) /** * Returns amount of vocations loaded. - * + * * @return int Count of vocations. */ - public function count() + public function count(): int { return count($this->vocations); } /** * Returns iterator handle for loops. - * + * * @return ArrayIterator Vocations list iterator. */ public function getIterator() @@ -159,7 +159,7 @@ public function getIterator() /** * Checks if given element exists. - * + * * @version 0.1.3 * @param string|int $offset Array key. * @return bool True if it's set. @@ -178,7 +178,7 @@ public function offsetExists($offset) /** * Returns item from given position. - * + * * @version 0.1.3 * @param string|int $offset Array key. * @return string|int If key is an integer (type-sensitive!) then returns vocation name. If it's a string then return associated ID. @@ -197,7 +197,7 @@ public function offsetGet($offset) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to vocations list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @param string|int $offset Array key. * @param mixed $value Field value. * @throws E_OTS_ReadOnly Always - this class is read-only. @@ -209,7 +209,7 @@ public function offsetSet($offset, $value) /** * This method is implemented for ArrayAccess interface. In fact you can't write/append to vocations list. Any call to this method will cause {@link E_OTS_ReadOnly E_OTS_ReadOnly} raise. - * + * * @param string|int $offset Array key. * @throws E_OTS_ReadOnly Always - this class is read-only. */ diff --git a/system/libs/validator.php b/system/libs/validator.php index 81ffbba5ae..08639b364e 100644 --- a/system/libs/validator.php +++ b/system/libs/validator.php @@ -217,9 +217,10 @@ public static function newCharacterName($name) { global $db, $config; - $name_lower = strtolower($name); + $name_lower = strtolower($name); + $custom_first_words_blocked = $config['character_name_blocked']['prefix'] ?? []; - $first_words_blocked = array('admin ', 'administrator ', 'gm ', 'cm ', 'god ','tutor ', "'", '-'); + $first_words_blocked = array_merge($custom_first_words_blocked, ['admin ', 'administrator ', 'gm ', 'cm ', 'god ', 'tutor ', "'", '-']); foreach($first_words_blocked as $word) { if($word == substr($name_lower, 0, strlen($word))) { @@ -254,7 +255,8 @@ public static function newCharacterName($name) return false; } - $names_blocked = array('admin', 'administrator', 'gm', 'cm', 'god', 'tutor'); + $custom_names_blocked = $config['character_name_blocked']['names'] ?? []; + $names_blocked = array_merge($custom_names_blocked, ['admin', 'administrator', 'gm', 'cm', 'god', 'tutor']); foreach($names_blocked as $word) { if($word == $name_lower) { @@ -263,7 +265,8 @@ public static function newCharacterName($name) } } - $words_blocked = array('admin', 'administrator', 'gamemaster', 'game master', 'game-master', "game'master", '--', "''","' ", " '", '- ', ' -', "-'", "'-", 'fuck', 'sux', 'suck', 'noob', 'tutor'); + $custom_words_blocked = $config['character_name_blocked']['words'] ?? []; + $words_blocked = array_merge($custom_words_blocked, array('admin', 'administrator', 'gamemaster', 'game master', 'game-master', "game'master", '--', "''", "' ", " '", '- ', ' -', "-'", "'-", 'fuck', 'sux', 'suck', 'noob', 'tutor')); foreach($words_blocked as $word) { if(!(strpos($name_lower, $word) === false)) { @@ -323,16 +326,6 @@ public static function newCharacterName($name) } } - if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) { - self::$lastError = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.'; - return false; - } - - if(!preg_match("/[A-z ']/", $name)) { - self::$lastError = 'Your name containst illegal characters.'; - return false; - } - return true; } diff --git a/system/locale/de/install.php b/system/locale/de/install.php index 9307d22b52..ce581d1d76 100644 --- a/system/locale/de/install.php +++ b/system/locale/de/install.php @@ -20,7 +20,7 @@ $locale['loading_spinner'] = 'Bitte warten, installieren...'; $locale['importing_spinner'] = 'Bitte warte, Daten werden importiert...'; $locale['please_fill_all'] = 'Bitte füllen Sie alle Felder aus!'; -$locale['already_installed'] = 'MyAAC wurde bereits installiert. Bitte löschen install/ Verzeichnis. Wenn Sie MyAAC neu installieren möchten, löschen Sie die Datei config.local.php aus dem Hauptverzeichnis und aktualisieren Sie die Seite.'; +$locale['already_installed'] = 'MyAAC wurde bereits installiert. Bitte löschen install/ Verzeichnis. Wenn Sie MyAAC neu installieren möchten, löschen Sie die Datei config.local.php aus dem Hauptverzeichnis und aktualisieren Sie die Seite.'; // welcome $locale['step_welcome'] = 'Willkommen'; @@ -63,6 +63,7 @@ $locale['step_database'] = 'Schema importieren'; $locale['step_database_title'] = 'MySQL schema importieren'; $locale['step_database_importing'] = 'Ihre Datenbank ist MySQL. Datenbankname ist: "$DATABASE_NAME$". Schema wird jetzt importiert...'; +$locale['step_database_config_saved'] = 'Die lokale Konfiguration wurde in einer Datei gespeichert: config.local.php'; $locale['step_database_error_path'] = 'Bitte geben Sie den Serverpfad an.'; $locale['step_database_error_config'] = 'Datei config.lua kann nicht gefunden werden. Ist der Serverpfad korrekt? Gehen Sie zurück und überprüfen Sie noch einmal.'; $locale['step_database_error_database_empty'] = 'Der Datenbanktyp kann nicht aus config.lua ermittelt werden. Ihr OTS wird von diesem AAC nicht unterstützt.'; diff --git a/system/locale/en/install.php b/system/locale/en/install.php index f3d55e880a..1fc46e4476 100644 --- a/system/locale/en/install.php +++ b/system/locale/en/install.php @@ -20,7 +20,7 @@ $locale['loading_spinner'] = 'Please wait, installing...'; $locale['importing_spinner'] = 'Please wait, importing data...'; $locale['please_fill_all'] = 'Please fill all inputs!'; -$locale['already_installed'] = 'MyAAC has been already installed. Please delete install/ directory. If you want to reinstall MyAAC - please delete config.local.php file from the main directory and refresh the page.'; +$locale['already_installed'] = 'MyAAC has been already installed. Please delete install/ directory. If you want to reinstall MyAAC - please delete config.local.php file from the main directory and refresh the page.'; // welcome $locale['step_welcome'] = 'Welcome'; @@ -63,6 +63,7 @@ $locale['step_database'] = 'Import schema'; $locale['step_database_title'] = 'Import MySQL schema'; $locale['step_database_importing'] = 'Your database is MySQL. Database name is: "$DATABASE_NAME$". Importing schema now...'; +$locale['step_database_config_saved'] = 'Local configuration has been saved into file: config.local.php'; $locale['step_database_error_path'] = 'Please specify server path.'; $locale['step_database_error_config'] = 'Cannot find config.lua file. Is your server path correct? Go back and check again.'; $locale['step_database_error_database_empty'] = 'Cannot determine database type from config.lua. Your OTS is unsupported by this AAC.'; diff --git a/system/locale/pl/install.php b/system/locale/pl/install.php index 10a2773495..f12af021ef 100644 --- a/system/locale/pl/install.php +++ b/system/locale/pl/install.php @@ -59,6 +59,7 @@ $locale['step_database'] = 'Baza Danych'; $locale['step_database_title'] = 'Baza MySQL'; $locale['step_database_importing'] = 'Twoja baza to MySQL. Nazwa bazy danych to: "$DATABASE_NAME$". Importowanie schematu...'; +$locale['step_database_config_saved'] = 'Lokalna konfiguracja została zapisana do pliku: config.local.php'; $locale['step_database_error_path'] = 'Proszę podać ścieżkę do serwera.'; $locale['step_database_error_config'] = 'Nie można znaleźć pliku config.lua. Czy ścieżka do katalogu serwera jest poprawna? Wróć się i sprawdź ponownie.'; $locale['step_database_error_database_empty'] = 'Nie można wykryć typu bazy danych z pliku config.lua. Prawdopodobnie Twój OTS nie jest wspierany przez ten AAC.'; diff --git a/system/locale/pt_br/install.php b/system/locale/pt_br/install.php index b015a5afd2..b0fa95b7dd 100644 --- a/system/locale/pt_br/install.php +++ b/system/locale/pt_br/install.php @@ -20,7 +20,7 @@ $locale['loading_spinner'] = 'Por favor aguarde, instalando...'; $locale['importing_spinner'] = 'Por favor, aguarde, importando dados...'; $locale['please_fill_all'] = 'Por favor, preencha todas as entradas!'; -$locale['already_installed'] = 'MyAAC já foi instalado. Por favor, apague o diretório install/ . Se você quiser reinstalar o MyAAC - exclua o arquivo config.local.php do diretório principal e atualize a página.'; +$locale['already_installed'] = 'MyAAC já foi instalado. Por favor, apague o diretório install/ . Se você quiser reinstalar o MyAAC - exclua o arquivo config.local.php do diretório principal e atualize a página.'; // welcome $locale['step_welcome'] = 'Bem vindo'; @@ -63,6 +63,7 @@ $locale['step_database'] = 'Importar schema'; $locale['step_database_title'] = 'Importar MySQL schema'; $locale['step_database_importing'] = 'Seu banco de dados é o MySQL. O nome do banco de dados é: "$DATABASE_NAME$". Importando schema agora...'; +$locale['step_database_config_saved'] = 'A configuração local foi salva no arquivo: config.local.php'; $locale['step_database_error_path'] = 'Por favor, especifique o caminho da pasta do servidor.'; $locale['step_database_error_config'] = 'Não é possível encontrar o arquivo config.lua. O caminho da pasta do seu servidor está correto? Volte e verifique novamente.'; $locale['step_database_error_database_empty'] = 'Não é possível determinar o tipo de banco de dados a partir do config.lua. Seu OTS não é suportado por este AAC.'; diff --git a/system/locale/sv/install.php b/system/locale/sv/install.php index 81c4f60851..b5aaca0473 100644 --- a/system/locale/sv/install.php +++ b/system/locale/sv/install.php @@ -18,7 +18,7 @@ $locale['not_loaded'] = 'Inte Laddad'; $locale['please_fill_all'] = 'Vänligen fyll i allt!'; -$locale['already_installed'] = 'MyAAC är redan installerat. Vänligen ta bort install/ mappen. Om du vill installera MyAAC igen - ta bort filen config.local.php från huvudkatalogen och uppdatera sidan.'; +$locale['already_installed'] = 'MyAAC är redan installerat. Vänligen ta bort install/ mappen. Om du vill installera MyAAC igen - ta bort filen config.local.php från huvudkatalogen och uppdatera sidan.'; // welcome $locale['step_welcome'] = 'Välkommen'; @@ -57,6 +57,7 @@ $locale['step_database'] = 'Importera schema'; $locale['step_database_title'] = 'Importera MySQL schema'; $locale['step_database_importing'] = 'Din databas är MySQL. Databasnamnet är: "$DATABASE_NAME$". Importerar schema nu...'; +$locale['step_database_config_saved'] = 'Lokal konfiguration har sparats i filen: config.local.php'; $locale['step_database_error_path'] = 'Ange server mapp.'; $locale['step_database_error_config'] = 'Kan inte hitta konfigurations fil. Är din server mapp korrekt? Gå tillbaka och kolla igen.'; $locale['step_database_error_database_empty'] = 'Kan inte bestämma databas typ från config.lua. Din OTS stöds inte av MyAAC.'; diff --git a/system/login.php b/system/login.php index 74adfac25e..3207047df9 100644 --- a/system/login.php +++ b/system/login.php @@ -10,169 +10,147 @@ defined('MYAAC') or die('Direct access not allowed!'); $logged = false; $logged_flags = 0; +$account_logged = new OTS_Account(); $action = isset($_REQUEST['action']) ? strtolower($_REQUEST['action']) : ''; -if(!defined('ACTION')) { - define('ACTION', $action); +if (!defined('ACTION')) { + define('ACTION', $action); } // stay-logged with sessions $current_session = getSession('account'); -if($current_session !== false) -{ - $account_logged = new OTS_Account(); - $account_logged->load($current_session); - if($account_logged->isLoaded() && $account_logged->getPassword() == getSession('password') - //&& (!isset($_SESSION['admin']) || admin()) - && (getSession('remember_me') !== false || getSession('last_visit') > time() - 15 * 60)) { // login for 15 minutes if "remember me" is not used - $logged = true; - } - else { - unsetSession('account'); - unset($account_logged); - } +if ($current_session !== false) { + $account_logged->load($current_session); + if ($account_logged->isLoaded() && $account_logged->getPassword() == getSession('password') + //&& (!isset($_SESSION['admin']) || admin()) + && (getSession('remember_me') !== false || getSession('last_visit') > time() - 15 * 60)) { // login for 15 minutes if "remember me" is not used + $logged = true; + } else { + unsetSession('account'); + unset($account_logged); + } } -if(ACTION === 'logout' && !isset($_REQUEST['account_login'])) { - if(isset($account_logged) && $account_logged->isLoaded()) { - if($hooks->trigger(HOOK_LOGOUT, array('account' => $account_logged, 'password' => getSession('password')))) { - unsetSession('account'); - unsetSession('password'); - unsetSession('remember_me'); - - $logged = false; - unset($account_logged); - - if(isset($_REQUEST['redirect'])) - { - header('Location: ' . urldecode($_REQUEST['redirect'])); - exit; - } - } - } -} -else -{ - // new login with data from form - if(!$logged && isset($_POST['account_login'], $_POST['password_login'])) - { - $login_account = $_POST['account_login']; - $login_password = $_POST['password_login']; - $remember_me = isset($_POST['remember_me']); - if(!empty($login_account) && !empty($login_password)) - { - if($cache->enabled()) - { - $tmp = ''; - if($cache->fetch('failed_logins', $tmp)) - { - $tmp = unserialize($tmp); - $to_remove = array(); - foreach($tmp as $ip => $t) - { - if(time() - $t['last'] >= 5 * 60) - $to_remove[] = $ip; - } - - foreach($to_remove as $ip) - unset($tmp[$ip]); - } - else - $tmp = array(); - - $ip = $_SERVER['REMOTE_ADDR']; - $t = isset($tmp[$ip]) ? $tmp[$ip] : NULL; - } - - $account_logged = new OTS_Account(); - if (config('account_login_by_email')) { - $account_logged->findByEMail($login_account); - } - - if (!config('account_login_by_email') || config('account_login_by_email_fallback')) { - if(USE_ACCOUNT_NAME) { - $account_logged->find($login_account); - } else { - $account_logged->load($login_account, true); - } - } - - $config_salt_enabled = $db->hasColumn('accounts', 'salt'); - if($account_logged->isLoaded() && encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $login_password) == $account_logged->getPassword() - && (!isset($t) || $t['attempts'] < 5) - ) - { - setSession('account', $account_logged->getNumber()); - setSession('password', encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $login_password)); - if($remember_me) { - setSession('remember_me', true); - } - - $logged = true; - $logged_flags = $account_logged->getWebFlags(); - - if(isset($_POST['admin']) && !admin()) { - $errors[] = 'This account has no admin privileges.'; - unsetSession('account'); - unsetSession('password'); - unsetSession('remember_me'); - $logged = false; - } - else { - $account_logged->setCustomField('web_lastlogin', time()); - } - - $hooks->trigger(HOOK_LOGIN, array('account' => $account_logged, 'password' => $login_password, 'remember_me' => $remember_me)); - } - else - { - $hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me)); - - $errorMessage = getAccountLoginByLabel() . ' or password is not correct.'; - - // temporary solution for blocking failed login attempts - if($cache->enabled()) - { - if(isset($t)) - { - $t['attempts']++; - $t['last'] = time(); - - if($t['attempts'] >= 5) - $errors[] = 'A wrong password has been entered 5 times in a row. You are unable to log into your account for the next 5 minutes. Please wait.'; - else - $errors[] = $errorMessage; - } - else - { - $t = array('attempts' => 1, 'last' => time()); - $errors[] = $errorMessage; - } - - $tmp[$ip] = $t; - $cache->set('failed_logins', serialize($tmp), 60 * 60); // save for 1 hour - } - else { - $errors[] = $errorMessage; - } - } - } - else { - $errors[] = 'Please enter your ' . getAccountLoginByLabel() . ' and password.'; - - $hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me)); - } - } - - if($logged) { - $logged_flags = $account_logged->getWebFlags(); - $twig->addGlobal('logged', true); - $twig->addGlobal('account_logged', $account_logged); - } +if (ACTION === 'logout' && !isset($_REQUEST['account_login'])) { + if (isset($account_logged) && $account_logged->isLoaded()) { + if ($hooks->trigger(HOOK_LOGOUT, ['account_id' => $account_logged->getId()])) { + unsetSession('account'); + unsetSession('password'); + unsetSession('remember_me'); + + $logged = false; + unset($account_logged); + + if (isset($_REQUEST['redirect'])) { + header('Location: ' . urldecode($_REQUEST['redirect'])); + exit; + } + } + } +} else { + // new login with data from form + if (!$logged && isset($_POST['account_login'], $_POST['password_login'])) { + $login_account = $_POST['account_login']; + $login_password = $_POST['password_login']; + $remember_me = isset($_POST['remember_me']); + if (!empty($login_account) && !empty($login_password)) { + if ($cache->enabled()) { + $tmp = ''; + if ($cache->fetch('failed_logins', $tmp)) { + $tmp = unserialize($tmp); + $to_remove = array(); + foreach ($tmp as $ip => $t) { + if (time() - $t['last'] >= 5 * 60) + $to_remove[] = $ip; + } + + foreach ($to_remove as $ip) + unset($tmp[$ip]); + } else + $tmp = array(); + + $ip = $_SERVER['REMOTE_ADDR']; + $t = $tmp[$ip] ?? null; + } + + if (config('account_login_by_email')) { + $account_logged->findByEMail($login_account); + } + + if (!config('account_login_by_email') || config('account_login_by_email_fallback')) { + if (USE_ACCOUNT_NAME) { + $account_logged->find($login_account); + } else { + $account_logged->load($login_account, true); + } + } + + $config_salt_enabled = $db->hasColumn('accounts', 'salt'); + if ($account_logged->isLoaded() && encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $login_password) == $account_logged->getPassword() + && (!isset($t) || $t['attempts'] < 5) + ) { + setSession('account', $account_logged->getNumber()); + setSession('password', encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $login_password)); + if ($remember_me) { + setSession('remember_me', true); + } + + $logged = true; + $logged_flags = $account_logged->getWebFlags(); + + if (isset($_POST['admin']) && !admin()) { + $errors[] = 'This account has no admin privileges.'; + unsetSession('account'); + unsetSession('password'); + unsetSession('remember_me'); + $logged = false; + } else { + $account_logged->setCustomField('web_lastlogin', time()); + } + + $hooks->trigger(HOOK_LOGIN, array('account' => $account_logged, 'password' => $login_password, 'remember_me' => $remember_me)); + } else { + $hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me)); + + $errorMessage = getAccountLoginByLabel() . ' or password is not correct.'; + + // temporary solution for blocking failed login attempts + if ($cache->enabled()) { + if (isset($t)) { + $t['attempts']++; + $t['last'] = time(); + + if ($t['attempts'] >= 5) + $errors[] = 'A wrong password has been entered 5 times in a row. You are unable to log into your account for the next 5 minutes. Please wait.'; + else + $errors[] = $errorMessage; + } else { + $t = array('attempts' => 1, 'last' => time()); + $errors[] = $errorMessage; + } + + $tmp[$ip] = $t; + $cache->set('failed_logins', serialize($tmp), 60 * 60); // save for 1 hour + } else { + $errors[] = $errorMessage; + } + } + } else { + $errors[] = 'Please enter your ' . getAccountLoginByLabel() . ' and password.'; + + $hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me)); + } + } + + if ($logged) { + $logged_flags = $account_logged->getWebFlags(); + $twig->addGlobal('logged', true); + $twig->addGlobal('account_logged', $account_logged); + } } setSession('last_visit', time()); -if(defined('PAGE')) { - setSession('last_page', PAGE); +if (defined('PAGE')) { + setSession('last_page', PAGE); } setSession('last_uri', $_SERVER['REQUEST_URI']); diff --git a/system/migrations/34.php b/system/migrations/34.php new file mode 100644 index 0000000000..c325672fec --- /dev/null +++ b/system/migrations/34.php @@ -0,0 +1,6 @@ +exec('ALTER TABLE `' . TABLE_PREFIX . 'visitors` MODIFY `ip` VARCHAR(45) NOT NULL;'); diff --git a/system/pages/account/confirm_email.php b/system/pages/account/confirm_email.php index 078ba32454..27bd0aafd0 100644 --- a/system/pages/account/confirm_email.php +++ b/system/pages/account/confirm_email.php @@ -12,18 +12,26 @@ $title = 'Confirm Email'; $hash = isset($_GET['v']) ? $_GET['v'] : ''; -if(empty($hash)) { - warning('Please enter email hash code.
    If you copied the link, please try again with full link.'); - return; +if (empty($hash)) { + warning('Please enter email hash code.
    If you copied the link, please try again with full link.'); + return; } $res = $db->query('SELECT `email_hash` FROM `accounts` WHERE `email_hash` = ' . $db->quote($hash)); -if(!$res->rowCount()) { - note("Your email couldn't be verified. Please contact staff to do it manually."); -} -else -{ - $db->update('accounts', array('email_verified' => '1'), array('email_hash' => $hash)); - success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this.'); +if (!$res->rowCount()) { + note("Your email couldn't be verified. Please contact staff to do it manually."); +} else { + $query = $db->query('SELECT id FROM accounts WHERE email_hash = ' . $db->quote($hash) . ' AND email_verified = 0'); + if ($query->rowCount() == 1) { + $query = $query->fetch(PDO::FETCH_ASSOC); + $account = new OTS_Account(); + $account->load($query['id']); + if ($account->isLoaded()) { + $hooks->trigger(HOOK_EMAIL_CONFIRMED, ['account' => $account]); + } + } + + $db->update('accounts', array('email_verified' => '1'), array('email_hash' => $hash)); + success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this.'); } ?> diff --git a/system/pages/characters.php b/system/pages/characters.php index b67ac6b4bb..9892b5ddfa 100644 --- a/system/pages/characters.php +++ b/system/pages/characters.php @@ -277,7 +277,7 @@ function retrieve_former_name($name) unset($storage); } - if ($config['characters']['equipment']) { + if ($config['characters']['equipment'] && $db->hasTableAndColumns('player_items', ['pid', 'sid', 'itemtype'])) { $equipment = []; $empty_slots = array("", "no_helmet", "no_necklace", "no_backpack", "no_armor", "no_handleft", "no_handright", "no_legs", "no_boots", "no_ring", "no_ammo"); if ($hidden) { @@ -365,7 +365,7 @@ function retrieve_former_name($name) $deaths[] = array('time' => $death['date'], 'description' => $description . '.'); } } - }else { + } else if ($db->hasTableAndColumns('player_deaths', ['time', 'level', 'killed_by', 'is_player'])) { $mostdamage = ''; if($db->hasColumn('player_deaths', 'mostdamage_by')) $mostdamage = ', `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`'; diff --git a/system/pages/createaccount.php b/system/pages/createaccount.php index 0aed26ddff..94420510f8 100644 --- a/system/pages/createaccount.php +++ b/system/pages/createaccount.php @@ -201,7 +201,6 @@ $new_account->setPassword(encrypt($password)); $new_account->setEMail($email); - $new_account->unblock(); $new_account->save(); if($config_salt_enabled) @@ -253,7 +252,7 @@ } else { - error('An error occorred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log'); + error('An error occurred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log'); $new_account->delete(); } } @@ -264,6 +263,7 @@ $character_created = $createCharacter->doCreate($character_name, $character_sex, $character_vocation, $character_town, $new_account, $errors); if (!$character_created) { error('There was an error creating your character. Please create your character later in account management page.'); + error(implode(' ', $errors)); } } @@ -365,4 +365,4 @@ )); } -$twig->display('account.create.html.twig', $params); \ No newline at end of file +$twig->display('account.create.html.twig', $params); diff --git a/system/pages/guilds/accept_invite.php b/system/pages/guilds/accept_invite.php index d33d525609..46d55efb29 100644 --- a/system/pages/guilds/accept_invite.php +++ b/system/pages/guilds/accept_invite.php @@ -34,20 +34,17 @@ $errors[] = 'Invalid name format.'; } - if(empty($errors)) { - $player = new OTS_Player(); - $player->find($name); - if(!$player->isLoaded()) { - $errors[] = 'Player with name '.$name.' doesn\'t exist.'; - } - else - { - $rank_of_player = $player->getRank(); - if($rank_of_player->isLoaded()) { - $errors[] = 'Character with name '.$name.' is already in guild. You must leave guild before you join other guild.'; - } - } - } + if (empty($errors)) { + $player = new OTS_Player(); + $player->find($name); + if (!$player->isLoaded()) { + $errors[] = "Player with name {$name} doesn\'t exist."; + } else if ($player->getAccountID() != $account_logged->getId()) { + $errors[] = "Character with name {$name} is not in your account."; + } else if ($player->getRank()->isLoaded()) { + $errors[] = "Character with name {$name} is already in guild. You must leave guild before you join other guild."; + } + } } if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { @@ -64,9 +61,9 @@ } } - if(!$is_invited) { - $errors[] = 'Character '.$player->getName.' isn\'t invited to guild '.$guild->getName().'.'; - } + if (!$is_invited) { + $errors[] = "Character {$player->getName()} isn\'t invited to guild {$guild->getName()}."; + } } } else @@ -124,4 +121,4 @@ } } -?> \ No newline at end of file +?> diff --git a/system/pages/highscores.php b/system/pages/highscores.php index ca769de6d8..b121296b4e 100644 --- a/system/pages/highscores.php +++ b/system/pages/highscores.php @@ -14,9 +14,13 @@ if($config['account_country'] && $config['highscores_country_box']) require SYSTEM . 'countries.conf.php'; -$list = isset($_GET['list']) ? $_GET['list'] : ''; -$_page = isset($_GET['page']) ? $_GET['page'] : 0; -$vocation = isset($_GET['vocation']) ? $_GET['vocation'] : NULL; +$list = $_GET['list'] ?? ''; +$_page = $_GET['page'] ?? 0; +$vocation = $_GET['vocation'] ?? null; + +if (!is_numeric($_page) || $_page < 0 || $_page > PHP_INT_MAX) { + $_page = 0; +} $add_sql = ''; $config_vocations = $config['vocations']; @@ -322,7 +326,7 @@ if(isset($config['vocations'][$player['vocation']])) { $tmp = $config['vocations'][$player['vocation']]; } - + } echo ' diff --git a/system/pages/online.php b/system/pages/online.php index 0cc345251a..6a60dbbe31 100644 --- a/system/pages/online.php +++ b/system/pages/online.php @@ -53,9 +53,9 @@ } if($db->hasTable('players_online')) // tfs 1.0 - $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `level`, `vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); + $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); else - $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `level`, `vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); + $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); $players_data = array(); $explodeFlags = array(); diff --git a/system/status.php b/system/status.php index 6b9f204910..27cb650b7d 100644 --- a/system/status.php +++ b/system/status.php @@ -17,6 +17,10 @@ $status['uptime'] = '0h 0m'; $status['monsters'] = 0; +if (config('status_enabled') === false) { + return; +} + $status_ip = $config['lua']['ip']; if(isset($config['lua']['statusProtocolPort'])) { $config['lua']['loginPort'] = $config['lua']['statusProtocolPort']; diff --git a/system/template.php b/system/template.php index 2b38045a5f..af665cc79f 100644 --- a/system/template.php +++ b/system/template.php @@ -80,6 +80,7 @@ } $template_ini = parse_ini_file($file); + unset($file); if ($cache->enabled()) { $cache->set('template_ini_' . $template_name, serialize($template_ini)); diff --git a/system/templates/account.back_button.html.twig b/system/templates/account.back_button.html.twig new file mode 100644 index 0000000000..c7a952fcca --- /dev/null +++ b/system/templates/account.back_button.html.twig @@ -0,0 +1,7 @@ +{% if new_line is defined and new_line %} +
    +{% endif %} +
    + {{ include('buttons.back.html.twig') }} +
    diff --git a/system/templates/account.create_character.html.twig b/system/templates/account.create_character.html.twig index 1f0f2b811b..68d550245f 100644 --- a/system/templates/account.create_character.html.twig +++ b/system/templates/account.create_character.html.twig @@ -3,7 +3,7 @@ Please choose a name{% if config.character_samples|length > 1 %}, vocation{% end

    In any case the name must not violate the naming conventions stated in the {{ config.lua.serverName }} Rules, or your character might get deleted or name locked. -{% if account_logged.getPlayersList()|length >= config.characters_per_account %} +{% if account_logged.getPlayersList(false)|length >= config.characters_per_account %} You have maximum number of characters per account on your account. Delete one before you make new. {% endif %}
    @@ -162,8 +162,8 @@ In any case the name must not violate the naming conventions stated in the {% if config.lua.worldType == 'retro' %} - - + +
    {% endif %} - + {% if config.character_towns|length > 1 %} @@ -287,4 +287,4 @@ In any case the name must not violate the naming conventions stated in the - \ No newline at end of file + diff --git a/system/templates/admin.news.form.html.twig b/system/templates/admin.news.form.html.twig index 9509820679..67fc6fcae9 100644 --- a/system/templates/admin.news.form.html.twig +++ b/system/templates/admin.news.form.html.twig @@ -33,7 +33,7 @@
    @@ -186,4 +186,4 @@ window.onbeforeunload = unloadPage; -{% endif %} \ No newline at end of file +{% endif %} diff --git a/system/templates/characters.html.twig b/system/templates/characters.html.twig index 2907f8e4f3..8fc8760512 100644 --- a/system/templates/characters.html.twig +++ b/system/templates/characters.html.twig @@ -1,793 +1,1095 @@ {% set rows = 0 %} {% if canEdit %} -
    - {% set button_name = 'Edit Character' %} - {% include('buttons.base.html.twig') %} - -
    + + {% set button_name = 'Edit Character' %} + {% include('buttons.base.html.twig') %} + +
    {% endif %} - - - + + +
    -
    -
    -
    - - - - -
    Character Information
    - - - - -
    -
    - - - - - - -
    -
    - - - - - - -
    -
    - - - - {% set rows = rows + 1 %} - - - - - - {% set rows = rows + 1 %} - - - - - - {% set rows = rows + 1 %} - - - - - - {% set rows = rows + 1 %} - - - - - - {% set rows = rows + 1 %} - - - - - - {% set rows = rows + 1 %} - - - - - - {% set rows = rows + 1 %} - - - - - - {% if frags_enabled %} - {% set rows = rows + 1 %} - - - - - {% endif %} - - {% if config.characters.balance %} - {% set rows = rows + 1 %} - - - - - {% endif %} - - {% if house.found %} - {% set rows = rows + 1 %} - - - - - {% endif %} - - {% if guild.rank is not null %} - {% set rows = rows + 1 %} - - - - - {% endif %} - - {% if marriage_enabled %} - {% set rows = rows + 1 %} - - - - - {% endif %} - - {% set rows = rows + 1 %} - - - - - - {% if comment is not null %} - {% set rows = rows + 1 %} - - - - - {% endif %} - - {% set rows = rows + 1 %} - - - - - - -
    Name:{% if skull is not null %}{% endif %} {{ player.getName() }} {{ oldName }} {% if player.isOnline() %}{% else %}{% endif %}
    Country:{{ country }} {{ flag|raw }}
    Sex:{{ sex }}
    Vocation:{{ vocation }}
    Level:{{ player.getLevel() }}
    Achievement Points:{{ achievementPoints }}
    Residence:{{ town }}
    Frags:{{ frags_count }}
    Balance: - $ - {% if not player.isHidden() %} {{ player.getBalance() }} Gold Coins. - {% else %} Hidden {% endif %} -
    House:{{ house.name ~ house.town ~ house.add }}
    Guild membership:{{ guild.rank }} of the {{ guild.link|raw }}
    Marital status:{{ marital_status }}
    Last Login:{% if player.getLastLogin() == 0 %}Never logged in.{% else %}{{ player.getLastLogin()|date("M d Y, H:i:s") }} CEST{% endif %}
    Comment:{{ comment|raw }}
    Account Status:{% if account.isPremium() %}Premium Account{% else %}Free Account{% endif %}
    -
    -
    -
    -
    -
    -
    +
    +
    +
    + + + + +
    Character Information
    + + + + +
    +
    + + + + + + +
    +
    + + + + + + +
    +
    + + + + {% set rows = rows + 1 %} + + + + + + {% set rows = rows + 1 %} + + + + + + {% set rows = rows + 1 %} + + + + + + {% set rows = rows + 1 %} + + + + + + {% set rows = rows + 1 %} + + + + + + {% set rows = rows + 1 %} + + + + + + {% set rows = rows + 1 %} + + + + + + {% if frags_enabled %} + {% set rows = rows + 1 %} + + + + + {% endif %} + + {% if config.characters.balance %} + {% set rows = rows + 1 %} + + + + + {% endif %} + + {% if house.found %} + {% set rows = rows + 1 %} + + + + + {% endif %} + + {% if guild.rank is not null %} + {% set rows = rows + 1 %} + + + + + {% endif %} + + {% if marriage_enabled %} + {% set rows = rows + 1 %} + + + + + {% endif %} + + {% set rows = rows + 1 %} + + + + + + {% if comment is not null %} + {% set rows = rows + 1 %} + + + + + {% endif %} + + {% set rows = rows + 1 %} + + + + + + +
    Name:{% if skull is not null %}{% endif %} {{ player.getName() }} {{ oldName }} {% if player.isOnline() %} + {% else %}{% endif %} +
    +
    Country:{{ country }} {{ flag|raw }}
    Sex:{{ sex }}
    Vocation:{{ vocation }}
    Level:{{ player.getLevel() }}
    Achievement Points:{{ achievementPoints }}
    Residence:{{ town }}
    Frags:{{ frags_count }}
    Balance: + $ + {% if not player.isHidden() %} {{ player.getBalance() }} Gold Coins. + {% else %} Hidden {% endif %} +
    House:{{ house.name ~ house.town ~ house.add }}
    Guild membership:{{ guild.rank }} of the {{ guild.link|raw }}
    Marital status:{{ marital_status }}
    Last Login:{% if player.getLastLogin() == 0 %}Never logged in.{% else %}{{ player.getLastLogin()|date("M d Y, H:i:s") }} CEST{% endif %}
    Comment:{{ comment|raw }}
    Account Status:{% if account.isPremium() %}Premium Account{% else %} + Free Account{% endif %}
    +
    +
    +
    +
    +
    +

    -
    -
    - - - - -
    Account Information
    - - - - -
    - - - - -
    -
    - -
    -
    - - -{% set group = player.getGroup() %} -{% if group.isLoaded() and group.getId() != 1 %} -{% set rows = rows + 1 %} - - - - -{% endif %} -{% set rows = rows + 1 %} - - - - -
    Position:{{ group.getName()|capitalize }}
    Created:{{ account.getCreated()|date("M d Y, g:i:s") }} CET - {% if bannedUntil matches '/^\\d+$/' or bannedUntil == '-1' %} - [Banished {% if bannedUntil == '-1' %}forever{% else %}until {{ bannedUntil|date('d F Y, h:s') }}{% endif %}] - {% else %} - {{ bannedUntil|raw }} - {% endif %}
    -
    +
    +
    + + + + +
    Account Information
    + + + + +
    +
    + + + + + + +
    +
    + + + + + + +
    +
    + + + {% set group = player.getGroup() %} + {% if group.isLoaded() and group.getId() != 1 %} + {% set rows = rows + 1 %} + + + + + {% endif %} + {% set rows = rows + 1 %} + + + + + +
    Position:{{ group.getName()|capitalize }}
    Created:{{ account.getCreated()|date("M d Y, g:i:s") }} CET + {% if bannedUntil matches '/^\\d+$/' or bannedUntil == '-1' %} + [Banished {% if bannedUntil == '-1' %}forever{% else %}until {{ bannedUntil|date('d F Y, h:s') }}{% endif %}] + {% else %} + {{ bannedUntil|raw }} + {% endif %}
    +
    +
    +
    +
    -

    -
    -
    - - - - -
    Character Details
    - - - - -
    - - - - - -
    - -{% if config.characters.outfit %} -
    - - -
    -
    - - - - - -
    -Current outfit: - -
    -player outfit -
    -
    -
    -
    - -{% endif %} +
    +
    + + + + +
    Character Details
    + + + + +
    +
    + + + + - - - + + + + + +
    + + {% if config.characters.outfit %} +
    + + + + + + +
    +
    + + + + + + + +
    + Current outfit: + +
    + player outfit +
    +
    +
    +
    +
    + + {% endif %} -{% if config.characters.equipment %} - -
    - - -
    -
    - - - - - - - -
    -Inventory: -
    - - - - - - -
    - - - - - -
    {{ equipment[2]|raw }}
    {{ equipment[6]|raw }}
    {{ equipment[9]|raw }}
    Soul: {{ soul }}
    -
    - - - - - -
    {{ equipment[1]|raw }}
    {{ equipment[4]|raw }}
    {{ equipment[7]|raw }}
    {{ equipment[8]|raw }}
    -
    - - - - - - -
    {{ equipment[3]|raw }}
    {{ equipment[5]|raw }}
    {{ equipment[10]|raw }}
    Cap: {{ cap }}
    -
    -
    -
    -
    - -{% endif %} -
    -
    - - -
    -
    - - - - - - - - - -
    Health: -{{ health_current }}/{{ health_max }} ({{ health_percent }}%) -
    -
    -
    -
    Mana: -{{ mana_current }}/{{ mana_max }} ({{ mana_percent }}%) -
    -
    -
    -
    -
    -
    - - - -
    - - -
    -
    - - - - - - - - - -
    Experience: -Have {{ player.getExperience() }} and need {{ expLeft }} to Level {{ player.getLevel() + 1 }}. -
    Percent: -{{ player.getExperience() }}/{{ expNext }} ({{ expLeftPercent }}%) -
    -
    -
    -
    -
    -
    - - -{% if config.characters.skills %} - -
    - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - -{% set i = 0 %} -{% for skill in skills %} -{% set i = i + 1 %} - -{% endfor %} - -
    LevelMLFistClubSwordAxeDistDefFish
    {{ player.getLevel() }}{{ skill.value }}
    -
    + {% if config.characters.equipment %} + +
    + + + + + + +
    +
    + + + + + + + + + +
    + Inventory: +
    + + + + + + +
    + + + + + + + + + + + + + +
    {{ equipment[2]|raw }}
    {{ equipment[6]|raw }}
    {{ equipment[9]|raw }}
    Soul: {{ soul }}
    +
    + + + + + + + + + + + + + +
    {{ equipment[1]|raw }}
    {{ equipment[4]|raw }}
    {{ equipment[7]|raw }}
    {{ equipment[8]|raw }}
    +
    + + + + + + + + + + + + + +
    {{ equipment[3]|raw }}
    {{ equipment[5]|raw }}
    {{ equipment[10]|raw }}
    Cap: {{ cap }}
    +
    +
    +
    +
    +
    + + {% endif %} +
    +
    + + + + + + +
    +
    + + + + + + + + + + + +
    Health: + {{ health_current }}/{{ health_max }} ({{ health_percent }}%) +
    +
    +
    +
    Mana: + {{ mana_current }}/{{ mana_max }} ({{ mana_percent }}%) +
    +
    +
    +
    +
    +
    +
    + + + +
    + + + + + + +
    +
    + + + + + + + + + + + +
    Experience: + Have {{ player.getExperience() }} and need {{ expLeft }} to Level + {{ player.getLevel() + 1 }}. +
    Percent: + {{ player.getExperience() }}/{{ expNext }} ({{ expLeftPercent }}%) +
    +
    +
    +
    +
    +
    +
    + + + {% if config.characters.skills %} + +
    + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + {% set i = 0 %} + {% for skill in skills %} + {% set i = i + 1 %} + + {% endfor %} + + +
    + + + + + + + + +
    LevelMLFistClubSwordAxeDistDefFish
    {{ player.getLevel() }}{{ skill.value }}
    +
    +
    +
    + + {% endif %} +
    - -{% endif %} -

    -
    -
    - - - - -
    Character Quests
    - - - - -
    -
    -
    -
    - - - - -
    - -

    -
    -
    - - - - -
    Account Achievements
    - - - - -
    -
    -
    -
    -
    - - - - -
    - -
    +
    +
    + + + + +
    Account Achievements
    + + + + +
    +
    +
    +
    +
    + + + + + + +
    + +
    +

    {% if deaths|length > 0 %} - -
    -
    -
    - - - - -
    Character Deaths
    - - - - -
    -
    -
    -
    - - - - -
    - -
    -
    - + +
    +
    +
    + + + + +
    Character Deaths
    + + + + +
    +
    +
    +
    +
    + + + + + + +
    + +
    +
    +
    + {% endif %} {% if frags|length > 0 %} - -
    -
    -
    - - - - -
    Character Frags
    - - - - -
    -
    -
    -
    - - - - -
    - -
    -
    - + +
    +
    +
    + + + + +
    Character Frags
    + + + + +
    +
    +
    +
    +
    + + + + + + +
    + +
    +
    +
    + {% endif %} {{ hook(constant('HOOK_CHARACTERS_BEFORE_SIGNATURE')) }} {% if config.signature_enabled %} - -
    -
    -
    - - - - -
    Character Signature
    - - - - -
    -
    -
    -
    - - - - -
    - -
    -
    - + +
    +
    +
    + + + + +
    Character Signature
    + + + + +
    +
    +
    +
    +
    + + + + + + +
    + +
    +
    +
    + {% endif %} {{ hook(constant('HOOK_CHARACTERS_AFTER_SIGNATURE')) }} - - ',d=0;d",c=0;c
    '+j+"
    "}else b+="
    "}return b+="
    - {% if not hidden %} - {% set rows = 0 %} -
    -
    -
    - - - - -
    Characters
    - - - - -
    - - - - + {% if canEdit %} +
    + + {% set button_name = 'Edit Character' %} + {% include('buttons.base.html.twig') %} + + {% endif %} + +
    -
    - + + +
    -
    - - - - - - - - - - {% set i = 0 %} - {% for player in account_players %} - {% if not player.isHidden() and (config('characters')['deleted'] or not player.isDeleted()) %} - {% set i = i + 1 %} - - - - - - + + +
    NameLevelVocationStatus 
    - {{ i }}. {{ player.getName() }}{% if player.isDeleted() %} [DELETED]{% endif %} - {{ player.getLevel() }}{{ player.getVocationName() }}{% if player.isOnline() %}{% else %}{% endif %} - - - - + + {% endif %} + {% endfor %} + +
    - - -
    -
    -
    -
    + + + + + +
    + {% if not hidden %} + {% set rows = 0 %} +
    +
    +
    + + + + +
    Characters
    + + + + +
    +
    + + + + - -
    +
    + + + + -
    +
    + + + + + + + + + + {% set i = 0 %} + {% for player in account_players %} + {% if not player.isHidden() and (config('characters')['deleted'] or not player.isDeleted()) %} + {% set i = i + 1 %} + + + + + + - - {% endif %} - {% endfor %} -
    NameLevelVocationStatus 
    + {{ i }}. {{ player.getName() }}{% if player.isDeleted() %} [DELETED]{% endif %} + {{ player.getLevel() }}{{ player.getVocationName() }}{% if player.isOnline() %}{% else %}{% endif %} + + + + - - -
    + + {% set button_name = "View" %} + {% set button_title = player.getName() %} + {{ include('buttons.base.html.twig') }} -{% if canEdit %} - -
    -
    -
    -
    -
    -{% endif %} -
    -
    -
    -
    -
    -{% endif %} + {% if canEdit %} + +
    +
    + +
    +
    +
    + {% endif %} +
    +
    + +
    +
    +
    +
    + {% endif %} -{{ hook(constant('HOOK_CHARACTERS_AFTER_CHARACTERS')) }} + {{ hook(constant('HOOK_CHARACTERS_AFTER_CHARACTERS')) }} -{% if canEdit %} -
    - - {% set button_name = 'Edit Character' %} - {% include('buttons.base.html.twig') %} - -{% endif %} -

    {{ search_form|raw }} diff --git a/system/templates/exception.html.twig b/system/templates/exception.html.twig index 3731f8d101..6d4bf45e81 100644 --- a/system/templates/exception.html.twig +++ b/system/templates/exception.html.twig @@ -8,8 +8,8 @@ - - + + @@ -76,4 +76,4 @@

    {{ powered_by }}

    - \ No newline at end of file + diff --git a/system/templates/install.config.html.twig b/system/templates/install.config.html.twig index 42b21ff3b8..d29f905f26 100644 --- a/system/templates/install.config.html.twig +++ b/system/templates/install.config.html.twig @@ -1,63 +1,67 @@
    - - - {% for value in ['server_path', 'mail_admin', 'mail_address'] %} - - - - {% endfor %} - - - - - - - - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - - -
    + + + {% for value in ['server_path', 'mail_admin', 'mail_address'] %} + + + + {% endfor %} + + + + + + + + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + + +
    - {% if errors is defined %} - {% for error in errors %} -

    {{ error }}

    - {% endfor %} - {% endif %} - {{ buttons|raw }} -
    \ No newline at end of file + {% if errors is defined %} + {% for error in errors %} +

    {{ error }}

    + {% endfor %} + {% endif %} + {{ buttons|raw }} + diff --git a/system/templates/install.installer.html.twig b/system/templates/install.installer.html.twig index d069403463..f70a2e496a 100644 --- a/system/templates/install.installer.html.twig +++ b/system/templates/install.installer.html.twig @@ -1,11 +1,11 @@
    - - {{ message }} + + {{ message }}
    - + \ No newline at end of file + $(function () { + performInstall('{{ url }}'); + }); + diff --git a/system/templates/news.archive.html.twig b/system/templates/news.archive.html.twig index 40a3afb707..652b96a3d4 100644 --- a/system/templates/news.archive.html.twig +++ b/system/templates/news.archive.html.twig @@ -1,46 +1,62 @@
    -
    -
    - - - - -
    News archive
    - - - - -
    - - - - -
    -
    - -
    -
    - - - - -{% set i = 0 %} - {% for news in newses %} - {% set i = i + 1 %} - - - - - - {% endfor %} - -
    -
    - -
    -
    {{ news.date|date('j.n.Y') }} - {{ news.title }} -
    -
    +
    +
    + + + + +
    News archive
    + + + + +
    +
    + + + + + + +
    +
    + + + + + + +
    +
    + + + {% set i = 0 %} + {% for news in newses %} + {% set i = i + 1 %} + + + + + + {% endfor %} + +
    +
    + +
    +
    {{ news.date|date('j.n.Y') }} + {{ news.title }} +
    +
    +
    +
    +
    -
    \ No newline at end of file diff --git a/system/templates/news.back_button.html.twig b/system/templates/news.back_button.html.twig index 7bb86712f4..2d8e5cd706 100644 --- a/system/templates/news.back_button.html.twig +++ b/system/templates/news.back_button.html.twig @@ -1,13 +1,14 @@
    - - - - - - - - -
    - -
    -
    \ No newline at end of file + + + + + + + + +
    + {% set button_name = 'Back' %} + {{ include('buttons.base.html.twig') }} +
    + diff --git a/system/twig.php b/system/twig.php index 19011de70e..ee73f14fa1 100644 --- a/system/twig.php +++ b/system/twig.php @@ -16,6 +16,9 @@ $twig_loader->addPath(PLUGINS); +$twig->addGlobal('logged', false); +$twig->addGlobal('account_logged', new OTS_Account()); + if($dev_mode) { $twig->addExtension(new Twig_DebugExtension()); } diff --git a/templates/tibiacom/buttons.base.html.twig b/templates/tibiacom/buttons.base.html.twig index c339b4a482..61ba6cf85a 100644 --- a/templates/tibiacom/buttons.base.html.twig +++ b/templates/tibiacom/buttons.base.html.twig @@ -1,6 +1,9 @@ {% spaceless %} -
    -
    -
    -
    -{% endspaceless %} \ No newline at end of file +
    +
    + + +
    +
    +{% endspaceless %} diff --git a/templates/tibiacom/tables.headline.html.twig b/templates/tibiacom/tables.headline.html.twig new file mode 100644 index 0000000000..5e13c8827d --- /dev/null +++ b/templates/tibiacom/tables.headline.html.twig @@ -0,0 +1,32 @@ +
    +
    +
    + + + + +
    {{ title|raw }}
    + + + + +
    +
    + + + + +
    +
    + {{ content|raw }} +
    +
    +
    diff --git a/tools/tinymce/jquery.tinymce.min.js b/tools/tinymce/jquery.tinymce.min.js index 1088223850..4a69c27b34 100644 --- a/tools/tinymce/jquery.tinymce.min.js +++ b/tools/tinymce/jquery.tinymce.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i0&&(c=j().get(d[0].id)))return c.getContent()},c=function(a){var b=null;return a&&a.id&&h.tinymce&&(b=j().get(a.id)),b},e=function(a){return!!(a&&a.length&&h.tinymce&&a.is(":tinymce"))},f={};g.each(["text","html","val"],function(a,h){var i=f[h]=g.fn[h],j="text"===h;g.fn[h]=function(a){var f=this;if(!e(f))return i.apply(f,arguments);if(a!==d)return b.call(f.filter(":tinymce"),a),i.apply(f.not(":tinymce"),arguments),f;var h="",k=arguments;return(j?f:f.eq(0)).each(function(a,b){var d=c(b);h+=d?j?d.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):d.getContent({save:!0}):i.apply(g(b),k)}),h}}),g.each(["append","prepend"],function(a,b){var h=f[b]=g.fn[b],i="prepend"===b;g.fn[b]=function(a){var b=this;return e(b)?a!==d?("string"==typeof a&&b.filter(":tinymce").each(function(b,d){var e=c(d);e&&e.setContent(i?a+e.getContent():e.getContent()+a)}),h.apply(b.not(":tinymce"),arguments),b):void 0:h.apply(b,arguments)}}),g.each(["remove","replaceWith","replaceAll","empty"],function(b,c){var d=f[c]=g.fn[c];g.fn[c]=function(){return a.call(this,c),d.apply(this,arguments)}}),f.attr=g.fn.attr,g.fn.attr=function(a,h){var i=this,j=arguments;if(!a||"value"!==a||!e(i))return h!==d?f.attr.apply(i,j):f.attr.apply(i,j);if(h!==d)return b.call(i.filter(":tinymce"),h),f.attr.apply(i.not(":tinymce"),j),i;var k=i[0],l=c(k);return l?l.getContent({save:!0}):f.attr.apply(g(k),j)}}}}),d("0")()}(); \ No newline at end of file +!function(){var f,c,u,p,d,s=[];d="undefined"!=typeof global?global:window,p=d.jQuery;var v=function(){return d.tinymce};p.fn.tinymce=function(o){var e,t,i,l=this,r="";if(!l.length)return l;if(!o)return v()?v().get(l[0].id):null;l.css("visibility","hidden");var n=function(){var a=[],c=0;u||(m(),u=!0),l.each(function(e,t){var n,i=t.id,r=o.oninit;i||(t.id=i=v().DOM.uniqueId()),v().get(i)||(n=v().createEditor(i,o),a.push(n),n.on("init",function(){var e,t=r;l.css("visibility",""),r&&++c==a.length&&("string"==typeof t&&(e=-1===t.indexOf(".")?null:v().resolve(t.replace(/\.\w+$/,"")),t=v().resolve(t)),t.apply(e||v(),a))}))}),p.each(a,function(e,t){t.render()})};if(d.tinymce||c||!(e=o.script_url))1===c?s.push(n):n();else{c=1,t=e.substring(0,e.lastIndexOf("/")),-1!=e.indexOf(".min")&&(r=".min"),d.tinymce=d.tinyMCEPreInit||{base:t,suffix:r},-1!=e.indexOf("gzip")&&(i=o.language||"en",e=e+(/\?/.test(e)?"&":"?")+"js=true&core=true&suffix="+escape(r)+"&themes="+escape(o.theme||"modern")+"&plugins="+escape(o.plugins||"")+"&languages="+(i||""),d.tinyMCE_GZ||(d.tinyMCE_GZ={start:function(){var n=function(e){v().ScriptLoader.markDone(v().baseURI.toAbsolute(e))};n("langs/"+i+".js"),n("themes/"+o.theme+"/theme"+r+".js"),n("themes/"+o.theme+"/langs/"+i+".js"),p.each(o.plugins.split(","),function(e,t){t&&(n("plugins/"+t+"/plugin"+r+".js"),n("plugins/"+t+"/langs/"+i+".js"))})},end:function(){}}));var a=document.createElement("script");a.type="text/javascript",a.onload=a.onreadystatechange=function(e){e=e||window.event,2===c||"load"!=e.type&&!/complete|loaded/.test(a.readyState)||(v().dom.Event.domLoaded=1,c=2,o.script_loaded&&o.script_loaded(),n(),p.each(s,function(e,t){t()}))},a.src=e,document.body.appendChild(a)}return l},p.extend(p.expr[":"],{tinymce:function(e){var t;return!!(e.id&&"tinymce"in d&&(t=v().get(e.id))&&t.editorManager===v())}});var m=function(){var r=function(e){"remove"===e&&this.each(function(e,t){var n=l(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=v().get(t.id.replace(/_parent$/,""));n&&n.remove()})},o=function(i){var e,t=this;if(null!=i)r.call(t),t.each(function(e,t){var n;(n=v().get(t.id))&&n.setContent(i)});else if(0])*>/g,""):n.getContent({save:!0}):a.apply(p(t),r)}),i}}),p.each(["append","prepend"],function(e,t){var n=s[t]=p.fn[t],r="prepend"===t;p.fn[t]=function(i){var e=this;return u(e)?i!==f?("string"==typeof i&&e.filter(":tinymce").each(function(e,t){var n=l(t);n&&n.setContent(r?i+n.getContent():n.getContent()+i)}),n.apply(e.not(":tinymce"),arguments),e):void 0:n.apply(e,arguments)}}),p.each(["remove","replaceWith","replaceAll","empty"],function(e,t){var n=s[t]=p.fn[t];p.fn[t]=function(){return r.call(this,t),n.apply(this,arguments)}}),s.attr=p.fn.attr,p.fn.attr=function(e,t){var n=this,i=arguments;if(!e||"value"!==e||!u(n))return s.attr.apply(n,i);if(t!==f)return o.call(n.filter(":tinymce"),t),s.attr.apply(n.not(":tinymce"),i),n;var r=n[0],a=l(r);return a?a.getContent({save:!0}):s.attr.apply(p(r),i)}}}(); \ No newline at end of file diff --git a/tools/tinymce/plugins/advlist/plugin.min.js b/tools/tinymce/plugins/advlist/plugin.min.js index 2105a2bc5e..122cd8ff64 100644 --- a/tools/tinymce/plugins/advlist/plugin.min.js +++ b/tools/tinymce/plugins/advlist/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i0&&j[0].nodeName===c)})}},h=function(a){return function(b){var c=d.getSelectedStyleType(a);b.control.items().each(function(a){a.active(a.settings.data===c)})}},i=function(a,b,d,f,i,j){a.addButton(b,{active:!1,type:"splitbutton",tooltip:d,menu:e.toMenuItems(j),onPostRender:g(a,i),onshow:h(a),onselect:function(b){c.applyListFormat(a,i,b.control.settings.data)},onclick:function(){a.execCommand(f)}})},j=function(a,b,c,d,e,f){a.addButton(b,{active:!1,type:"button",tooltip:c,onPostRender:g(a,e),onclick:function(){a.execCommand(d)}})},k=function(a,b,c,d,e,f){f.length>0?i(a,b,c,d,e,f):j(a,b,c,d,e,f)},l=function(a){k(a,"numlist","Numbered list","InsertOrderedList","OL",b.getNumberStyles(a)),k(a,"bullist","Bullet list","InsertUnorderedList","UL",b.getBulletStyles(a))};return{register:l}}),g("0",["1","2","3","4"],function(a,b,c,d){return a.add("advlist",function(a){var e=function(a,c){var d=a.settings.plugins?a.settings.plugins:"";return b.inArray(d.split(/[ ,]/),c)!==-1};e(a,"lists")&&(d.register(a),c.register(a))}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.util.Tools"),s=function(t,e,n){var r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===n?null:{"list-style-type":n})},o=function(n){n.addCommand("ApplyUnorderedListStyle",function(t,e){s(n,"UL",e["list-style-type"])}),n.addCommand("ApplyOrderedListStyle",function(t,e){s(n,"OL",e["list-style-type"])})},e=function(t){var e=t.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman");return e?e.split(/[ ,]/):[]},n=function(t){var e=t.getParam("advlist_bullet_styles","default,circle,disc,square");return e?e.split(/[ ,]/):[]},u=function(t){return t&&/^(TH|TD)$/.test(t.nodeName)},c=function(r){return function(t){return t&&/^(OL|UL|DL)$/.test(t.nodeName)&&(n=t,(e=r).$.contains(e.getBody(),n));var e,n}},d=function(t){var e=t.dom.getParent(t.selection.getNode(),"ol,ul");return t.dom.getStyle(e,"listStyleType")||""},p=function(t){return a.map(t,function(t){return{text:t.replace(/\-/g," ").replace(/\b\w/g,function(t){return t.toUpperCase()}),data:"default"===t?"":t}})},f=function(i,l){return function(t){var o=t.control;i.on("NodeChange",function(t){var e=function(t,e){for(var n=0;nc&&(b=c)}return b},i=function(a,b,c){1!==b.nodeType||b.hasChildNodes()?a.setStart(b,h(b,c)):a.setStartBefore(b)},j=function(a,b,c){1!==b.nodeType||b.hasChildNodes()?a.setEnd(b,h(b,c)):a.setEndAfter(b)},k=function(a,b,e){var f,g,h,k,l,m,n,o,p,q,r=c.getAutoLinkPattern(a),s=c.getDefaultLinkTarget(a);if("A"!==a.selection.getNode().tagName){if(f=a.selection.getRng(!0).cloneRange(),f.startOffset<5){if(o=f.endContainer.previousSibling,!o){if(!f.endContainer.firstChild||!f.endContainer.firstChild.nextSibling)return;o=f.endContainer.firstChild.nextSibling}if(p=o.length,i(f,o,p),j(f,o,p),f.endOffset<5)return;g=f.endOffset,k=o}else{if(k=f.endContainer,3!==k.nodeType&&k.firstChild){for(;3!==k.nodeType&&k.firstChild;)k=k.firstChild;3===k.nodeType&&(i(f,k,0),j(f,k,k.nodeValue.length))}g=1===f.endOffset?2:f.endOffset-1-b}h=g;do i(f,k,g>=2?g-2:0),j(f,k,g>=1?g-1:0),g-=1,q=f.toString();while(" "!==q&&""!==q&&160!==q.charCodeAt(0)&&g-2>=0&&q!==e);d(f.toString(),e)?(i(f,k,g),j(f,k,h),g+=1):0===f.startOffset?(i(f,k,0),j(f,k,h)):(i(f,k,g),j(f,k,h)),m=f.toString(),"."===m.charAt(m.length-1)&&j(f,k,h-1),m=f.toString().trim(),n=m.match(r),n&&("www."===n[1]?n[1]="http://www.":/@$/.test(n[1])&&!/^mailto:/.test(n[1])&&(n[1]="mailto:"+n[1]),l=a.selection.getBookmark(),a.selection.setRng(f),a.execCommand("createlink",!1,n[1]+n[2]),s&&a.dom.setAttrib(a.selection.getNode(),"target",s),a.selection.moveToBookmark(l),a.nodeChanged())}},l=function(b){var c;return b.on("keydown",function(a){if(13===a.keyCode)return g(b)}),a.ie?void b.on("focus",function(){if(!c){c=!0;try{b.execCommand("AutoUrlDetect",!1,!0)}catch(a){}}}):(b.on("keypress",function(a){if(41===a.keyCode)return e(b)}),void b.on("keyup",function(a){if(32===a.keyCode)return f(b)}))};return{setup:l}}),g("0",["1","2","3"],function(a,b,c){return b.add("autolink",function(a){c.setup(a)}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=tinymce.util.Tools.resolve("tinymce.Env"),m=function(e){return e.getParam("autolink_pattern",/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i)},y=function(e){return e.getParam("default_link_target","")},o=function(e,t){if(t<0&&(t=0),3===e.nodeType){var n=e.data.length;nc.getAutoResizeMinHeight(b)&&(k=l);var t=c.getAutoResizeMaxHeight(b);t&&l>t?(k=t,f(b,!0)):f(b,!1),k!==e.get()&&(h=k-e.get(),s.setStyle(b.iframeElement,"height",k+"px"),e.set(k),a.webKit&&h<0&&g(b))}},h=function(a,b){a.on("init",function(){var b,d,e=a.dom;b=c.getAutoResizeOverflowPadding(a),d=c.getAutoResizeBottomMargin(a),b!==!1&&e.setStyles(a.getBody(),{paddingLeft:b,paddingRight:b}),d!==!1&&e.setStyles(a.getBody(),{paddingBottom:d})}),a.on("nodechange setcontent keyup FullscreenStateChanged",function(c){g(a,b)}),c.shouldAutoResizeOnInit(a)&&a.on("init",function(){e(a,b,20,100,function(){e(a,b,5,1e3)})})};return{setup:h,resize:g}}),g("3",["4"],function(a){var b=function(b,c){b.addCommand("mceAutoResize",function(){a.resize(b,c)})};return{register:b}}),g("0",["1","2","3","4"],function(a,b,c,d){return b.add("autoresize",function(b){if(!b.inline){var e=a(0);c.register(b,e),d.setup(b,e)}}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var i=function(t){var e=t,n=function(){return e};return{get:n,set:function(t){e=t},clone:function(){return i(n())}}},t=tinymce.util.Tools.resolve("tinymce.PluginManager"),y=tinymce.util.Tools.resolve("tinymce.Env"),r=tinymce.util.Tools.resolve("tinymce.util.Delay"),h=function(t){return parseInt(t.getParam("autoresize_min_height",t.getElement().offsetHeight),10)},v=function(t){return parseInt(t.getParam("autoresize_max_height",0),10)},o=function(t){return t.getParam("autoresize_overflow_padding",1)},a=function(t){return t.getParam("autoresize_bottom_margin",50)},n=function(t){return t.getParam("autoresize_on_init",!0)},u=function(t,e,n,i,o){r.setEditorTimeout(t,function(){_(t,e),n--?u(t,e,n,i,o):o&&o()},i)},S=function(t,e){var n=t.getBody();n&&(n.style.overflowY=e?"":"hidden",e||(n.scrollTop=0))},_=function(t,e){var n,i,o,r,a,u,s,l,g,c,f,d=t.dom;if(i=t.getDoc())if((m=t).plugins.fullscreen&&m.plugins.fullscreen.isFullscreen())S(t,!0);else{var m;o=i.body,r=h(t),u=d.getStyle(o,"margin-top",!0),s=d.getStyle(o,"margin-bottom",!0),l=d.getStyle(o,"padding-top",!0),g=d.getStyle(o,"padding-bottom",!0),c=d.getStyle(o,"border-top-width",!0),f=d.getStyle(o,"border-bottom-width",!0),a=o.offsetHeight+parseInt(u,10)+parseInt(s,10)+parseInt(l,10)+parseInt(g,10)+parseInt(c,10)+parseInt(f,10),(isNaN(a)||a<=0)&&(a=y.ie?o.scrollHeight:y.webkit&&0===o.clientHeight?0:o.offsetHeight),a>h(t)&&(r=a);var p=v(t);p&&p]*>((\xa0| |[ \t]|]*>)+?|)|
    $","i").test(b)},g=function(a){var c=parseInt(b.getItem(e.getAutoSavePrefix(a)+"time"),10)||0;return!((new Date).getTime()-c>e.getAutoSaveRetention(a))||(h(a,!1),!1)},h=function(a,c){var f=e.getAutoSavePrefix(a);b.removeItem(f+"draft"),b.removeItem(f+"time"),c!==!1&&d.fireRemoveDraft(a)},i=function(a){var c=e.getAutoSavePrefix(a);!f(a)&&a.isDirty()&&(b.setItem(c+"draft",a.getContent({format:"raw",no_events:!0})),b.setItem(c+"time",(new Date).getTime()),d.fireStoreDraft(a))},j=function(a){var c=e.getAutoSavePrefix(a);g(a)&&(a.setContent(b.getItem(c+"draft"),{format:"raw"}),d.fireRestoreDraft(a))},k=function(b,c){var d=e.getAutoSaveInterval(b);c.get()||(a(function(){b.removed||i(b)},d),c.set(!0))},l=function(a){a.undoManager.transact(function(){j(a),h(a)}),a.focus()};return{isEmpty:f,hasDraft:g,removeDraft:h,storeDraft:i,restoreDraft:j,startStoreDraft:k,restoreLastDraft:l}}),g("3",["7"],function(a){var b=function(a,b){return function(){var c=Array.prototype.slice.call(arguments);return a.apply(null,[b].concat(c))}},c=function(c){return{hasDraft:b(a.hasDraft,c),storeDraft:b(a.storeDraft,c),restoreDraft:b(a.restoreDraft,c),removeDraft:b(a.removeDraft,c),isEmpty:b(a.isEmpty,c)}};return{get:c}}),h("8",window),g("9",["6"],function(a){return a("tinymce.EditorManager")}),g("4",["8","9","a","b"],function(a,b,c,d){b._beforeUnloadHandler=function(){var a;return c.each(b.get(),function(b){b.plugins.autosave&&b.plugins.autosave.storeDraft(),!a&&b.isDirty()&&d.shouldAskBeforeUnload(b)&&(a=b.translate("You have unsaved changes are you sure you want to navigate away?"))}),a};var e=function(c){a.onbeforeunload=b._beforeUnloadHandler};return{setup:e}}),g("5",["7"],function(a){var b=function(b,c){return function(d){var e=d.control;e.disabled(!a.hasDraft(b)),b.on("StoreDraft RestoreDraft RemoveDraft",function(){e.disabled(!a.hasDraft(b))}),a.startStoreDraft(b,c)}},c=function(c,d){c.addButton("restoredraft",{title:"Restore last draft",onclick:function(){a.restoreLastDraft(c)},onPostRender:b(c,d)}),c.addMenuItem("restoredraft",{text:"Restore last draft",onclick:function(){a.restoreLastDraft(c)},onPostRender:b(c,d),context:"file"})};return{register:c}}),g("0",["1","2","3","4","5"],function(a,b,c,d,e){return b.add("autosave",function(b){var f=a(!1);return d.setup(b),e.register(b,f),c.get(b)}),function(){}}),d("0")()}(); \ No newline at end of file +!function(a){"use strict";var i=function(t){var e=t,n=function(){return e};return{get:n,set:function(t){e=t},clone:function(){return i(n())}}},t=tinymce.util.Tools.resolve("tinymce.PluginManager"),r=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),o=tinymce.util.Tools.resolve("tinymce.util.Tools"),u=function(t,e){var n=t||e,r=/^(\d+)([ms]?)$/.exec(""+n);return(r[2]?{s:1e3,m:6e4}[r[2]]:1)*parseInt(n,10)},s=function(t){var e=t.getParam("autosave_prefix","tinymce-autosave-{path}{query}{hash}-{id}-");return e=(e=(e=(e=e.replace(/\{path\}/g,a.document.location.pathname)).replace(/\{query\}/g,a.document.location.search)).replace(/\{hash\}/g,a.document.location.hash)).replace(/\{id\}/g,t.id)},c=function(t,e){var n=t.settings.forced_root_block;return""===(e=o.trim(void 0===e?t.getBody().innerHTML:e))||new RegExp("^<"+n+"[^>]*>((\xa0| |[ \t]|]*>)+?|)|
    $","i").test(e)},f=function(t){var e=parseInt(r.getItem(s(t)+"time"),10)||0;return!((new Date).getTime()-e>u(t.settings.autosave_retention,"20m")&&(l(t,!1),1))},l=function(t,e){var n=s(t);r.removeItem(n+"draft"),r.removeItem(n+"time"),!1!==e&&t.fire("RemoveDraft")},m=function(t){var e=s(t);!c(t)&&t.isDirty()&&(r.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),r.setItem(e+"time",(new Date).getTime().toString()),t.fire("StoreDraft"))},v=function(t){var e=s(t);f(t)&&(t.setContent(r.getItem(e+"draft"),{format:"raw"}),t.fire("RestoreDraft"))},d=function(t,e){var n=u(t.settings.autosave_interval,"30s");e.get()||(setInterval(function(){t.removed||m(t)},n),e.set(!0))},g=function(t){t.undoManager.transact(function(){v(t),l(t)}),t.focus()};function y(r){for(var o=[],t=1;t(.*?)<\/a>/gi,"[url=$1]$2[/url]"),c(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),c(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),c(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),c(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),c(/(.*?)<\/span>/gi,"[color=$1]$2[/color]"),c(/(.*?)<\/font>/gi,"[color=$1]$2[/color]"),c(/(.*?)<\/span>/gi,"[size=$1]$2[/size]"),c(/(.*?)<\/font>/gi,"$1"),c(//gi,"[img]$1[/img]"),c(/(.*?)<\/span>/gi,"[code]$1[/code]"),c(/(.*?)<\/span>/gi,"[quote]$1[/quote]"),c(/(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"),c(/(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"),c(/(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"),c(/(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"),c(/(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"),c(/(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"),c(/<\/(strong|b)>/gi,"[/b]"),c(/<(strong|b)>/gi,"[b]"),c(/<\/(em|i)>/gi,"[/i]"),c(/<(em|i)>/gi,"[i]"),c(/<\/u>/gi,"[/u]"),c(/(.*?)<\/span>/gi,"[u]$1[/u]"),c(//gi,"[u]"),c(/]*>/gi,"[quote]"),c(/<\/blockquote>/gi,"[/quote]"),c(/
    /gi,"\n"),c(//gi,"\n"),c(/
    /gi,"\n"),c(/

    /gi,""),c(/<\/p>/gi,"\n"),c(/ |\u00a0/gi," "),c(/"/gi,'"'),c(/</gi,"<"),c(/>/gi,">"),c(/&/gi,"&"),b},c=function(b){b=a.trim(b);var c=function(a,c){b=b.replace(a,c)};return c(/\n/gi,"
    "),c(/\[b\]/gi,""),c(/\[\/b\]/gi,""),c(/\[i\]/gi,""),c(/\[\/i\]/gi,""),c(/\[u\]/gi,""),c(/\[\/u\]/gi,""),c(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'$2'),c(/\[url\](.*?)\[\/url\]/gi,'$1'),c(/\[img\](.*?)\[\/img\]/gi,''),c(/\[color=(.*?)\](.*?)\[\/color\]/gi,'$2'),c(/\[code\](.*?)\[\/code\]/gi,'$1 '),c(/\[quote.*?\](.*?)\[\/quote\]/gi,'$1 '),b};return{html2bbcode:b,bbcode2html:c}}),g("0",["1","2"],function(a,b){return a.add("bbcode",function(){return{init:function(a){a.on("beforeSetContent",function(a){a.content=b.bbcode2html(a.content)}),a.on("postProcess",function(a){a.set&&(a.content=b.bbcode2html(a.content)),a.get&&(a.content=b.html2bbcode(a.content))})}}}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var o=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.util.Tools"),e=function(e){e=t.trim(e);var o=function(o,t){e=e.replace(o,t)};return o(/(.*?)<\/a>/gi,"[url=$1]$2[/url]"),o(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),o(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),o(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),o(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),o(/(.*?)<\/span>/gi,"[color=$1]$2[/color]"),o(/(.*?)<\/font>/gi,"[color=$1]$2[/color]"),o(/(.*?)<\/span>/gi,"[size=$1]$2[/size]"),o(/(.*?)<\/font>/gi,"$1"),o(//gi,"[img]$1[/img]"),o(/(.*?)<\/span>/gi,"[code]$1[/code]"),o(/(.*?)<\/span>/gi,"[quote]$1[/quote]"),o(/(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"),o(/(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"),o(/(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"),o(/(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"),o(/(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"),o(/(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"),o(/<\/(strong|b)>/gi,"[/b]"),o(/<(strong|b)>/gi,"[b]"),o(/<\/(em|i)>/gi,"[/i]"),o(/<(em|i)>/gi,"[i]"),o(/<\/u>/gi,"[/u]"),o(/(.*?)<\/span>/gi,"[u]$1[/u]"),o(//gi,"[u]"),o(/]*>/gi,"[quote]"),o(/<\/blockquote>/gi,"[/quote]"),o(/
    /gi,"\n"),o(//gi,"\n"),o(/
    /gi,"\n"),o(/

    /gi,""),o(/<\/p>/gi,"\n"),o(/ |\u00a0/gi," "),o(/"/gi,'"'),o(/</gi,"<"),o(/>/gi,">"),o(/&/gi,"&"),e},i=function(e){e=t.trim(e);var o=function(o,t){e=e.replace(o,t)};return o(/\n/gi,"
    "),o(/\[b\]/gi,""),o(/\[\/b\]/gi,""),o(/\[i\]/gi,""),o(/\[\/i\]/gi,""),o(/\[u\]/gi,""),o(/\[\/u\]/gi,""),o(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'$2'),o(/\[url\](.*?)\[\/url\]/gi,'$1'),o(/\[img\](.*?)\[\/img\]/gi,''),o(/\[color=(.*?)\](.*?)\[\/color\]/gi,'$2'),o(/\[code\](.*?)\[\/code\]/gi,'$1 '),o(/\[quote.*?\](.*?)\[\/quote\]/gi,'$1 '),e};o.add("bbcode",function(){return{init:function(o){o.on("beforeSetContent",function(o){o.content=i(o.content)}),o.on("postProcess",function(o){o.set&&(o.content=i(o.content)),o.get&&(o.content=e(o.content))})}}})}(); \ No newline at end of file diff --git a/tools/tinymce/plugins/charmap/plugin.min.js b/tools/tinymce/plugins/charmap/plugin.min.js index 62ff39a21d..9ea3f75751 100644 --- a/tools/tinymce/plugins/charmap/plugin.min.js +++ b/tools/tinymce/plugins/charmap/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i

    "}b+="
    "};return{getHtml:a}}),g("8",["6","7","c"],function(a,b,c){var d=function(a){for(;a;){if("TD"===a.nodeName)return a;a=a.parentNode}},e=function(e){var f,g={type:"container",html:c.getHtml(b.getCharMap(e)),onclick:function(b){var c=b.target;if(/^(TD|DIV)$/.test(c.nodeName)){var g=d(c).firstChild;if(g&&g.hasAttribute("data-chr")){var h=g.getAttribute("data-chr"),i=parseInt(h,10);isNaN(i)||a.insertChar(e,String.fromCharCode(i)),b.ctrlKey||f.close()}}},onmouseover:function(a){var b=d(a.target);b&&b.firstChild?(f.find("#preview").text(b.firstChild.firstChild.data),f.find("#previewTitle").text(b.title)):(f.find("#preview").text(" "),f.find("#previewTitle").text(" "))}};f=e.windowManager.open({title:"Special character",spacing:10,padding:10,items:[g,{type:"container",layout:"flex",direction:"column",align:"center",spacing:5,minWidth:160,minHeight:160,items:[{type:"label",name:"preview",text:" ",style:"font-size: 40px; text-align: center",border:1,minWidth:140,minHeight:80},{type:"spacer",minHeight:20},{type:"label",name:"previewTitle",text:" ",style:"white-space: pre-wrap;",border:1,minWidth:140}]}],buttons:[{text:"Close",onclick:function(){f.close()}}]})};return{open:e}}),g("3",["8"],function(a){var b=function(b){b.addCommand("mceShowCharmap",function(){a.open(b)})};return{register:b}}),g("4",[],function(){var a=function(a){a.addButton("charmap",{icon:"charmap",tooltip:"Special character",cmd:"mceShowCharmap"}),a.addMenuItem("charmap",{icon:"charmap",text:"Special character",cmd:"mceShowCharmap",context:"insert"})};return{register:a}}),g("0",["1","2","3","4"],function(a,b,c,d){return a.add("charmap",function(a){return c.register(a),d.register(a),b.get(a)}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=function(e,t){return e.fire("insertCustomChar",{chr:t})},l=function(e,t){var a=i(e,t).chr;e.execCommand("mceInsertContent",!1,a)},a=tinymce.util.Tools.resolve("tinymce.util.Tools"),r=function(e){return e.settings.charmap},n=function(e){return e.settings.charmap_append},o=a.isArray,c=function(e){return o(e)?[].concat((t=e,a.grep(t,function(e){return o(e)&&2===e.length}))):"function"==typeof e?e():[];var t},s=function(e){return function(e,t){var a=r(e);a&&(t=c(a));var i=n(e);return i?[].concat(t).concat(c(i)):t}(e,[["160","no-break space"],["173","soft hyphen"],["34","quotation mark"],["162","cent sign"],["8364","euro sign"],["163","pound sign"],["165","yen sign"],["169","copyright sign"],["174","registered sign"],["8482","trade mark sign"],["8240","per mille sign"],["181","micro sign"],["183","middle dot"],["8226","bullet"],["8230","three dot leader"],["8242","minutes / feet"],["8243","seconds / inches"],["167","section sign"],["182","paragraph sign"],["223","sharp s / ess-zed"],["8249","single left-pointing angle quotation mark"],["8250","single right-pointing angle quotation mark"],["171","left pointing guillemet"],["187","right pointing guillemet"],["8216","left single quotation mark"],["8217","right single quotation mark"],["8220","left double quotation mark"],["8221","right double quotation mark"],["8218","single low-9 quotation mark"],["8222","double low-9 quotation mark"],["60","less-than sign"],["62","greater-than sign"],["8804","less-than or equal to"],["8805","greater-than or equal to"],["8211","en dash"],["8212","em dash"],["175","macron"],["8254","overline"],["164","currency sign"],["166","broken bar"],["168","diaeresis"],["161","inverted exclamation mark"],["191","turned question mark"],["710","circumflex accent"],["732","small tilde"],["176","degree sign"],["8722","minus sign"],["177","plus-minus sign"],["247","division sign"],["8260","fraction slash"],["215","multiplication sign"],["185","superscript one"],["178","superscript two"],["179","superscript three"],["188","fraction one quarter"],["189","fraction one half"],["190","fraction three quarters"],["402","function / florin"],["8747","integral"],["8721","n-ary sumation"],["8734","infinity"],["8730","square root"],["8764","similar to"],["8773","approximately equal to"],["8776","almost equal to"],["8800","not equal to"],["8801","identical to"],["8712","element of"],["8713","not an element of"],["8715","contains as member"],["8719","n-ary product"],["8743","logical and"],["8744","logical or"],["172","not sign"],["8745","intersection"],["8746","union"],["8706","partial differential"],["8704","for all"],["8707","there exists"],["8709","diameter"],["8711","backward difference"],["8727","asterisk operator"],["8733","proportional to"],["8736","angle"],["180","acute accent"],["184","cedilla"],["170","feminine ordinal indicator"],["186","masculine ordinal indicator"],["8224","dagger"],["8225","double dagger"],["192","A - grave"],["193","A - acute"],["194","A - circumflex"],["195","A - tilde"],["196","A - diaeresis"],["197","A - ring above"],["256","A - macron"],["198","ligature AE"],["199","C - cedilla"],["200","E - grave"],["201","E - acute"],["202","E - circumflex"],["203","E - diaeresis"],["274","E - macron"],["204","I - grave"],["205","I - acute"],["206","I - circumflex"],["207","I - diaeresis"],["298","I - macron"],["208","ETH"],["209","N - tilde"],["210","O - grave"],["211","O - acute"],["212","O - circumflex"],["213","O - tilde"],["214","O - diaeresis"],["216","O - slash"],["332","O - macron"],["338","ligature OE"],["352","S - caron"],["217","U - grave"],["218","U - acute"],["219","U - circumflex"],["220","U - diaeresis"],["362","U - macron"],["221","Y - acute"],["376","Y - diaeresis"],["562","Y - macron"],["222","THORN"],["224","a - grave"],["225","a - acute"],["226","a - circumflex"],["227","a - tilde"],["228","a - diaeresis"],["229","a - ring above"],["257","a - macron"],["230","ligature ae"],["231","c - cedilla"],["232","e - grave"],["233","e - acute"],["234","e - circumflex"],["235","e - diaeresis"],["275","e - macron"],["236","i - grave"],["237","i - acute"],["238","i - circumflex"],["239","i - diaeresis"],["299","i - macron"],["240","eth"],["241","n - tilde"],["242","o - grave"],["243","o - acute"],["244","o - circumflex"],["245","o - tilde"],["246","o - diaeresis"],["248","o slash"],["333","o macron"],["339","ligature oe"],["353","s - caron"],["249","u - grave"],["250","u - acute"],["251","u - circumflex"],["252","u - diaeresis"],["363","u - macron"],["253","y - acute"],["254","thorn"],["255","y - diaeresis"],["563","y - macron"],["913","Alpha"],["914","Beta"],["915","Gamma"],["916","Delta"],["917","Epsilon"],["918","Zeta"],["919","Eta"],["920","Theta"],["921","Iota"],["922","Kappa"],["923","Lambda"],["924","Mu"],["925","Nu"],["926","Xi"],["927","Omicron"],["928","Pi"],["929","Rho"],["931","Sigma"],["932","Tau"],["933","Upsilon"],["934","Phi"],["935","Chi"],["936","Psi"],["937","Omega"],["945","alpha"],["946","beta"],["947","gamma"],["948","delta"],["949","epsilon"],["950","zeta"],["951","eta"],["952","theta"],["953","iota"],["954","kappa"],["955","lambda"],["956","mu"],["957","nu"],["958","xi"],["959","omicron"],["960","pi"],["961","rho"],["962","final sigma"],["963","sigma"],["964","tau"],["965","upsilon"],["966","phi"],["967","chi"],["968","psi"],["969","omega"],["8501","alef symbol"],["982","pi symbol"],["8476","real part symbol"],["978","upsilon - hook symbol"],["8472","Weierstrass p"],["8465","imaginary part"],["8592","leftwards arrow"],["8593","upwards arrow"],["8594","rightwards arrow"],["8595","downwards arrow"],["8596","left right arrow"],["8629","carriage return"],["8656","leftwards double arrow"],["8657","upwards double arrow"],["8658","rightwards double arrow"],["8659","downwards double arrow"],["8660","left right double arrow"],["8756","therefore"],["8834","subset of"],["8835","superset of"],["8836","not a subset of"],["8838","subset of or equal to"],["8839","superset of or equal to"],["8853","circled plus"],["8855","circled times"],["8869","perpendicular"],["8901","dot operator"],["8968","left ceiling"],["8969","right ceiling"],["8970","left floor"],["8971","right floor"],["9001","left-pointing angle bracket"],["9002","right-pointing angle bracket"],["9674","lozenge"],["9824","black spade suit"],["9827","black club suit"],["9829","black heart suit"],["9830","black diamond suit"],["8194","en space"],["8195","em space"],["8201","thin space"],["8204","zero width non-joiner"],["8205","zero width joiner"],["8206","left-to-right mark"],["8207","right-to-left mark"]])},t=function(t){return{getCharMap:function(){return s(t)},insertChar:function(e){l(t,e)}}},u=function(e){var t,a,i,r=Math.min(e.length,25),n=Math.ceil(e.length/r);for(t='',i=0;i",a=0;a
    '+s+"
    "}else t+="
    "}return t+=""},d=function(e){for(;e;){if("TD"===e.nodeName)return e;e=e.parentNode}},m=function(n){var o,e={type:"container",html:u(s(n)),onclick:function(e){var t=e.target;if(/^(TD|DIV)$/.test(t.nodeName)){var a=d(t).firstChild;if(a&&a.hasAttribute("data-chr")){var i=a.getAttribute("data-chr"),r=parseInt(i,10);isNaN(r)||l(n,String.fromCharCode(r)),e.ctrlKey||o.close()}}},onmouseover:function(e){var t=d(e.target);t&&t.firstChild?(o.find("#preview").text(t.firstChild.firstChild.data),o.find("#previewTitle").text(t.title)):(o.find("#preview").text(" "),o.find("#previewTitle").text(" "))}};o=n.windowManager.open({title:"Special character",spacing:10,padding:10,items:[e,{type:"container",layout:"flex",direction:"column",align:"center",spacing:5,minWidth:160,minHeight:160,items:[{type:"label",name:"preview",text:" ",style:"font-size: 40px; text-align: center",border:1,minWidth:140,minHeight:80},{type:"spacer",minHeight:20},{type:"label",name:"previewTitle",text:" ",style:"white-space: pre-wrap;",border:1,minWidth:140}]}],buttons:[{text:"Close",onclick:function(){o.close()}}]})},g=function(e){e.addCommand("mceShowCharmap",function(){m(e)})},p=function(e){e.addButton("charmap",{icon:"charmap",tooltip:"Special character",cmd:"mceShowCharmap"}),e.addMenuItem("charmap",{icon:"charmap",text:"Special character",cmd:"mceShowCharmap",context:"insert"})};e.add("charmap",function(e){return g(e),p(e),t(e)})}(); \ No newline at end of file diff --git a/tools/tinymce/plugins/code/plugin.min.js b/tools/tinymce/plugins/code/plugin.min.js index bbc39239b7..7afcca644e 100644 --- a/tools/tinymce/plugins/code/plugin.min.js +++ b/tools/tinymce/plugins/code/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;ia.length)break a;if(!(q instanceof e)){k.lastIndex=0;var r=k.exec(q);if(r){m&&(n=r[1].length);var s=r.index-1+n,r=r[0].slice(n),t=r.length,u=s+t,v=q.slice(0,s+1),w=q.slice(u+1),x=[p,1];v&&x.push(v);var y=new e(h,l?c.tokenize(r,l):r,o);x.push(y),w&&x.push(w),Array.prototype.splice.apply(f,x)}}}}}return f},hooks:{all:{},add:function(a,b){var d=c.hooks.all;d[a]=d[a]||[],d[a].push(b)},run:function(a,b){var d=c.hooks.all[a];if(d&&d.length)for(var e,f=0;e=d[f++];)e(b)}}},d=c.Token=function(a,b,c){this.type=a,this.content=b,this.alias=c};if(d.stringify=function(a,b,e){if("string"==typeof a)return a;if("Array"===c.util.type(a))return a.map(function(c){return d.stringify(c,b,a)}).join("");var f={type:a.type,content:d.stringify(a.content,b,e),tag:"span",classes:["token",a.type],attributes:{},language:b,parent:e};if("comment"==f.type&&(f.attributes.spellcheck="true"),a.alias){var g="Array"===c.util.type(a.alias)?a.alias:[a.alias];Array.prototype.push.apply(f.classes,g)}c.hooks.run("wrap",f);var h="";for(var i in f.attributes)h+=(h?" ":"")+i+'="'+(f.attributes[i]||"")+'"';return"<"+f.tag+' class="'+f.classes.join(" ")+'" '+h+">"+f.content+""},!b.document)return b.addEventListener?(b.addEventListener("message",function(a){var d=JSON.parse(a.data),e=d.language,f=d.code,g=d.immediateClose;b.postMessage(c.highlight(f,c.languages[e],e)),g&&b.close()},!1),b.Prism):b.Prism}();return"undefined"!=typeof module&&module.exports&&(module.exports=c),"undefined"!=typeof global&&(global.Prism=c),c.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},c.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),c.languages.xml=c.languages.markup,c.languages.html=c.languages.markup,c.languages.mathml=c.languages.markup,c.languages.svg=c.languages.markup,c.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},c.languages.css.atrule.inside.rest=c.util.clone(c.languages.css),c.languages.markup&&(c.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/i,inside:{tag:{pattern:/|<\/style>/i,inside:c.languages.markup.tag.inside},rest:c.languages.css},alias:"language-css"}}),c.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:c.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:c.languages.css}},alias:"language-css"}},c.languages.markup.tag)),c.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},c.languages.javascript=c.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i}),c.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),c.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:c.languages.javascript}},string:/[\s\S]+/}}}),c.languages.markup&&c.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/i,inside:{tag:{pattern:/|<\/script>/i,inside:c.languages.markup.tag.inside},rest:c.languages.javascript},alias:"language-javascript"}}),c.languages.js=c.languages.javascript,c.languages.c=c.languages.extend("clike",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/\-[>-]?|\+\+?|!=?|<>?=?|==?|&&?|\|?\||[~^%?*\/]/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i}),c.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,lookbehind:!0}}}}),delete c.languages.c["class-name"],delete c.languages.c["boolean"],c.languages.csharp=c.languages.extend("clike",{keyword:/\b(abstract|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/,string:[/@("|')(\1\1|\\\1|\\?(?!\1)[\s\S])*\1/,/("|')(\\?.)*?\1/],number:/\b-?(0x[\da-f]+|\d*\.?\d+)\b/i}),c.languages.insertBefore("csharp","keyword",{preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0}}),c.languages.cpp=c.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(true|false)\b/,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),c.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)[a-z0-9_]+/i,lookbehind:!0}}),c.languages.java=c.languages.extend("clike",{keyword:/\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/,number:/\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp\-]+\b|\b\d*\.?\d+(?:e[+-]?\d+)?[df]?\b/i,operator:{pattern:/(^|[^.])(?:\+[+=]?|-[-=]?|!=?|<>?>?=?|==?|&[&=]?|\|[|=]?|\*=?|\/=?|%=?|\^=?|[?:~])/m,lookbehind:!0}}),c.languages.php=c.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,constant:/\b[A-Z0-9_]{2,}\b/,comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,lookbehind:!0}}),c.languages.insertBefore("php","class-name",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),c.languages.insertBefore("php","keyword",{delimiter:/\?>|<\?(?:php)?/i,variable:/\$\w+\b/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),c.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}}),c.languages.markup&&(c.hooks.add("before-highlight",function(a){"php"===a.language&&(a.tokenStack=[],a.backupCode=a.code,a.code=a.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/gi,function(b){return a.tokenStack.push(b),"{{{PHP"+a.tokenStack.length+"}}}"}))}),c.hooks.add("before-insert",function(a){"php"===a.language&&(a.code=a.backupCode,delete a.backupCode)}),c.hooks.add("after-highlight",function(a){if("php"===a.language){for(var b,d=0;b=a.tokenStack[d];d++)a.highlightedCode=a.highlightedCode.replace("{{{PHP"+(d+1)+"}}}",c.highlight(b,a.grammar,"php").replace(/\$/g,"$$$$"));a.element.innerHTML=a.highlightedCode}}),c.hooks.add("wrap",function(a){"php"===a.language&&"markup"===a.type&&(a.content=a.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g,'$1'))}),c.languages.insertBefore("php","comment",{markup:{pattern:/<[^?]\/?(.*?)>/,inside:c.languages.markup},php:/\{\{\{PHP[0-9]+\}\}\}/})),c.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:/"""[\s\S]+?"""|'''[\s\S]+?'''|("|')(?:\\?.)*?\1/,"function":{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)[a-z0-9_]+/i,lookbehind:!0},keyword:/\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,"boolean":/\b(?:True|False)\b/,number:/\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,punctuation:/[{}[\];(),.:]/},function(a){a.languages.ruby=a.languages.extend("clike",{comment:/#(?!\{[^\r\n]*?\}).*/,keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/});var b={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:a.util.clone(a.languages.ruby)}};a.languages.insertBefore("ruby","keyword",{regex:[{pattern:/%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/,inside:{interpolation:b}},{pattern:/%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,inside:{interpolation:b}},{pattern:/%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,inside:{interpolation:b}},{pattern:/%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,inside:{interpolation:b}},{pattern:/%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,inside:{interpolation:b}},{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}],variable:/[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,symbol:/:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/}),a.languages.insertBefore("ruby","number",{builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/}),a.languages.ruby.string=[{pattern:/%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,inside:{interpolation:b}},{pattern:/%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,inside:{interpolation:b}},{pattern:/%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,inside:{interpolation:b}},{pattern:/%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,inside:{interpolation:b}},{pattern:/%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,inside:{interpolation:b}},{pattern:/("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,inside:{interpolation:b}}]}(c),c}),g("8",[],function(){function a(a){return a&&"PRE"===a.nodeName&&a.className.indexOf("language-")!==-1}function b(a){return function(b,c){return a(c)}}return{isCodeSample:a,trimArg:b}}),g("b",["e","d","8"],function(a,b,c){var d=function(a){var b=a.selection.getNode();return c.isCodeSample(b)?b:null},e=function(c,e,f){c.undoManager.transact(function(){var g=d(c);f=a.DOM.encode(f),g?(c.dom.setAttrib(g,"class","language-"+e),g.innerHTML=f,b.highlightElement(g),c.selection.select(g)):(c.insertContent('
    '+f+"
    "),c.selection.select(c.$("#__new").removeAttr("id")[0]))})},f=function(a){var b=d(a);return b?b.textContent:""};return{getSelectedCodeSample:d,insertCodeSample:e,getCurrentCode:f}}),g("c",["a","b"],function(a,b){var c=function(b){var c=[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}],d=a.getLanguages(b);return d?d:c},d=function(a){var c,d=b.getSelectedCodeSample(a);return d?(c=d.className.match(/language-(\w+)/),c?c[1]:""):""};return{getLanguages:c,getCurrentLanguage:d}}),g("7",["a","b","c"],function(a,b,c){return{open:function(d){var e=a.getDialogMinWidth(d),f=a.getDialogMinHeight(d),g=c.getCurrentLanguage(d),h=c.getLanguages(d),i=b.getCurrentCode(d);d.windowManager.open({title:"Insert/Edit code sample",minWidth:e,minHeight:f,layout:"flex",direction:"column",align:"stretch",body:[{type:"listbox",name:"language",label:"Language",maxWidth:200,value:g,values:h},{type:"textbox",name:"code",multiline:!0,spellcheck:!1,ariaLabel:"Code view",flex:1,style:"direction: ltr; text-align: left",classes:"monospace",value:i,autofocus:!0}],onSubmit:function(a){b.insertCodeSample(d,a.data.language,a.data.code)}})}}}),g("3",["7","8"],function(a,b){var c=function(c){c.addCommand("codesample",function(){var d=c.selection.getNode();c.selection.isCollapsed()||b.isCodeSample(d)?a.open(c):c.formatter.toggle("code")})};return{register:c}}),g("4",["d","8"],function(a,b){var c=function(c){var d=c.$;c.on("PreProcess",function(a){d("pre[contenteditable=false]",a.node).filter(b.trimArg(b.isCodeSample)).each(function(a,b){var c=d(b),e=b.textContent;c.attr("class",d.trim(c.attr("class"))),c.removeAttr("contentEditable"),c.empty().append(d("").each(function(){this.textContent=e}))})}),c.on("SetContent",function(){var e=d("pre").filter(b.trimArg(b.isCodeSample)).filter(function(a,b){return"false"!==b.contentEditable});e.length&&c.undoManager.transact(function(){e.each(function(b,e){d(e).find("br").each(function(a,b){b.parentNode.replaceChild(c.getDoc().createTextNode("\n"),b)}),e.contentEditable=!1,e.innerHTML=c.dom.encode(e.textContent),a.highlightElement(e),e.className=d.trim(e.className)})})})};return{setup:c}}),g("5",["a"],function(a){var b=function(b,c,d,e){var f,g=a.getContentCss(b);b.inline&&d.get()||!b.inline&&e.get()||(b.inline?d.set(!0):e.set(!0),g!==!1&&(f=b.dom.create("link",{rel:"stylesheet",href:g?g:c+"/css/prism.css"}),b.getDoc().getElementsByTagName("head")[0].appendChild(f)))};return{loadCss:b}}),g("6",[],function(){var a=function(a){a.addButton("codesample",{cmd:"codesample",title:"Insert/Edit code sample"}),a.addMenuItem("codesample",{cmd:"codesample",text:"Code sample",icon:"codesample"})};return{register:a}}),g("0",["1","2","3","4","5","6","7","8"],function(a,b,c,d,e,f,g,h){var i=a(!1);return b.add("codesample",function(b,j){var k=a(!1);d.setup(b),f.register(b),c.register(b),b.on("init",function(){e.loadCss(b,j,i,k)}),b.on("dblclick",function(a){h.isCodeSample(a.target)&&g.open(b)})}),function(){}}),d("0")()}(); \ No newline at end of file +!function(u){"use strict";var n=function(e){var t=e,a=function(){return t};return{get:a,set:function(e){t=e},clone:function(){return n(a())}}},e=tinymce.util.Tools.resolve("tinymce.PluginManager"),i=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),s=function(e){return e.settings.codesample_content_css},a=function(e){return e.settings.codesample_languages},o=function(e){return Math.min(i.DOM.getViewPort().w,e.getParam("codesample_dialog_width",800))},l=function(e){return Math.min(i.DOM.getViewPort().w,e.getParam("codesample_dialog_height",650))},t={},r=t,g=void 0!==t?t:"undefined"!=typeof WorkerGlobalScope&&u.self instanceof WorkerGlobalScope?u.self:{},c=function(){var c=/\blang(?:uage)?-(?!\*)(\w+)\b/i,S=g.Prism={util:{encode:function(e){return e instanceof o?new o(e.type,S.util.encode(e.content),e.alias):"Array"===S.util.type(e)?e.map(S.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(h instanceof n)){c.lastIndex=0;var m=c.exec(h);if(m){g&&(d=m[1].length);var b=m.index-1+d,y=b+(m=m[0].slice(d)).length,v=h.slice(0,b+1),k=h.slice(y+1),w=[f,1];v&&w.push(v);var x=new n(s,u?S.tokenize(m,u):m,p);w.push(x),k&&w.push(k),Array.prototype.splice.apply(i,w)}}}}}return i},hooks:{all:{},add:function(e,t){var a=S.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=S.hooks.all[e];if(a&&a.length)for(var n=0,i=void 0;i=a[n++];)i(t)}}},o=S.Token=function(e,t,a){this.type=e,this.content=t,this.alias=a};if(o.stringify=function(t,a,e){if("string"==typeof t)return t;if("Array"===S.util.type(t))return t.map(function(e){return o.stringify(e,a,t)}).join("");var n={type:t.type,content:o.stringify(t.content,a,e),tag:"span",classes:["token",t.type],attributes:{},language:a,parent:e};if("comment"===n.type&&(n.attributes.spellcheck="true"),t.alias){var i="Array"===S.util.type(t.alias)?t.alias:[t.alias];Array.prototype.push.apply(n.classes,i)}S.hooks.run("wrap",n);var r="";for(var s in n.attributes)r+=(r?" ":"")+s+'="'+(n.attributes[s]||"")+'"';return"<"+n.tag+' class="'+n.classes.join(" ")+'" '+r+">"+n.content+""},!g.document)return g.addEventListener&&g.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,n=t.code,i=t.immediateClose;g.postMessage(S.highlight(n,S.languages[a],a)),i&&g.close()},!1),g.Prism}();void 0!==r&&(r.Prism=c),c.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},c.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),c.languages.xml=c.languages.markup,c.languages.html=c.languages.markup,c.languages.mathml=c.languages.markup,c.languages.svg=c.languages.markup,c.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},c.languages.css.atrule.inside.rest=c.util.clone(c.languages.css),c.languages.markup&&(c.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/i,inside:{tag:{pattern:/|<\/style>/i,inside:c.languages.markup.tag.inside},rest:c.languages.css},alias:"language-css"}}),c.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:c.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:c.languages.css}},alias:"language-css"}},c.languages.markup.tag)),c.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},c.languages.javascript=c.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i}),c.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),c.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:c.languages.javascript}},string:/[\s\S]+/}}}),c.languages.markup&&c.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/i,inside:{tag:{pattern:/|<\/script>/i,inside:c.languages.markup.tag.inside},rest:c.languages.javascript},alias:"language-javascript"}}),c.languages.js=c.languages.javascript,c.languages.c=c.languages.extend("clike",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/\-[>-]?|\+\+?|!=?|<>?=?|==?|&&?|\|?\||[~^%?*\/]/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i}),c.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,lookbehind:!0}}}}),delete c.languages.c["class-name"],delete c.languages.c["boolean"],c.languages.csharp=c.languages.extend("clike",{keyword:/\b(abstract|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/,string:[/@("|')(\1\1|\\\1|\\?(?!\1)[\s\S])*\1/,/("|')(\\?.)*?\1/],number:/\b-?(0x[\da-f]+|\d*\.?\d+)\b/i}),c.languages.insertBefore("csharp","keyword",{preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0}}),c.languages.cpp=c.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(true|false)\b/,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),c.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)[a-z0-9_]+/i,lookbehind:!0}}),c.languages.java=c.languages.extend("clike",{keyword:/\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/,number:/\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp\-]+\b|\b\d*\.?\d+(?:e[+-]?\d+)?[df]?\b/i,operator:{pattern:/(^|[^.])(?:\+[+=]?|-[-=]?|!=?|<>?>?=?|==?|&[&=]?|\|[|=]?|\*=?|\/=?|%=?|\^=?|[?:~])/m,lookbehind:!0}}),c.languages.php=c.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,constant:/\b[A-Z0-9_]{2,}\b/,comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,lookbehind:!0}}),c.languages.insertBefore("php","class-name",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),c.languages.insertBefore("php","keyword",{delimiter:/\?>|<\?(?:php)?/i,variable:/\$\w+\b/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),c.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}}),c.languages.markup&&(c.hooks.add("before-highlight",function(t){"php"===t.language&&(t.tokenStack=[],t.backupCode=t.code,t.code=t.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/gi,function(e){return t.tokenStack.push(e),"{{{PHP"+t.tokenStack.length+"}}}"}))}),c.hooks.add("before-insert",function(e){"php"===e.language&&(e.code=e.backupCode,delete e.backupCode)}),c.hooks.add("after-highlight",function(e){if("php"===e.language){for(var t=0,a=void 0;a=e.tokenStack[t];t++)e.highlightedCode=e.highlightedCode.replace("{{{PHP"+(t+1)+"}}}",c.highlight(a,e.grammar,"php").replace(/\$/g,"$$$$"));e.element.innerHTML=e.highlightedCode}}),c.hooks.add("wrap",function(e){"php"===e.language&&"markup"===e.type&&(e.content=e.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g,'$1'))}),c.languages.insertBefore("php","comment",{markup:{pattern:/<[^?]\/?(.*?)>/,inside:c.languages.markup},php:/\{\{\{PHP[0-9]+\}\}\}/})),c.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:/"""[\s\S]+?"""|'''[\s\S]+?'''|("|')(?:\\?.)*?\1/,"function":{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)[a-z0-9_]+/i,lookbehind:!0},keyword:/\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,"boolean":/\b(?:True|False)\b/,number:/\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,punctuation:/[{}[\];(),.:]/},function(e){e.languages.ruby=e.languages.extend("clike",{comment:/#(?!\{[^\r\n]*?\}).*/,keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/});var t={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.util.clone(e.languages.ruby)}};e.languages.insertBefore("ruby","keyword",{regex:[{pattern:/%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,inside:{interpolation:t}},{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}],variable:/[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,symbol:/:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.insertBefore("ruby","number",{builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:/%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,inside:{interpolation:t}},{pattern:/("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,inside:{interpolation:t}}]}(c);var d={isCodeSample:function(e){return e&&"PRE"===e.nodeName&&-1!==e.className.indexOf("language-")},trimArg:function(a){return function(e,t){return a(t)}}},p=function(e){var t=e.selection.getNode();return d.isCodeSample(t)?t:null},f=p,h=function(t,a,n){t.undoManager.transact(function(){var e=p(t);n=i.DOM.encode(n),e?(t.dom.setAttrib(e,"class","language-"+a),e.innerHTML=n,c.highlightElement(e),t.selection.select(e)):(t.insertContent('
    '+n+"
    "),t.selection.select(t.$("#__new").removeAttr("id")[0]))})},m=function(e){var t=p(e);return t?t.textContent:""},b=function(e){var t=a(e);return t||[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}]},y=function(e){var t,a=f(e);return a&&(t=a.className.match(/language-(\w+)/))?t[1]:""},v=function(t){var e=o(t),a=l(t),n=y(t),i=b(t),r=m(t);t.windowManager.open({title:"Insert/Edit code sample",minWidth:e,minHeight:a,layout:"flex",direction:"column",align:"stretch",body:[{type:"listbox",name:"language",label:"Language",maxWidth:200,value:n,values:i},{type:"textbox",name:"code",multiline:!0,spellcheck:!1,ariaLabel:"Code view",flex:1,style:"direction: ltr; text-align: left",classes:"monospace",value:r,autofocus:!0}],onSubmit:function(e){h(t,e.data.language,e.data.code)}})},k=function(t){t.addCommand("codesample",function(){var e=t.selection.getNode();t.selection.isCollapsed()||d.isCodeSample(e)?v(t):t.formatter.toggle("code")})},w=function(a){var i=a.$;a.on("PreProcess",function(e){i("pre[contenteditable=false]",e.node).filter(d.trimArg(d.isCodeSample)).each(function(e,t){var a=i(t),n=t.textContent;a.attr("class",i.trim(a.attr("class"))),a.removeAttr("contentEditable"),a.empty().append(i("").each(function(){this.textContent=n}))})}),a.on("SetContent",function(){var e=i("pre").filter(d.trimArg(d.isCodeSample)).filter(function(e,t){return"false"!==t.contentEditable});e.length&&a.undoManager.transact(function(){e.each(function(e,t){i(t).find("br").each(function(e,t){t.parentNode.replaceChild(a.getDoc().createTextNode("\n"),t)}),t.contentEditable=!1,t.innerHTML=a.dom.encode(t.textContent),c.highlightElement(t),t.className=i.trim(t.className)})})})},x=function(e,t,a,n){var i,r=s(e);e.inline&&a.get()||!e.inline&&n.get()||(e.inline?a.set(!0):n.set(!0),!1!==r&&(i=e.dom.create("link",{rel:"stylesheet",href:r||t+"/css/prism.css"}),e.getDoc().getElementsByTagName("head")[0].appendChild(i)))},S=function(e){e.addButton("codesample",{cmd:"codesample",title:"Insert/Edit code sample"}),e.addMenuItem("codesample",{cmd:"codesample",text:"Code sample",icon:"codesample"})},C=n(!1);e.add("codesample",function(t,e){var a=n(!1);w(t),S(t),k(t),t.on("init",function(){x(t,e,C,a)}),t.on("dblclick",function(e){d.isCodeSample(e.target)&&v(t)})})}(window); \ No newline at end of file diff --git a/tools/tinymce/plugins/colorpicker/plugin.min.js b/tools/tinymce/plugins/colorpicker/plugin.min.js index 132caaa2cc..10317a5f6f 100644 --- a/tools/tinymce/plugins/colorpicker/plugin.min.js +++ b/tools/tinymce/plugins/colorpicker/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i'}),d+=""}),d+=""};return{getHtml:c}}),g("2",["4"],function(a){var b=function(a,b,c){a.insertContent(a.dom.createHTML("img",{src:b,alt:c}))},c=function(c,d){var e=a.getHtml(d);c.addButton("emoticons",{type:"panelbutton",panel:{role:"application",autohide:!0,html:e,onclick:function(a){var d=c.dom.getParent(a.target,"a");d&&(b(c,d.getAttribute("data-mce-url"),d.getAttribute("data-mce-alt")),this.hide())}},tooltip:"Emoticons"})};return{register:c}}),g("0",["1","2"],function(a,b){return a.add("emoticons",function(a,c){b.register(a,c)}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),e=tinymce.util.Tools.resolve("tinymce.util.Tools"),n=[["cool","cry","embarassed","foot-in-mouth"],["frown","innocent","kiss","laughing"],["money-mouth","sealed","smile","surprised"],["tongue-out","undecided","wink","yell"]],i=function(i){var o;return o='',e.each(n,function(t){o+="",e.each(t,function(t){var e=i+"/img/smiley-"+t+".gif";o+=''}),o+=""}),o+="
    "},o=function(a,t){var e=i(t);a.addButton("emoticons",{type:"panelbutton",panel:{role:"application",autohide:!0,html:e,onclick:function(t){var e,i,o,n=a.dom.getParent(t.target,"a");n&&(e=a,i=n.getAttribute("data-mce-url"),o=n.getAttribute("data-mce-alt"),e.insertContent(e.dom.createHTML("img",{src:i,alt:o})),this.hide())}},tooltip:"Emoticons"})};t.add("emoticons",function(t,e){o(t,e)})}(); \ No newline at end of file diff --git a/tools/tinymce/plugins/fullpage/plugin.min.js b/tools/tinymce/plugins/fullpage/plugin.min.js index 87055444e7..de5221a8e0 100644 --- a/tools/tinymce/plugins/fullpage/plugin.min.js +++ b/tools/tinymce/plugins/fullpage/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i")};return{shouldHideInSourceView:a,getDefaultXmlPi:b,getDefaultEncoding:c,getDefaultFontFamily:d,getDefaultFontSize:e,getDefaultTextColor:f,getDefaultTitle:g,getDefaultDocType:h}}),g("a",["c","d","e","8","9"],function(a,b,c,d,e){var f=function(b){return new a({validate:!1,root_name:"#document"}).parse(b)},g=function(a,b){function c(a,b){var c=a.attr(b);return c||""}var g,h,i=f(b),j={};return j.fontface=e.getDefaultFontFamily(a),j.fontsize=e.getDefaultFontSize(a),g=i.firstChild,7===g.type&&(j.xml_pi=!0,h=/encoding="([^"]+)"/.exec(g.value),h&&(j.docencoding=h[1])),g=i.getAll("#doctype")[0],g&&(j.doctype=""),g=i.getAll("title")[0],g&&g.firstChild&&(j.title=g.firstChild.value),d.each(i.getAll("meta"),function(a){var b,c=a.attr("name"),d=a.attr("http-equiv");c?j[c.toLowerCase()]=a.attr("content"):"Content-Type"===d&&(b=/charset\s*=\s*(.*)\s*/gi.exec(a.attr("content")),b&&(j.docencoding=b[1]))}),g=i.getAll("html")[0],g&&(j.langcode=c(g,"lang")||c(g,"xml:lang")),j.stylesheets=[],d.each(i.getAll("link"),function(a){"stylesheet"===a.attr("rel")&&j.stylesheets.push(a.attr("href"))}),g=i.getAll("body")[0],g&&(j.langdir=c(g,"dir"),j.style=c(g,"style"),j.visited_color=c(g,"vlink"),j.link_color=c(g,"link"),j.active_color=c(g,"alink")),j},h=function(a,e,g){function h(a,b,c){a.attr(b,c?c:void 0)}function i(a){k.firstChild?k.insert(a,k.firstChild):k.append(a)}var j,k,l,m,n,o=a.dom;j=f(g),k=j.getAll("head")[0],k||(m=j.getAll("html")[0],k=new b("head",1),m.firstChild?m.insert(k,m.firstChild,!0):m.append(k)),m=j.firstChild,e.xml_pi?(n='version="1.0"',e.docencoding&&(n+=' encoding="'+e.docencoding+'"'),7!==m.type&&(m=new b("xml",7),j.insert(m,j.firstChild,!0)),m.value=n):m&&7===m.type&&m.remove(),m=j.getAll("#doctype")[0],e.doctype?(m||(m=new b("#doctype",10),e.xml_pi?j.insert(m,j.firstChild):i(m)),m.value=e.doctype.substring(9,e.doctype.length-1)):m&&m.remove(),m=null,d.each(j.getAll("meta"),function(a){"Content-Type"===a.attr("http-equiv")&&(m=a)}),e.docencoding?(m||(m=new b("meta",1),m.attr("http-equiv","Content-Type"),m.shortEnded=!0,i(m)),m.attr("content","text/html; charset="+e.docencoding)):m&&m.remove(),m=j.getAll("title")[0],e.title?(m?m.empty():(m=new b("title",1),i(m)),m.append(new b("#text",3)).value=e.title):m&&m.remove(),d.each("keywords,description,author,copyright,robots".split(","),function(a){var c,d,f=j.getAll("meta"),g=e[a];for(c=0;c"))};return{parseHeader:f,htmlToData:g,dataToHtml:h}}),g("7",["8","a"],function(a,b){var c=function(c,d){var e=b.htmlToData(c,d.get());c.windowManager.open({title:"Document properties",data:e,defaults:{type:"textbox",size:40},body:[{name:"title",label:"Title"},{name:"keywords",label:"Keywords"},{name:"description",label:"Description"},{name:"robots",label:"Robots"},{name:"author",label:"Author"},{name:"docencoding",label:"Encoding"}],onSubmit:function(f){var g=b.dataToHtml(c,a.extend(e,f.data),d.get());d.set(g)}})};return{open:c}}),g("3",["7"],function(a){var b=function(b,c){b.addCommand("mceFullPageProperties",function(){a.open(b,c)})};return{register:b}}),g("b",["8"],function(a){var b=function(b,c){return a.each(b,function(a){c=c.replace(a,function(a){return""})}),c},c=function(a){return a.replace(//g,function(a,b){return unescape(b)})};return{protectHtml:b,unprotectHtml:c}}),g("4",["8","9","a","b"],function(a,b,c,d){var e=a.each,f=function(a){return a.replace(/<\/?[A-Z]+/g,function(a){return a.toLowerCase()})},g=function(g,i,j,k){var l,m,n,o,p,q="",r=g.dom;if(!(k.selection||(n=d.protectHtml(g.settings.protect,k.content),"raw"===k.format&&i.get()||k.source_view&&b.shouldHideInSourceView(g)))){0!==n.length||k.source_view||(n=a.trim(i.get())+"\n"+a.trim(n)+"\n"+a.trim(j.get())),n=n.replace(/<(\/?)BODY/gi,"<$1body"),l=n.indexOf("",l),i.set(f(n.substring(0,l+1))),m=n.indexOf("\n")),o=c.parseHeader(i.get()),e(o.getAll("style"),function(a){a.firstChild&&(q+=a.firstChild.value)}),p=o.getAll("body")[0],p&&r.setAttribs(g.getBody(),{style:p.attr("style")||"",dir:p.attr("dir")||"",vLink:p.attr("vlink")||"",link:p.attr("link")||"",aLink:p.attr("alink")||""}),r.remove("fullpage_styles");var s=g.getDoc().getElementsByTagName("head")[0];q&&(r.add(s,"style",{id:"fullpage_styles"},q),p=r.get("fullpage_styles"),p.styleSheet&&(p.styleSheet.cssText=q));var t={};a.each(s.getElementsByTagName("link"),function(a){"stylesheet"===a.rel&&a.getAttribute("data-mce-fullpage")&&(t[a.href]=a)}),a.each(o.getAll("link"),function(a){var b=a.attr("href");return!b||(t[b]||"stylesheet"!==a.attr("rel")||r.add(s,"link",{rel:"stylesheet",text:"text/css",href:b,"data-mce-fullpage":"1"}),void delete t[b])}),a.each(t,function(a){a.parentNode.removeChild(a)})}},h=function(a){var c,d="",e="";if(b.getDefaultXmlPi(a)){var f=b.getDefaultEncoding(a);d+='\n'}return d+=b.getDefaultDocType(a),d+="\n\n\n",(c=b.getDefaultTitle(a))&&(d+=""+c+"\n"),(c=b.getDefaultEncoding(a))&&(d+='\n'),(c=b.getDefaultFontFamily(a))&&(e+="font-family: "+c+";"),(c=b.getDefaultFontSize(a))&&(e+="font-size: "+c+";"),(c=b.getDefaultTextColor(a))&&(e+="color: "+c+";"),d+="\n\n"},i=function(c,e,f,g){g.selection||g.source_view&&b.shouldHideInSourceView(c)||(g.content=d.unprotectHtml(a.trim(e)+"\n"+a.trim(g.content)+"\n"+a.trim(f)))},j=function(a,b,c){a.on("BeforeSetContent",function(d){g(a,b,c,d)}),a.on("GetContent",function(d){i(a,b.get(),c.get(),d)})};return{setup:j}}),g("5",[],function(){var a=function(a){a.addButton("fullpage",{title:"Document properties",cmd:"mceFullPageProperties"}),a.addMenuItem("fullpage",{text:"Document properties",cmd:"mceFullPageProperties",context:"file"})};return{register:a}}),g("0",["1","2","3","4","5"],function(a,b,c,d,e){return b.add("fullpage",function(b){var f=a(""),g=a("");c.register(b,f),e.register(b),d.setup(b,f,g)}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var l=function(e){var t=e,n=function(){return t};return{get:n,set:function(e){t=e},clone:function(){return l(n())}}},e=tinymce.util.Tools.resolve("tinymce.PluginManager"),g=tinymce.util.Tools.resolve("tinymce.util.Tools"),t=tinymce.util.Tools.resolve("tinymce.html.DomParser"),f=tinymce.util.Tools.resolve("tinymce.html.Node"),m=tinymce.util.Tools.resolve("tinymce.html.Serializer"),h=function(e){return e.getParam("fullpage_hide_in_source_view")},r=function(e){return e.getParam("fullpage_default_xml_pi")},o=function(e){return e.getParam("fullpage_default_encoding")},a=function(e){return e.getParam("fullpage_default_font_family")},c=function(e){return e.getParam("fullpage_default_font_size")},s=function(e){return e.getParam("fullpage_default_text_color")},u=function(e){return e.getParam("fullpage_default_title")},d=function(e){return e.getParam("fullpage_default_doctype","")},p=function(e){return t({validate:!1,root_name:"#document"}).parse(e)},y=p,v=function(e,t){var n,l,i=p(t),r={};function o(e,t){return e.attr(t)||""}return r.fontface=a(e),r.fontsize=c(e),7===(n=i.firstChild).type&&(r.xml_pi=!0,(l=/encoding="([^"]+)"/.exec(n.value))&&(r.docencoding=l[1])),(n=i.getAll("#doctype")[0])&&(r.doctype=""),(n=i.getAll("title")[0])&&n.firstChild&&(r.title=n.firstChild.value),g.each(i.getAll("meta"),function(e){var t,n=e.attr("name"),l=e.attr("http-equiv");n?r[n.toLowerCase()]=e.attr("content"):"Content-Type"===l&&(t=/charset\s*=\s*(.*)\s*/gi.exec(e.attr("content")))&&(r.docencoding=t[1])}),(n=i.getAll("html")[0])&&(r.langcode=o(n,"lang")||o(n,"xml:lang")),r.stylesheets=[],g.each(i.getAll("link"),function(e){"stylesheet"===e.attr("rel")&&r.stylesheets.push(e.attr("href"))}),(n=i.getAll("body")[0])&&(r.langdir=o(n,"dir"),r.style=o(n,"style"),r.visited_color=o(n,"vlink"),r.link_color=o(n,"link"),r.active_color=o(n,"alink")),r},_=function(e,r,t){var o,n,l,a,i,c=e.dom;function s(e,t,n){e.attr(t,n||undefined)}function u(e){n.firstChild?n.insert(e,n.firstChild):n.append(e)}o=p(t),(n=o.getAll("head")[0])||(a=o.getAll("html")[0],n=new f("head",1),a.firstChild?a.insert(n,a.firstChild,!0):a.append(n)),a=o.firstChild,r.xml_pi?(i='version="1.0"',r.docencoding&&(i+=' encoding="'+r.docencoding+'"'),7!==a.type&&(a=new f("xml",7),o.insert(a,o.firstChild,!0)),a.value=i):a&&7===a.type&&a.remove(),a=o.getAll("#doctype")[0],r.doctype?(a||(a=new f("#doctype",10),r.xml_pi?o.insert(a,o.firstChild):u(a)),a.value=r.doctype.substring(9,r.doctype.length-1)):a&&a.remove(),a=null,g.each(o.getAll("meta"),function(e){"Content-Type"===e.attr("http-equiv")&&(a=e)}),r.docencoding?(a||((a=new f("meta",1)).attr("http-equiv","Content-Type"),a.shortEnded=!0,u(a)),a.attr("content","text/html; charset="+r.docencoding)):a&&a.remove(),a=o.getAll("title")[0],r.title?(a?a.empty():u(a=new f("title",1)),a.append(new f("#text",3)).value=r.title):a&&a.remove(),g.each("keywords,description,author,copyright,robots".split(","),function(e){var t,n,l=o.getAll("meta"),i=r[e];for(t=0;t"))},n=function(n,l){var i=v(n,l.get());n.windowManager.open({title:"Document properties",data:i,defaults:{type:"textbox",size:40},body:[{name:"title",label:"Title"},{name:"keywords",label:"Keywords"},{name:"description",label:"Description"},{name:"robots",label:"Robots"},{name:"author",label:"Author"},{name:"docencoding",label:"Encoding"}],onSubmit:function(e){var t=_(n,g.extend(i,e.data),l.get());l.set(t)}})},i=function(e,t){e.addCommand("mceFullPageProperties",function(){n(e,t)})},b=function(e,t){return g.each(e,function(e){t=t.replace(e,function(e){return"\x3c!--mce:protected "+escape(e)+"--\x3e"})}),t},x=function(e){return e.replace(//g,function(e,t){return unescape(t)})},k=g.each,C=function(e){return e.replace(/<\/?[A-Z]+/g,function(e){return e.toLowerCase()})},A=function(e){var t,n="",l="";if(r(e)){var i=o(e);n+='\n'}return n+=d(e),n+="\n\n\n",(t=u(e))&&(n+=""+t+"\n"),(t=o(e))&&(n+='\n'),(t=a(e))&&(l+="font-family: "+t+";"),(t=c(e))&&(l+="font-size: "+t+";"),(t=s(e))&&(l+="color: "+t+";"),n+="\n\n"},w=function(r,o,a){r.on("BeforeSetContent",function(e){!function(e,t,n,l){var i,r,o,a,c,s="",u=e.dom;if(!(l.selection||(o=b(e.settings.protect,l.content),"raw"===l.format&&t.get()||l.source_view&&h(e)))){0!==o.length||l.source_view||(o=g.trim(t.get())+"\n"+g.trim(o)+"\n"+g.trim(n.get())),-1!==(i=(o=o.replace(/<(\/?)BODY/gi,"<$1body")).indexOf("",i),t.set(C(o.substring(0,i+1))),-1===(r=o.indexOf("\n")),a=y(t.get()),k(a.getAll("style"),function(e){e.firstChild&&(s+=e.firstChild.value)}),(c=a.getAll("body")[0])&&u.setAttribs(e.getBody(),{style:c.attr("style")||"",dir:c.attr("dir")||"",vLink:c.attr("vlink")||"",link:c.attr("link")||"",aLink:c.attr("alink")||""}),u.remove("fullpage_styles");var d=e.getDoc().getElementsByTagName("head")[0];s&&(u.add(d,"style",{id:"fullpage_styles"},s),(c=u.get("fullpage_styles")).styleSheet&&(c.styleSheet.cssText=s));var f={};g.each(d.getElementsByTagName("link"),function(e){"stylesheet"===e.rel&&e.getAttribute("data-mce-fullpage")&&(f[e.href]=e)}),g.each(a.getAll("link"),function(e){var t=e.attr("href");if(!t)return!0;f[t]||"stylesheet"!==e.attr("rel")||u.add(d,"link",{rel:"stylesheet",text:"text/css",href:t,"data-mce-fullpage":"1"}),delete f[t]}),g.each(f,function(e){e.parentNode.removeChild(e)})}}(r,o,a,e)}),r.on("GetContent",function(e){var t,n,l,i;t=r,n=o.get(),l=a.get(),(i=e).selection||i.source_view&&h(t)||(i.content=x(g.trim(n)+"\n"+g.trim(i.content)+"\n"+g.trim(l)))})},P=function(e){e.addButton("fullpage",{title:"Document properties",cmd:"mceFullPageProperties"}),e.addMenuItem("fullpage",{text:"Document properties",cmd:"mceFullPageProperties",context:"file"})};e.add("fullpage",function(e){var t=l(""),n=l("");i(e,t),P(e),w(e,t,n)})}(); \ No newline at end of file diff --git a/tools/tinymce/plugins/fullscreen/plugin.min.js b/tools/tinymce/plugins/fullscreen/plugin.min.js index 5f4587c86c..259afc9a5b 100644 --- a/tools/tinymce/plugins/fullscreen/plugin.min.js +++ b/tools/tinymce/plugins/fullscreen/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i-1},h=function(a,b){return t(a,b).isSome()},i=function(a,b){for(var c=[],d=0;d=0;c--){var d=a[c];b(d,c,a)}},n=function(a,b){for(var c=[],d=[],e=0,f=a.length;e Ctrl + Shift + P",action:"Focus to contextual toolbar"},{shortcut:b+" + K",action:"Insert link (if link plugin activated)"},{shortcut:b+" + S",action:"Save (if save plugin activated)"},{shortcut:b+" + F",action:"Find (if searchreplace plugin activated)"}];return{shortcuts:d}}),g("7",["a","b","c"],function(a,b,c){var d=function(){var d=function(a){return'aria-label="Action: '+a.action+", Shortcut: "+a.shortcut.replace(/Ctrl/g,"Control")+'"'},e=a.map(c.shortcuts,function(a){return'"+b.translate(a.action)+""+a.shortcut+""}).join("");return{title:"Handy Shortcuts",type:"container",style:"overflow-y: auto; overflow-x: hidden; max-height: 250px",items:[{type:"container",html:'
    "+e+"
    '+b.translate("Action")+""+b.translate("Shortcut")+"
    "}]}};return{makeTab:d}}),g("e",["h","m"],function(a,b){var c=function(){var a=b.keys,c=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b};return void 0===a?c:a}(),d=function(a,b){for(var d=c(a),e=0,f=d.length;e${name}'),i=function(b,c){return a.find(g.urls,function(a){return a.key===c}).fold(function(){var a=b.plugins[c].getMetadata;return"function"==typeof a?h(a()):c},function(a){return h({name:a.name,url:"https://www.tinymce.com/docs/plugins/"+a.key})})},j=function(d){var e=c.keys(d.plugins);return void 0===d.settings.forced_plugins?e:a.filter(e,b.not(b.curry(a.contains,d.settings.forced_plugins)))},k=function(b){var c=j(b),d=a.map(c,function(a){return"
  • "+i(b,a)+"
  • "}),e=d.length,g=d.join("");return"

    "+f.translate(["Plugins installed ({0}):",e])+"

      "+g+"
    "},l=function(a){return{type:"container",html:'
    '+k(a)+"
    ",flex:1}},m=function(){return{type:"container",html:'

    '+f.translate("Premium plugins:")+'

    • PowerPaste
    • Spell Checker Pro
    • Accessibility Checker
    • Advanced Code Editor
    • Enhanced Media Embed
    • Link Checker

    '+f.translate("Learn more...")+"

    ",flex:1}},n=function(a){return{title:"Plugins",type:"container",style:"overflow-y: auto; overflow-x: hidden;",layout:"flex",padding:10,spacing:10,items:[l(a),m()]}};return{makeTab:n}}),g("9",["6","b"],function(a,b){var c=function(a,b){return 0===a.indexOf("@")?"X.X.X":a+"."+b},d=function(){var d=c(a.majorVersion,a.minorVersion),e='TinyMCE '+d+"";return[{type:"label",html:b.translate(["You are using {0}",e])},{type:"spacer",flex:1},{text:"Close",onclick:function(){this.parent().parent().close()}}]};return{makeRow:d}}),g("4",["6","7","8","9"],function(a,b,c,d){var e=function(a,e){return function(){a.windowManager.open({title:"Help",bodyType:"tabpanel",layout:"flex",body:[b.makeTab(),c.makeTab(a,e)],buttons:d.makeRow(),onPostRender:function(){var a=this.getEl("title");a.innerHTML='TinyMCE Logo'}})}};return{open:e}}),g("2",["4"],function(a){var b=function(b,c){b.addCommand("mceHelp",a.open(b,c))};return{register:b}}),g("3",["4"],function(a){var b=function(b,c){b.addButton("help",{icon:"help",onclick:a.open(b,c)}),b.addMenuItem("Help",{text:"Help",icon:"help",context:"help",onclick:a.open(b,c)})};return{register:b}}),g("0",["1","2","3","4"],function(a,b,c,d){return a.add("help",function(a,d){c.register(a,d),b.register(a,d),a.shortcuts.add("Alt+0","Open help dialog","mceHelp")}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=function(){},a=function(e){return function(){return e}};function l(r){for(var o=[],e=1;e'+v.translate(e.action)+""+e.shortcut+"";var t}).join("");return{title:"Handy Shortcuts",type:"container",style:"overflow-y: auto; overflow-x: hidden; max-height: 250px",items:[{type:"container",html:'
    "+e+"
    '+v.translate("Action")+""+v.translate("Shortcut")+"
    "}]}},S=Object.keys,O=[{key:"advlist",name:"Advanced List"},{key:"anchor",name:"Anchor"},{key:"autolink",name:"Autolink"},{key:"autoresize",name:"Autoresize"},{key:"autosave",name:"Autosave"},{key:"bbcode",name:"BBCode"},{key:"charmap",name:"Character Map"},{key:"code",name:"Code"},{key:"codesample",name:"Code Sample"},{key:"colorpicker",name:"Color Picker"},{key:"compat3x",name:"3.x Compatibility"},{key:"contextmenu",name:"Context Menu"},{key:"directionality",name:"Directionality"},{key:"emoticons",name:"Emoticons"},{key:"fullpage",name:"Full Page"},{key:"fullscreen",name:"Full Screen"},{key:"help",name:"Help"},{key:"hr",name:"Horizontal Rule"},{key:"image",name:"Image"},{key:"imagetools",name:"Image Tools"},{key:"importcss",name:"Import CSS"},{key:"insertdatetime",name:"Insert Date/Time"},{key:"legacyoutput",name:"Legacy Output"},{key:"link",name:"Link"},{key:"lists",name:"Lists"},{key:"media",name:"Media"},{key:"nonbreaking",name:"Nonbreaking"},{key:"noneditable",name:"Noneditable"},{key:"pagebreak",name:"Page Break"},{key:"paste",name:"Paste"},{key:"preview",name:"Preview"},{key:"print",name:"Print"},{key:"save",name:"Save"},{key:"searchreplace",name:"Search and Replace"},{key:"spellchecker",name:"Spell Checker"},{key:"tabfocus",name:"Tab Focus"},{key:"table",name:"Table"},{key:"template",name:"Template"},{key:"textcolor",name:"Text Color"},{key:"textpattern",name:"Text Pattern"},{key:"toc",name:"Table of Contents"},{key:"visualblocks",name:"Visual Blocks"},{key:"visualchars",name:"Visual Characters"},{key:"wordcount",name:"Word Count"}],T=l(function(e,o){return e.replace(/\$\{([^{}]*)\}/g,function(e,t){var n,r=o[t];return"string"==(n=typeof r)||"number"===n?r.toString():e})},'${name}'),P=function(t,n){return function(e,t){for(var n=0,r=e.length;n"+P(t,e)+""}),i=a.length,c=a.join("");return"

    "+v.translate(["Plugins installed ({0}):",i])+"

      "+c+"
    "},H=function(e){return{title:"Plugins",type:"container",style:"overflow-y: auto; overflow-x: hidden;",layout:"flex",padding:10,spacing:10,items:[(t=e,{type:"container",html:'
    '+_(t)+"
    ",flex:1}),{type:"container",html:'

    '+v.translate("Premium plugins:")+'

    • PowerPaste
    • Spell Checker Pro
    • Accessibility Checker
    • Advanced Code Editor
    • Enhanced Media Embed
    • Link Checker

    '+v.translate("Learn more...")+"

    ",flex:1}]};var t},F=tinymce.util.Tools.resolve("tinymce.EditorManager"),M=function(){var e,t,n='TinyMCE '+(e=F.majorVersion,t=F.minorVersion,0===e.indexOf("@")?"X.X.X":e+"."+t)+"";return[{type:"label",html:v.translate(["You are using {0}",n])},{type:"spacer",flex:1},{text:"Close",onclick:function(){this.parent().parent().close()}}]},E=function(e,t){return function(){e.windowManager.open({title:"Help",bodyType:"tabpanel",layout:"flex",body:[w(),H(e)],buttons:M(),onPostRender:function(){this.getEl("title").innerHTML='TinyMCE Logo'}})}},I=function(e,t){e.addCommand("mceHelp",E(e,t))},j=function(e,t){e.addButton("help",{icon:"help",onclick:E(e,t)}),e.addMenuItem("help",{text:"Help",icon:"help",context:"help",onclick:E(e,t)})};e.add("help",function(e,t){j(e,t),I(e,t),e.shortcuts.add("Alt+0","Open help dialog","mceHelp")})}(); \ No newline at end of file diff --git a/tools/tinymce/plugins/hr/plugin.min.js b/tools/tinymce/plugins/hr/plugin.min.js index c1dfdcade4..72bc2cabd1 100644 --- a/tools/tinymce/plugins/hr/plugin.min.js +++ b/tools/tinymce/plugins/hr/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i")})};return{register:a}}),g("3",[],function(){var a=function(a){a.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),a.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})};return{register:a}}),g("0",["1","2","3"],function(a,b,c){return a.add("hr",function(a){b.register(a),c.register(a)}),function(){}}),d("0")()}(); \ No newline at end of file +!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=function(n){n.addCommand("InsertHorizontalRule",function(){n.execCommand("mceInsertContent",!1,"
    ")})},o=function(n){n.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),n.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})};n.add("hr",function(n){t(n),o(n)})}(); \ No newline at end of file diff --git a/tools/tinymce/plugins/image/plugin.min.js b/tools/tinymce/plugins/image/plugin.min.js index bc46e5300a..23473aa76d 100644 --- a/tools/tinymce/plugins/image/plugin.min.js +++ b/tools/tinymce/plugins/image/plugin.min.js @@ -1 +1 @@ -!function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i0&&/^[0-9]+$/.test(a)&&(a+="px"),a},m=function(a){if(a.margin){var b=a.margin.split(" ");switch(b.length){case 1:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[0],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[0];break;case 2:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[1];break;case 3:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a["margin-left"]=a["margin-left"]||b[1];break;case 4:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a["margin-left"]=a["margin-left"]||b[3]}delete a.margin}return a},n=function(a,b){var c=g.getImageList(a);"string"==typeof c?f.send({url:c,success:function(a){b(JSON.parse(a))}}):"function"==typeof c?c(b):b(c)},o=function(a,b,c){function d(){c.onload=c.onerror=null,a.selection&&(a.selection.select(c),a.nodeChanged())}c.onload=function(){b.width||b.height||!g.hasDimensions(a)||a.dom.setAttribs(c,{width:c.clientWidth,height:c.clientHeight}),d()},c.onerror=d},p=function(a){return new d(function(b,d){var e=new c;e.onload=function(){b(e.result)},e.onerror=function(){d(c.error.message)},e.readAsDataURL(a)})};return{getImageSize:i,buildListItems:j,removePixelSuffix:k,addPixelSuffix:l,mergeMargins:m,createImageList:n,waitLoadImage:o,blobToDataUri:p}}),g("c",["a","b"],function(a,b){var c=function(c){return function(d){var e=c.dom,f=d.control.rootControl;if(a.hasAdvTab(c)){var g=f.toJSON(),h=e.parseStyle(g.style);f.find("#vspace").value(""),f.find("#hspace").value(""),h=b.mergeMargins(h),(h["margin-top"]&&h["margin-bottom"]||h["margin-right"]&&h["margin-left"])&&(h["margin-top"]===h["margin-bottom"]?f.find("#vspace").value(b.removePixelSuffix(h["margin-top"])):f.find("#vspace").value(""),h["margin-right"]===h["margin-left"]?f.find("#hspace").value(b.removePixelSuffix(h["margin-right"])):f.find("#hspace").value("")),h["border-width"]&&f.find("#border").value(b.removePixelSuffix(h["border-width"])),f.find("#style").value(e.serializeStyle(e.parseStyle(e.serializeStyle(h))))}}},d=function(a,b){return{title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox",onchange:c(a)},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:function(c){b(a,c.control.rootControl)}},items:[{label:"Vertical space",name:"vspace"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]}};return{makeTab:d}}),g("e",[],function(){var a=function(a,b){a.state.set("oldVal",a.value()),b.state.set("oldVal",b.value())},b=function(a,b){var c=a.find("#width")[0],d=a.find("#height")[0],e=a.find("#constrain")[0];c&&d&&e&&b(c,d,e.checked())},c=function(b,c,d){var e=b.state.get("oldVal"),f=c.state.get("oldVal"),g=b.value(),h=c.value();d&&e&&f&&g&&h&&(g!==e?(h=Math.round(g/e*h),isNaN(h)||c.value(h)):(g=Math.round(h/f*g),isNaN(g)||b.value(g))),a(b,c)},d=function(c){b(c,a)},e=function(a){b(a,c)},f=function(){var a=function(a){e(a.control.rootControl)};return{type:"container",label:"Dimensions",layout:"flex",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:5,size:5,onchange:a,ariaLabel:"Width"},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:5,size:5,onchange:a,ariaLabel:"Height"},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}};return{createUi:f,syncSize:d,updateSize:e}}),g("d",["7","a","b","e"],function(a,b,c,d){var e=function(e,f){var g,h,i,j=e.meta||{},k=e.control,l=k.rootControl,m=l.find("#image-list")[0];m&&m.value(f.convertURL(k.value(),"src")),a.each(j,function(a,b){l.find("#"+b).value(a)}),j.width||j.height||(g=f.convertURL(k.value(),"src"),h=b.getPrependUrl(f),i=new RegExp("^(?:[a-z]+:)?//","i"),h&&!i.test(g)&&g.substring(0,h.length)!==h&&(g=h+g),k.value(g),c.getImageSize(f.documentBaseURI.toAbsolute(k.value()),function(a){a.width&&a.height&&b.hasDimensions(f)&&(l.find("#width").value(a.width),l.find("#height").value(a.height),d.updateSize(l))}))},f=function(a){a.meta=a.control.rootControl.toJSON()},g=function(a,g){var h=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:function(b){e(b,a)},onbeforecall:f},g];return b.hasDescription(a)&&h.push({name:"alt",type:"textbox",label:"Image description"}),b.hasImageTitle(a)&&h.push({name:"title",type:"textbox",label:"Image Title"}),b.hasDimensions(a)&&h.push(d.createUi()),b.getClassList(a)&&h.push({name:"class",type:"listbox",label:"Class",values:c.buildListItems(b.getClassList(a),function(b){b.value&&(b.textStyle=function(){return a.formatter.getCssText({inline:"img",classes:[b.value]})})})}),b.hasImageCaption(a)&&h.push({name:"caption",type:"checkbox",label:"Caption"}),h},h=function(a,b){return{title:"General",type:"form",items:g(a,b)}};return{makeTab:h,getGeneralItems:g}}),g("k",["n"],function(a){var b=function(){return a.getOrDie("URL")},c=function(a){return b().createObjectURL(a)},d=function(a){b().revokeObjectURL(a)};return{createObjectURL:c,revokeObjectURL:d}}),g("l",["5"],function(a){return a("tinymce.ui.Factory")}),g("o",["n"],function(a){return function(){var b=a.getOrDie("XMLHttpRequest");return new b}}),h("p",window),g("m",["o","g","p","i","7"],function(a,b,c,d,e){var f=function(){},g=function(a,b){return a?a.replace(/\/$/,"")+"/"+b.replace(/^\//,""):b};return function(b){var h=function(d,e,f,h){var i,j;i=new a,i.open("POST",b.url),i.withCredentials=b.credentials,i.upload.onprogress=function(a){h(a.loaded/a.total*100)},i.onerror=function(){f("Image upload failed due to a XHR Transport error. Code: "+i.status)},i.onload=function(){var a;return i.status<200||i.status>=300?void f("HTTP Error: "+i.status):(a=JSON.parse(i.responseText),a&&"string"==typeof a.location?void e(g(b.basePath,a.location)):void f("Invalid JSON: "+i.responseText))},j=new c.FormData,j.append("file",d.blob(),d.filename()),i.send(j)},i=function(a,b){return new d(function(c,d){try{b(a,c,d,f)}catch(a){d(a.message)}})},j=function(a){return a===h},k=function(a){return!b.url&&j(b.handler)?d.reject("Upload url missing from the settings."):i(a,b.handler)};return b=e.extend({credentials:!1,handler:h},b),{upload:k}}}),g("f",["k","l","a","b","m"],function(a,b,c,d,e){var f=function(f){return function(g){var h=b.get("Throbber"),i=g.control.rootControl,j=new h(i.getEl()),k=g.control.value(),l=a.createObjectURL(k),m=new e({url:c.getUploadUrl(f),basePath:c.getUploadBasePath(f),credentials:c.getUploadCredentials(f),handler:c.getUploadHandler(f)}),n=function(){j.hide(),a.revokeObjectURL(l)};return j.show(),d.blobToDataUri(k).then(function(a){var b=f.editorUpload.blobCache.create({blob:k,blobUri:l,name:k.name?k.name.replace(/\.[^\.]+$/,""):null,base64:a.split(",")[1]});return m.upload(b).then(function(a){var b=i.find("#src");return b.value(a),i.find("tabpanel")[0].activateTab(0),b.fire("change"),n(),a})})["catch"](function(a){f.windowManager.alert(a),n()})}},g=".jpg,.jpeg,.png,.gif",h=function(a){return{title:"Upload",type:"form",layout:"flex",direction:"column",align:"stretch",padding:"20 20 20 20",items:[{type:"container",layout:"flex",direction:"column",align:"center",spacing:10,items:[{text:"Browse for an image",type:"browsebutton",accept:g,onchange:f(a)},{text:"OR",type:"label"}]},{text:"Drop an image here",type:"dropzone",accept:g,height:100,onchange:f(a)}]}};return{makeTab:h}}),g("6",["8","9","7","a","b","c","d","e","f"],function(a,b,c,d,e,f,g,h,i){return function(a){function b(b){function j(){var b,d;h.updateSize(l),k(a,l),p=c.extend(p,l.toJSON()),p.alt||(p.alt=""),p.title||(p.title=""),""===p.width&&(p.width=null),""===p.height&&(p.height=null),p.style||(p.style=null),p={src:p.src,alt:p.alt,title:p.title,width:p.width,height:p.height,style:p.style,caption:p.caption,"class":p["class"]},a.undoManager.transact(function(){if(p.src){if(""===p.title&&(p.title=null),m?q.setAttribs(m,p):(p.id="__mcenew",a.focus(),a.selection.setContent(q.createHTML("img",p)),m=q.get("__mcenew"),q.setAttrib(m,"id",null)),a.editorUpload.uploadImagesAuto(),p.caption===!1&&q.is(m.parentNode,"figure.image")&&(b=m.parentNode,q.insertAfter(m,b),q.remove(b)),p.caption!==!0)e.waitLoadImage(a,p,m);else if(!q.is(m.parentNode,"figure.image")){d=m,m=m.cloneNode(!0),b=q.create("figure",{"class":"image"}),b.appendChild(m),b.appendChild(q.create("figcaption",{contentEditable:!0},"Caption")),b.contentEditable=!1;var c=q.getParent(d,function(b){return a.schema.getTextBlockElements()[b.nodeName]});c?q.split(c,d,b):q.replace(b,d),a.selection.select(b)}}else if(m){var f=q.is(m.parentNode,"figure.image")?m.parentNode:m;q.remove(f),a.focus(),a.nodeChanged(),q.isEmpty(a.getBody())&&(a.setContent(""),a.selection.setCursorLocation())}})}var l,m,n,o,p={},q=a.dom;if(m=a.selection.getNode(),n=q.getParent(m,"figure.image"),n&&(m=q.select("img",n)[0]),m&&("IMG"!==m.nodeName||m.getAttribute("data-mce-object")||m.getAttribute("data-mce-placeholder"))&&(m=null),m&&(p={src:q.getAttrib(m,"src"),alt:q.getAttrib(m,"alt"),title:q.getAttrib(m,"title"),"class":q.getAttrib(m,"class"),width:q.getAttrib(m,"width"),height:q.getAttrib(m,"height"),caption:!!n}),b&&(o={type:"listbox",label:"Image list",name:"image-list",values:e.buildListItems(b,function(b){b.value=a.convertURL(b.value||b.url,"src")},[{text:"None",value:""}]),value:p.src&&a.convertURL(p.src,"src"),onselect:function(a){var b=l.find("#alt");(!b.value()||a.lastControl&&b.value()===a.lastControl.text())&&b.value(a.control.text()),l.find("#src").value(a.control.value()).fire("change")},onPostRender:function(){o=this}}),d.hasAdvTab(a)||d.hasUploadUrl(a)||d.hasUploadHandler(a)){var r=[g.makeTab(a,o)];d.hasAdvTab(a)&&(m&&(m.style.marginLeft&&m.style.marginRight&&m.style.marginLeft===m.style.marginRight&&(p.hspace=e.removePixelSuffix(m.style.marginLeft)),m.style.marginTop&&m.style.marginBottom&&m.style.marginTop===m.style.marginBottom&&(p.vspace=e.removePixelSuffix(m.style.marginTop)),m.style.borderWidth&&(p.border=e.removePixelSuffix(m.style.borderWidth)),p.style=a.dom.serializeStyle(a.dom.parseStyle(a.dom.getAttrib(m,"style")))),r.push(f.makeTab(a,k))),(d.hasUploadUrl(a)||d.hasUploadHandler(a))&&r.push(i.makeTab(a)),l=a.windowManager.open({title:"Insert/edit image",data:p,bodyType:"tabpanel",body:r,onSubmit:j})}else l=a.windowManager.open({title:"Insert/edit image",data:p,body:g.getGeneralItems(a,o),onSubmit:j});h.syncSize(l)}function j(){e.createImageList(a,b)}var k=function(a,b){if(d.hasAdvTab(a)){var c=a.dom,f=b.toJSON(),g=c.parseStyle(f.style);g=e.mergeMargins(g),f.vspace&&(g["margin-top"]=g["margin-bottom"]=e.addPixelSuffix(f.vspace)),f.hspace&&(g["margin-left"]=g["margin-right"]=e.addPixelSuffix(f.hspace)),f.border&&(g["border-width"]=e.addPixelSuffix(f.border)),b.find("#style").value(c.serializeStyle(c.parseStyle(c.serializeStyle(g))))}};return{open:j}}}),g("2",["6"],function(a){var b=function(b){b.addCommand("mceImage",a(b).open)};return{register:b}}),g("3",["7"],function(a){var b=function(a){var b=a.attr("class");return b&&/\bimage\b/.test(b)},c=function(c){return function(d){for(var e,f=d.length,g=function(a){a.attr("contenteditable",c?"true":null)};f--;)e=d[f],b(e)&&(e.attr("contenteditable",c?"false":null),a.each(e.getAll("figcaption"),g))}},d=function(a){a.on("preInit",function(){a.parser.addNodeFilter("figure",c(!0)),a.serializer.addNodeFilter("figure",c(!1))})};return{setup:d}}),g("4",["6"],function(a){var b=function(b){b.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:a(b).open,stateSelector:"img:not([data-mce-object],[data-mce-placeholder]),figure.image"}),b.addMenuItem("image",{icon:"image",text:"Image",onclick:a(b).open,context:"insert",prependToContext:!0})};return{register:b}}),g("0",["1","2","3","4"],function(a,b,c,d){return a.add("image",function(a){c.setup(a),d.register(a),b.register(a)}),function(){}}),d("0")()}(); \ No newline at end of file +!function(l){"use strict";var i,e=tinymce.util.Tools.resolve("tinymce.PluginManager"),d=function(e){return!1!==e.settings.image_dimensions},u=function(e){return!0===e.settings.image_advtab},m=function(e){return e.getParam("image_prepend_url","")},n=function(e){return e.getParam("image_class_list")},r=function(e){return!1!==e.settings.image_description},a=function(e){return!0===e.settings.image_title},o=function(e){return!0===e.settings.image_caption},c=function(e){return e.getParam("image_list",!1)},s=function(e){return e.getParam("images_upload_url",!1)},g=function(e){return e.getParam("images_upload_handler",!1)},f=function(e){return e.getParam("images_upload_url")},p=function(e){return e.getParam("images_upload_handler")},h=function(e){return e.getParam("images_upload_base_path")},v=function(e){return e.getParam("images_upload_credentials")},b="undefined"!=typeof l.window?l.window:Function("return this;")(),y=function(e,t){return function(e,t){for(var n=t!==undefined&&null!==t?t:b,r=0;rc?a=c:a0?3*d:d),f=.3086,g=.6094,h=.082,c(b,[f*(1-e)+e,g*(1-e),h*(1-e),0,0,f*(1-e),g*(1-e)+e,h*(1-e),0,0,f*(1-e),g*(1-e),h*(1-e)+e,0,0,0,0,0,1,0,0,0,0,0,1])}function g(b,d){var e,f,g,h,i;return d=a(d,-180,180)/180*Math.PI,e=Math.cos(d),f=Math.sin(d),g=.213,h=.715,i=.072,c(b,[g+e*(1-g)+f*-g,h+e*-h+f*-h,i+e*-i+f*(1-i),0,0,g+e*-g+.143*f,h+e*(1-h)+.14*f,i+e*-i+f*-.283,0,0,g+e*-g+f*-(1-g),h+e*-h+f*h,i+e*(1-i)+f*i,0,0,0,0,0,1,0,0,0,0,0,1])}function h(b,d){return d=a(255*d,-255,255),c(b,[1,0,0,0,d,0,1,0,0,d,0,0,1,0,d,0,0,0,1,0,0,0,0,0,1])}function i(b,d,e,f){return d=a(d,0,2),e=a(e,0,2),f=a(f,0,2),c(b,[d,0,0,0,0,0,e,0,0,0,0,0,f,0,0,0,0,0,1,0,0,0,0,0,1])}function j(b,e){return e=a(e,0,1),c(b,d([.393,.769,.189,0,0,.349,.686,.168,0,0,.272,.534,.131,0,0,0,0,0,1,0,0,0,0,0,1],e))}function k(b,e){return e=a(e,0,1),c(b,d([.33,.34,.33,0,0,.33,.34,.33,0,0,.33,.34,.33,0,0,0,0,0,1,0,0,0,0,0,1],e))}var l=[0,.01,.02,.04,.05,.06,.07,.08,.1,.11,.12,.14,.15,.16,.17,.18,.2,.21,.22,.24,.25,.27,.28,.3,.32,.34,.36,.38,.4,.42,.44,.46,.48,.5,.53,.56,.59,.62,.65,.68,.71,.74,.77,.8,.83,.86,.89,.92,.95,.98,1,1.06,1.12,1.18,1.24,1.3,1.36,1.42,1.48,1.54,1.6,1.66,1.72,1.78,1.84,1.9,1.96,2,2.12,2.25,2.37,2.5,2.62,2.75,2.87,3,3.2,3.4,3.6,3.8,4,4.3,4.7,4.9,5,5.5,6,6.5,6.8,7,7.3,7.5,7.8,8,8.4,8.7,9,9.4,9.6,9.8,10];return{identity:b,adjust:d,multiply:c,adjustContrast:e,adjustBrightness:h,adjustSaturation:f,adjustHue:g,adjustColors:i,adjustSepia:j,adjustGrayscale:k}}),g("r",["13","t","1b"],function(a,b,c){function d(a,b){return a.toCanvas().then(function(c){return e(c,a.getType(),b)})}function e(c,d,e){function f(a,b){var c,d,e,f,g,h=a.data,i=b[0],j=b[1],k=b[2],l=b[3],m=b[4],n=b[5],o=b[6],p=b[7],q=b[8],r=b[9],s=b[10],t=b[11],u=b[12],v=b[13],w=b[14],x=b[15],y=b[16],z=b[17],A=b[18],B=b[19];for(g=0;gc?a=c:a2)&&(i=i<.5?.5:2,k=!0),(j<.5||j>2)&&(j=j<.5?.5:2,k=!0);var l=e(a,i,j);return k?l.then(function(a){return d(a,c,f)}):l}function e(d,e,f){return new c(function(c){var g=b.getWidth(d),h=b.getHeight(d),i=Math.floor(g*e),j=Math.floor(h*f),k=a.create(i,j),l=a.get2dContext(k);l.drawImage(d,0,0,g,h,0,0,i,j),c(k)})}return{scale:d}}),g("s",["13","t","1c"],function(a,b,c){function d(a,b){return a.toCanvas().then(function(c){return e(c,a.getType(),b)})}function e(c,d,e){var f=a.create(c.width,c.height),g=a.get2dContext(f),h=0,i=0;return e=e<0?360+e:e,90!=e&&270!=e||a.resize(f,f.height,f.width),90!=e&&180!=e||(h=f.width),270!=e&&180!=e||(i=f.height),g.translate(h,i),g.rotate(e*Math.PI/180),g.drawImage(c,0,0),b.fromCanvas(f,d)}function f(a,b){return a.toCanvas().then(function(c){return g(c,a.getType(),b)})}function g(c,d,e){var f=a.create(c.width,c.height),g=a.get2dContext(f);return"v"==e?(g.scale(1,-1),g.drawImage(c,0,-f.height)):(g.scale(-1,1),g.drawImage(c,-f.width,0)),b.fromCanvas(f,d)}function h(a,b,c,d,e){return a.toCanvas().then(function(f){return i(f,a.getType(),b,c,d,e)})}function i(c,d,e,f,g,h){var i=a.create(g,h),j=a.get2dContext(i);return j.drawImage(c,-e,-f),b.fromCanvas(i,d)}function j(a,d,e){return a.toCanvas().then(function(f){return c.scale(f,d,e).then(function(c){return b.fromCanvas(c,a.getType())})})}return{rotate:d,flip:f,crop:h,resize:j}}),g("d",["r","s"],function(a,b){var c=function(b){return a.invert(b)},d=function(b){return a.sharpen(b)},e=function(b){return a.emboss(b)},f=function(b,c){return a.gamma(b,c)},g=function(b,c){return a.exposure(b,c)},h=function(b,c,d,e){return a.colorize(b,c,d,e)},i=function(b,c){return a.brightness(b,c)},j=function(b,c){return a.hue(b,c)},k=function(b,c){return a.saturate(b,c)},l=function(b,c){return a.contrast(b,c)},m=function(b,c){return a.grayscale(b,c)},n=function(b,c){return a.sepia(b,c)},o=function(a,c){return b.flip(a,c)},p=function(a,c,d,e,f){return b.crop(a,c,d,e,f)},q=function(a,c,d){return b.resize(a,c,d)},r=function(a,c){return b.rotate(a,c)};return{invert:c,sharpen:d,emboss:e,brightness:i,hue:j,saturate:k,contrast:l,grayscale:m,sepia:n,colorize:h,gamma:f,exposure:g,flip:o,crop:p,resize:q,rotate:r}}),g("e",["t"],function(a){var b=function(b){return a.fromBlob(b)},c=function(b,c){return a.fromBlobAndUrlSync(b,c)},d=function(b){return a.fromImage(b)},e=function(a,b,c){return void 0===b&&void 0===c?f(a):a.toAdjustedBlob(b,c)},f=function(a){return a.toBlob()},g=function(a){return a.toDataURL()};return{blobToImageResult:b,fromBlobAndUrlSync:c,imageToImageResult:d,imageResultToBlob:e,imageResultToOriginalBlob:f,imageResultToDataURL:g}}),g("h",["u"],function(a){var b=function(){return a.getOrDie("URL")},c=function(a){return b().createObjectURL(a)},d=function(a){b().revokeObjectURL(a)};return{createObjectURL:c,revokeObjectURL:d}}),h("i",clearTimeout),g("j",["7"],function(a){return a("tinymce.util.Delay")}),g("k",["7"],function(a){return a("tinymce.util.Promise")}),g("l",["7"],function(a){return a("tinymce.util.URI")}),g("b",[],function(){var a=function(a){return a.getParam("imagetools_toolbar","rotateleft rotateright | flipv fliph | crop editimage imageoptions")},b=function(a){return a.getParam("imagetools_proxy")};return{getToolbarItems:a,getProxyUrl:b}}),g("m",[],function(){function a(a){function b(a){return/^[0-9\.]+px$/.test(a)}var c,d;return c=a.style.width,d=a.style.height,c||d?b(c)&&b(d)?{w:parseInt(c,10),h:parseInt(d,10)}:null:(c=a.width,d=a.height,c&&d?{w:parseInt(c,10),h:parseInt(d,10)}:null)}function b(a,b){var c,d;b&&(c=a.style.width,d=a.style.height,(c||d)&&(a.style.width=b.w+"px",a.style.height=b.h+"px",a.removeAttribute("data-mce-style")),c=a.width,d=a.height,(c||d)&&(a.setAttribute("width",b.w),a.setAttribute("height",b.h)))}function c(a){return{w:a.naturalWidth,h:a.naturalHeight}}return{getImageSize:a,setImageSize:b,getNaturalImageSize:c}}),h("1m",String),g("1e",["q","f","g","1m"],function(a,b,c,d){var e=function(){var a=b.prototype.indexOf,c=function(b,c){return a.call(b,c)},d=function(a,b){return u(a,b)};return void 0===a?d:c}(),f=function(b,c){var d=e(b,c);return d===-1?a.none():a.some(d)},g=function(a,b){return e(a,b)>-1},h=function(a,b){return t(a,b).isSome()},i=function(a,b){for(var c=[],d=0;d=0;c--){var d=a[c];b(d,c,a)}},n=function(a,b){for(var c=[],d=[],e=0,f=a.length;e=300?c.handleHttpError(b.status):a.resolve(b.blob)})}var f=function(a,b){var c=a.indexOf("?")===-1?"?":"&";return/[?&]apiKey=/.test(a)||!b?a:a+c+"apiKey="+encodeURIComponent(b)},g=function(b,e){return d.requestUrlAsBlob(f(b,e),{"Content-Type":"application/json;charset=UTF-8","tiny-api-key":e}).then(function(b){return b.status<200||b.status>=300?c.handleServiceErrorResponse(b.status,b.blob):a.resolve(b.blob)})},h=function(a,b){return b?g(a,b):e(a)};return{getUrl:h}}),h("y",setTimeout),g("z",["7"],function(a){return a("tinymce.dom.DOMUtils")}),g("10",["7"],function(a){return a("tinymce.ui.Factory")}),g("11",[],function(){return function(){function a(a){var b;return b=f.splice(++g),f.push(a),{state:a,removed:b}}function b(){if(d())return f[--g]}function c(){if(e())return f[++g]}function d(){return g>0}function e(){return g!==-1&&g').appendTo(k),e.each(B,function(b){a("#"+D,k).append('