diff --git a/composer.json b/composer.json index eabd6a12..d4e3e364 100644 --- a/composer.json +++ b/composer.json @@ -6,9 +6,10 @@ "ext-mbstring": ">=5.4", "ext-gd": ">=5.4", "ext-pdo": ">=5.4", - "twig/twig": "^2.14.11", + "twig/twig": "^2.9", + "phpmyadmin/twig-i18n-extension": "^4.0", "lifo/ip": "^1.0", - "gettext/gettext": "^1.0", + "gettext/gettext": "^5.5", "mrclay/minify": "^2.1.6", "geoip/geoip": "^1.17", "dapphp/securimage": "^4.0" diff --git a/composer.lock b/composer.lock index 171e053e..742c3cfc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1e3723687369c82eea457d2dded76b74", + "content-hash": "72e79f203581eea6e6b0455147b25878", "packages": [ { "name": "dapphp/securimage", @@ -31,12 +31,12 @@ }, "type": "library", "autoload": { - "classmap": [ - "securimage.php" - ], "psr-4": { "Securimage\\": "./" - } + }, + "classmap": [ + "securimage.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -114,37 +114,43 @@ "issues": "https://github.com/maxmind/geoip-api-php/issues", "source": "https://github.com/maxmind/geoip-api-php/tree/master" }, + "abandoned": "geoip2/geoip2", "time": "2016-05-16T19:06:50+00:00" }, { "name": "gettext/gettext", - "version": "v1.1.5", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/php-gettext/Gettext.git", - "reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c" + "reference": "8657e580747bb3baacccdcebe69cac094661e404" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-gettext/Gettext/zipball/1bdf755a1b49f0614d6fc29f446df567eb62cd5c", - "reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c", + "url": "https://api.github.com/repos/php-gettext/Gettext/zipball/8657e580747bb3baacccdcebe69cac094661e404", + "reference": "8657e580747bb3baacccdcebe69cac094661e404", "shasum": "" }, "require": { - "php": ">=5.3.0" + "gettext/languages": "^2.3", + "php": "^7.2|^8.0" + }, + "require-dev": { + "brick/varexporter": "^0.3.5", + "friendsofphp/php-cs-fixer": "^3.2", + "oscarotero/php-cs-fixer-config": "^2.0", + "phpunit/phpunit": "^8.0|^9.0", + "squizlabs/php_codesniffer": "^3.0" }, "type": "library", "autoload": { - "psr-0": { - "Gettext": "" - }, - "files": [ - "Gettext/translator_functions.php" - ] + "psr-4": { + "Gettext\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "AGPL-3.0" + "MIT" ], "authors": [ { @@ -154,33 +160,123 @@ "role": "Developer" } ], - "description": "PHP - JS gettext conversor", - "homepage": "https://github.com/oscarotero/Gettext", + "description": "PHP gettext manager", + "homepage": "https://github.com/php-gettext/Gettext", "keywords": [ "JS", "gettext", "i18n", + "mo", + "po", "translation" ], "support": { "email": "oom@oscarotero.com", - "issues": "https://github.com/oscarotero/Gettext/issues", - "source": "https://github.com/php-gettext/Gettext/tree/v1.1.5" + "issues": "https://github.com/php-gettext/Gettext/issues", + "source": "https://github.com/php-gettext/Gettext/tree/v5.7.0" }, - "time": "2014-10-22T15:53:45+00:00" + "funding": [ + { + "url": "https://paypal.me/oscarotero", + "type": "custom" + }, + { + "url": "https://github.com/oscarotero", + "type": "github" + }, + { + "url": "https://www.patreon.com/misteroom", + "type": "patreon" + } + ], + "time": "2022-07-27T19:54:55+00:00" + }, + { + "name": "gettext/languages", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/php-gettext/Languages.git", + "reference": "4d61d67fe83a2ad85959fe6133d6d9ba7dddd1ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-gettext/Languages/zipball/4d61d67fe83a2ad85959fe6133d6d9ba7dddd1ab", + "reference": "4d61d67fe83a2ad85959fe6133d6d9ba7dddd1ab", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4" + }, + "bin": [ + "bin/export-plural-rules" + ], + "type": "library", + "autoload": { + "psr-4": { + "Gettext\\Languages\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michele Locati", + "email": "mlocati@gmail.com", + "role": "Developer" + } + ], + "description": "gettext languages with plural rules", + "homepage": "https://github.com/php-gettext/Languages", + "keywords": [ + "cldr", + "i18n", + "internationalization", + "l10n", + "language", + "languages", + "localization", + "php", + "plural", + "plural rules", + "plurals", + "translate", + "translations", + "unicode" + ], + "support": { + "issues": "https://github.com/php-gettext/Languages/issues", + "source": "https://github.com/php-gettext/Languages/tree/2.10.0" + }, + "funding": [ + { + "url": "https://paypal.me/mlocati", + "type": "custom" + }, + { + "url": "https://github.com/mlocati", + "type": "github" + } + ], + "time": "2022-10-18T15:00:10+00:00" }, { "name": "lifo/ip", - "version": "v1.1", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/lifo101/ip.git", - "reference": "b6a36dab288d7aea155698808bfc6649799fe413" + "reference": "4c4cf5b554884be93f1d0422eaec8d6426993229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lifo101/ip/zipball/b6a36dab288d7aea155698808bfc6649799fe413", - "reference": "b6a36dab288d7aea155698808bfc6649799fe413", + "url": "https://api.github.com/repos/lifo101/ip/zipball/4c4cf5b554884be93f1d0422eaec8d6426993229", + "reference": "4c4cf5b554884be93f1d0422eaec8d6426993229", "shasum": "" }, "require": { @@ -212,9 +308,9 @@ ], "support": { "issues": "https://github.com/lifo101/ip/issues", - "source": "https://github.com/lifo101/ip/tree/master" + "source": "https://github.com/lifo101/ip/tree/v1.1.1" }, - "time": "2020-04-02T11:09:10+00:00" + "time": "2022-07-12T15:45:54+00:00" }, { "name": "mrclay/minify", @@ -267,30 +363,89 @@ }, "time": "2017-11-03T21:04:01+00:00" }, + { + "name": "phpmyadmin/twig-i18n-extension", + "version": "v4.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpmyadmin/twig-i18n-extension.git", + "reference": "c0d0dd171cd1c7733bf152fd44b61055843df052" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpmyadmin/twig-i18n-extension/zipball/c0d0dd171cd1c7733bf152fd44b61055843df052", + "reference": "c0d0dd171cd1c7733bf152fd44b61055843df052", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "twig/twig": "^1.42.3|^2.0|^3.0" + }, + "require-dev": { + "phpmyadmin/coding-standard": "^3.0.0", + "phpmyadmin/motranslator": "^5.2", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7 || ^8 || ^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpMyAdmin\\Twig\\Extensions\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "The phpMyAdmin Team", + "email": "developers@phpmyadmin.net", + "homepage": "https://www.phpmyadmin.net/team/" + } + ], + "description": "Internationalization support for Twig via the gettext library", + "keywords": [ + "gettext", + "i18n" + ], + "support": { + "issues": "https://github.com/phpmyadmin/twig-i18n-extension/issues", + "source": "https://github.com/phpmyadmin/twig-i18n-extension" + }, + "time": "2021-06-10T15:53:38+00:00" + }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -298,12 +453,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -328,7 +483,166 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" }, "funding": [ { @@ -344,34 +658,36 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "twig/twig", - "version": "v2.14.11", + "version": "v2.15.4", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "dd4353357c5a116322e92a00d16043a31881a81e" + "reference": "3e059001d6d597dd50ea7c74dd2464b4adea48d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/dd4353357c5a116322e92a00d16043a31881a81e", - "reference": "dd4353357c5a116322e92a00d16043a31881a81e", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3e059001d6d597dd50ea7c74dd2464b4adea48d3", + "reference": "3e059001d6d597dd50ea7c74dd2464b4adea48d3", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "^1.8" + "php": ">=7.1.3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.8" }, "require-dev": { "psr/container": "^1.0", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9" + "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.44-dev" + "dev-master": "2.15-dev" } }, "autoload": { @@ -410,7 +726,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v2.14.11" + "source": "https://github.com/twigphp/Twig/tree/v2.15.4" }, "funding": [ { @@ -422,7 +738,7 @@ "type": "tidelift" } ], - "time": "2021-09-17T08:35:19+00:00" + "time": "2022-12-27T12:26:20+00:00" } ], "packages-dev": [], @@ -437,5 +753,5 @@ "ext-pdo": ">=5.4" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.3.0" } diff --git a/inc/cache.php b/inc/cache.php index 85ef9d5a..1614326a 100644 --- a/inc/cache.php +++ b/inc/cache.php @@ -186,3 +186,30 @@ class Cache { } } +class Twig_Cache_TinyboardFilesystem extends Twig\Cache\FilesystemCache +{ + private $directory; + private $options; + + /** + * {@inheritdoc} + */ + public function __construct($directory, $options = 0) + { + parent::__construct($directory, $options); + + $this->directory = $directory; + } + + /** + * This function was removed in Twig 2.x due to developer views on the Twig library. Who says we can't keep it for ourselves though? + */ + public function clear() + { + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->directory), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + if ($file->isFile()) { + @unlink($file->getPathname()); + } + } + } +} \ No newline at end of file diff --git a/inc/config.php b/inc/config.php index 39263702..9f093021 100644 --- a/inc/config.php +++ b/inc/config.php @@ -47,6 +47,8 @@ $config['verbose_errors'] = false; // Warn about deprecations? See vichan-devel/vichan#363 and https://www.youtube.com/watch?v=9crnlHLVdno $config['deprecation_errors'] = false; + // Skip cache in twig. this is already enabled with debug + $config['twig_auto_reload'] = true; // EXPLAIN all SQL queries (when in debug mode). $config['debug_explain'] = false; diff --git a/inc/lib/twig/extensions/Extension/I18n.php b/inc/lib/twig/extensions/Extension/I18n.php deleted file mode 100644 index 897add6f..00000000 --- a/inc/lib/twig/extensions/Extension/I18n.php +++ /dev/null @@ -1,31 +0,0 @@ - $length) { - if ($preserve) { - if (false !== ($breakpoint = mb_strpos($value, ' ', $length))) { - $length = $breakpoint; - } - } - return mb_substr($value, 0, $length) . $separator; - } - return $value; -} - -function twig_filename_truncate_filter($value, $length = 30, $separator = '…') { - if (mb_strlen($value) > $length) { - $value = strrev($value); - $array = array_reverse(explode(".", $value, 2)); - $array = array_map("strrev", $array); - - $filename = &$array[0]; - $extension = isset($array[1]) ? $array[1] : false; - - $filename = mb_substr($filename, 0, $length - ($extension ? mb_strlen($extension) + 1 : 0)) . $separator; - - return implode(".", $array); - } - return $value; -} - -function twig_ratio_function($w, $h) { - return fraction($w, $h, ':'); -} -function twig_secure_link_confirm($text, $title, $confirm_message, $href) { - global $config; - - return '' . $text . ''; -} -function twig_secure_link($href) { - return $href . '/' . make_secure_link_token($href); -} diff --git a/inc/lib/twig/extensions/Node/Trans.php b/inc/lib/twig/extensions/Node/Trans.php deleted file mode 100644 index 506046a1..00000000 --- a/inc/lib/twig/extensions/Node/Trans.php +++ /dev/null @@ -1,160 +0,0 @@ - - */ -class TransNode extends Node -{ - public function __construct(Node $body, Node $plural = null, AbstractExpression $count = null, Node $notes = null, $lineno, $tag = null) - { - $nodes = ['body' => $body]; - if (null !== $count) { - $nodes['count'] = $count; - } - if (null !== $plural) { - $nodes['plural'] = $plural; - } - if (null !== $notes) { - $nodes['notes'] = $notes; - } - - parent::__construct($nodes, [], $lineno, $tag); - } - - public function compile(Compiler $compiler) - { - $compiler->addDebugInfo($this); - - list($msg, $vars) = $this->compileString($this->getNode('body')); - - if ($this->hasNode('plural')) { - list($msg1, $vars1) = $this->compileString($this->getNode('plural')); - - $vars = array_merge($vars, $vars1); - } - - $function = $this->getTransFunction($this->hasNode('plural')); - - if ($this->hasNode('notes')) { - $message = trim($this->getNode('notes')->getAttribute('data')); - - // line breaks are not allowed cause we want a single line comment - $message = str_replace(["\n", "\r"], ' ', $message); - $compiler->write("// notes: {$message}\n"); - } - - if ($vars) { - $compiler - ->write('echo strtr('.$function.'(') - ->subcompile($msg) - ; - - if ($this->hasNode('plural')) { - $compiler - ->raw(', ') - ->subcompile($msg1) - ->raw(', abs(') - ->subcompile($this->hasNode('count') ? $this->getNode('count') : null) - ->raw(')') - ; - } - - $compiler->raw('), array('); - - foreach ($vars as $var) { - if ('count' === $var->getAttribute('name')) { - $compiler - ->string('%count%') - ->raw(' => abs(') - ->subcompile($this->hasNode('count') ? $this->getNode('count') : null) - ->raw('), ') - ; - } else { - $compiler - ->string('%'.$var->getAttribute('name').'%') - ->raw(' => ') - ->subcompile($var) - ->raw(', ') - ; - } - } - - $compiler->raw("));\n"); - } else { - $compiler - ->write('echo '.$function.'(') - ->subcompile($msg) - ; - - if ($this->hasNode('plural')) { - $compiler - ->raw(', ') - ->subcompile($msg1) - ->raw(', abs(') - ->subcompile($this->hasNode('count') ? $this->getNode('count') : null) - ->raw(')') - ; - } - - $compiler->raw(");\n"); - } - } - - private function compileString(Node $body): array - { - if ($body instanceof NameExpression || $body instanceof ConstantExpression || $body instanceof TempNameExpression) { - return [$body, []]; - } - - $vars = []; - if (\count($body)) { - $msg = ''; - - foreach ($body as $node) { - if ($node instanceof PrintNode) { - $n = $node->getNode('expr'); - while ($n instanceof FilterExpression) { - $n = $n->getNode('node'); - } - while ($n instanceof CheckToStringNode) { - $n = $n->getNode('expr'); - } - $msg .= sprintf('%%%s%%', $n->getAttribute('name')); - $vars[] = new NameExpression($n->getAttribute('name'), $n->getTemplateLine()); - } else { - $msg .= $node->getAttribute('data'); - } - } - } else { - $msg = $body->getAttribute('data'); - } - - return [new Node([new ConstantExpression(trim($msg), $body->getTemplateLine())]), $vars]; - } - - private function getTransFunction(bool $plural): string - { - return $plural ? 'ngettext' : 'gettext'; - } -} diff --git a/inc/lib/twig/extensions/TokenParser/Trans.php b/inc/lib/twig/extensions/TokenParser/Trans.php deleted file mode 100644 index bf8eefba..00000000 --- a/inc/lib/twig/extensions/TokenParser/Trans.php +++ /dev/null @@ -1,91 +0,0 @@ -getLine(); - $stream = $this->parser->getStream(); - $count = null; - $plural = null; - $notes = null; - - if (!$stream->test(Token::BLOCK_END_TYPE)) { - $body = $this->parser->getExpressionParser()->parseExpression(); - } else { - $stream->expect(Token::BLOCK_END_TYPE); - $body = $this->parser->subparse([$this, 'decideForFork']); - $next = $stream->next()->getValue(); - - if ('plural' === $next) { - $count = $this->parser->getExpressionParser()->parseExpression(); - $stream->expect(Token::BLOCK_END_TYPE); - $plural = $this->parser->subparse([$this, 'decideForFork']); - - if ('notes' === $stream->next()->getValue()) { - $stream->expect(Token::BLOCK_END_TYPE); - $notes = $this->parser->subparse([$this, 'decideForEnd'], true); - } - } elseif ('notes' === $next) { - $stream->expect(Token::BLOCK_END_TYPE); - $notes = $this->parser->subparse([$this, 'decideForEnd'], true); - } - } - - $stream->expect(Token::BLOCK_END_TYPE); - - $this->checkTransString($body, $lineno); - - return new TransNode($body, $plural, $count, $notes, $lineno, $this->getTag()); - } - - public function decideForFork(Token $token) - { - return $token->test(['plural', 'notes', 'endtrans']); - } - - public function decideForEnd(Token $token) - { - return $token->test('endtrans'); - } - - public function getTag() - { - return 'trans'; - } - - private function checkTransString(Node $body, $lineno) - { - foreach ($body as $i => $node) { - if ( - $node instanceof TextNode - || - ($node instanceof PrintNode && $node->getNode('expr') instanceof NameExpression) - ) { - continue; - } - - throw new SyntaxError(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $lineno); - } - } -} diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 62b32965..b48cf340 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -3073,7 +3073,11 @@ function mod_rebuild() { $log[] = 'Clearing template cache'; load_twig(); +<<<<<<< HEAD $twig->clearCacheFiles(); +======= + $twig->getCache()->clear(); +>>>>>>> 6e5bc92d (update twig to 2.9) } if (isset($_POST['rebuild_themes'])) { diff --git a/inc/template.php b/inc/template.php index 1d08cc61..49a04fcf 100644 --- a/inc/template.php +++ b/inc/template.php @@ -15,11 +15,14 @@ function load_twig() { $twig = new Twig\Environment($loader, array( 'autoescape' => false, 'cache' => is_writable('templates') || (is_dir('templates/cache') && is_writable('templates/cache')) ? - "{$config['dir']['template']}/cache" : false, - 'debug' => $config['debug'] + new Twig_Cache_TinyboardFilesystem("{$config['dir']['template']}/cache") : false, + 'debug' => $config['debug'], + 'auto_reload' => $config['twig_auto_reload'] )); - $twig->addExtension(new Twig_Extensions_Extension_Tinyboard()); - $twig->addExtension(new Twig\Extensions\I18nExtension()); + if ($config['debug']) + $twig->addExtension(new \Twig\Extension\DebugExtension()); + $twig->addExtension(new Tinyboard()); + $twig->addExtension(new PhpMyAdmin\Twig\Extensions\I18nExtension()); } function Element($templateFile, array $options) { @@ -67,3 +70,138 @@ function Element($templateFile, array $options) { } } +class Tinyboard extends Twig\Extension\AbstractExtension +{ + /** + * Returns a list of filters to add to the existing list. + * + * @return array An array of filters + */ + public function getFilters() + { + return array( + new Twig\TwigFilter('filesize', 'format_bytes'), + new Twig\TwigFilter('truncate', 'twig_truncate_filter'), + new Twig\TwigFilter('truncate_body', 'truncate'), + new Twig\TwigFilter('truncate_filename', 'twig_filename_truncate_filter'), + new Twig\TwigFilter('extension', 'twig_extension_filter'), + new Twig\TwigFilter('sprintf', 'sprintf'), + new Twig\TwigFilter('capcode', 'capcode'), + new Twig\TwigFilter('remove_modifiers', 'remove_modifiers'), + new Twig\TwigFilter('hasPermission', 'twig_hasPermission_filter'), + new Twig\TwigFilter('date', 'twig_date_filter'), + new Twig\TwigFilter('poster_id', 'poster_id'), + new Twig\TwigFilter('remove_whitespace', 'twig_remove_whitespace_filter'), + new Twig\TwigFilter('count', 'count'), + new Twig\TwigFilter('ago', 'ago'), + new Twig\TwigFilter('until', 'until'), + new Twig\TwigFilter('push', 'twig_push_filter'), + new Twig\TwigFilter('bidi_cleanup', 'bidi_cleanup'), + new Twig\TwigFilter('addslashes', 'addslashes'), + new Twig\TwigFilter('cloak_ip', 'cloak_ip'), + new Twig\TwigFilter('cloak_mask', 'cloak_mask'), + ); + } + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of filters + */ + public function getFunctions() + { + return array( + new Twig\TwigFunction('time', 'time'), + new Twig\TwigFunction('floor', 'floor'), + new Twig\TwigFunction('timezone', 'twig_timezone_function'), + new Twig\TwigFunction('hiddenInputs', 'hiddenInputs'), + new Twig\TwigFunction('hiddenInputsHash', 'hiddenInputsHash'), + new Twig\TwigFunction('ratio', 'twig_ratio_function'), + new Twig\TwigFunction('secure_link_confirm', 'twig_secure_link_confirm'), + new Twig\TwigFunction('secure_link', 'twig_secure_link'), + new Twig\TwigFunction('link_for', 'link_for') + ); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'tinyboard'; + } +} + +function twig_timezone_function() { + return 'Z'; +} + +function twig_push_filter($array, $value) { + array_push($array, $value); + return $array; +} + +function twig_remove_whitespace_filter($data) { + return preg_replace('/[\t\r\n]/', '', $data); +} + +function twig_date_filter($date, $format) { + return gmstrftime($format, $date); +} + +function twig_hasPermission_filter($mod, $permission, $board = null) { + return hasPermission($permission, $board, $mod); +} + +function twig_extension_filter($value, $case_insensitive = true) { + $ext = mb_substr($value, mb_strrpos($value, '.') + 1); + if($case_insensitive) + $ext = mb_strtolower($ext); + return $ext; +} + +function twig_sprintf_filter( $value, $var) { + return sprintf($value, $var); +} + +function twig_truncate_filter($value, $length = 30, $preserve = false, $separator = '…') { + if (mb_strlen($value) > $length) { + if ($preserve) { + if (false !== ($breakpoint = mb_strpos($value, ' ', $length))) { + $length = $breakpoint; + } + } + return mb_substr($value, 0, $length) . $separator; + } + return $value; +} + +function twig_filename_truncate_filter($value, $length = 30, $separator = '…') { + if (mb_strlen($value) > $length) { + $value = strrev($value); + $array = array_reverse(explode(".", $value, 2)); + $array = array_map("strrev", $array); + + $filename = &$array[0]; + $extension = isset($array[1]) ? $array[1] : false; + + $filename = mb_substr($filename, 0, $length - ($extension ? mb_strlen($extension) + 1 : 0)) . $separator; + + return implode(".", $array); + } + return $value; +} + +function twig_ratio_function($w, $h) { + return fraction($w, $h, ':'); +} +function twig_secure_link_confirm($text, $title, $confirm_message, $href) { + global $config; + + return '' . $text . ''; +} +function twig_secure_link($href) { + return $href . '/' . make_secure_link_token($href); +} diff --git a/templates/banned.html b/templates/banned.html index 4c1a3ed2..c7fd175a 100644 --- a/templates/banned.html +++ b/templates/banned.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} {# Automatically removes unnecessary whitespace #}
{% if ban.expires and time() >= ban.expires %} diff --git a/templates/installer/check-requirements.html b/templates/installer/check-requirements.html index 3ae46dd5..f8ea6410 100644 --- a/templates/installer/check-requirements.html +++ b/templates/installer/check-requirements.html @@ -31,15 +31,17 @@ {% if errors or warnings %}

There were {{ errors }} error(s) and {{ warnings }} warning(s).

{% if errors %} diff --git a/templates/mod/config-editor-php.html b/templates/mod/config-editor-php.html index 0c1a3a09..9dc48f15 100644 --- a/templates/mod/config-editor-php.html +++ b/templates/mod/config-editor-php.html @@ -2,15 +2,17 @@

Any changes you make here will simply be appended to {{ file }}. If you wish to make the most of Tinyboard's customizability, you can instead edit the file directly. This page is intended for making quick changes and for those who don't have a basic understanding of PHP code.

- {% if boards|count %} + {% if boards|length %} {% endif %} diff --git a/templates/mod/config-editor.html b/templates/mod/config-editor.html index 1c3436cd..f5815c7f 100644 --- a/templates/mod/config-editor.html +++ b/templates/mod/config-editor.html @@ -6,10 +6,12 @@ {% if board %}
  • Edit site-wide config
  • {% endif %} - {% for _board in boards if _board.uri != board %} -
  • - Edit config for {{ config.board_abbreviation|sprintf(_board.uri) }} -
  • + {% for _board in boards %} + {% if _board.uri != board %} +
  • + Edit config for {{ config.board_abbreviation|sprintf(_board.uri) }} +
  • + {% endif %} {% endfor %} {% endif %} @@ -22,54 +24,56 @@ {% trans 'Type' %} {% trans 'Description' %} - {% for var in conf if var.type != 'array' %} - {% if var.name|length == 1 %} - {% set name = 'cf_' ~ var.name %} - {% else %} - {% set name = 'cf_' ~ var.name|join('/') %} - {% endif %} - - - - {% if var.name|length == 1 %} - {{ var.name }} - {% else %} - {{ var.name|join(' → ') }} - {% endif %} - + {% for var in conf %} + {% if var.type != 'array' %} + {% if var.name|length == 1 %} + {% set name = 'cf_' ~ var.name %} + {% else %} + {% set name = 'cf_' ~ var.name|join('/') %} + {% endif %} - - {% if var.type == 'string' %} - - {% elseif var.permissions %} - - {% elseif var.type == 'integer' %} - - {% elseif var.type == 'boolean' %} - - {% else %} - ? - {% endif %} + + + {% if var.name|length == 1 %} + {{ var.name }} + {% else %} + {{ var.name|join(' → ') }} + {% endif %} + - {% if var.type == 'integer' or var.type == 'boolean' %} - Default: {{ var.default }} - {% endif %} - - - - {{ var.type|e }} - - - - {{ var.comment|join(' ') }} - - + + {% if var.type == 'string' %} + + {% elseif var.permissions %} + + {% elseif var.type == 'integer' %} + + {% elseif var.type == 'boolean' %} + + {% else %} + ? + {% endif %} + + {% if var.type == 'integer' or var.type == 'boolean' %} + Default: {{ var.default }} + {% endif %} + + + + {{ var.type|e }} + + + + {{ var.comment|join(' ') }} + + + {% endif %} {% endfor %} diff --git a/templates/mod/dashboard.html b/templates/mod/dashboard.html index 8ceec3a8..d6b132c2 100644 --- a/templates/mod/dashboard.html +++ b/templates/mod/dashboard.html @@ -36,7 +36,7 @@ {% trans 'Messages' %}
    {% endfor %} -{% if count > news|count %} +{% if count > news|length %}

    {% for i in range(0, (count - 1) / config.mod.news_page) %} [{{ i + 1 }}] diff --git a/templates/mod/noticeboard.html b/templates/mod/noticeboard.html index fc2e0aef..1036b129 100644 --- a/templates/mod/noticeboard.html +++ b/templates/mod/noticeboard.html @@ -57,7 +57,7 @@ {% endfor %} -{% if count > noticeboard|count %} +{% if count > noticeboard|length %}

    {% for i in range(0, (count - 1) / config.mod.noticeboard_page) %} [{{ i + 1 }}] diff --git a/templates/mod/recent_posts.html b/templates/mod/recent_posts.html index f98341d4..307baa93 100644 --- a/templates/mod/recent_posts.html +++ b/templates/mod/recent_posts.html @@ -1,6 +1,6 @@ -{% if not posts|count %} +{% if not posts|length %}

    ({% trans 'There are no active posts.' %})

    {% else %}

    Viewing last {{ limit|e }} posts

    diff --git a/templates/mod/search_results.html b/templates/mod/search_results.html index 781f0db5..5df90f66 100644 --- a/templates/mod/search_results.html +++ b/templates/mod/search_results.html @@ -259,7 +259,7 @@ {% endif %} -{% if result_count > results|count %} +{% if result_count > results|length %}

    {% for i in range(0, (result_count - 1) / config.mod.search_page) %} [{{ i + 1 }}] diff --git a/templates/mod/themes.html b/templates/mod/themes.html index b230bc48..36fbec64 100644 --- a/templates/mod/themes.html +++ b/templates/mod/themes.html @@ -1,4 +1,4 @@ -{% if themes|count == 0 %} +{% if themes|length == 0 %}

    ({% trans 'There are no themes available.' %})

    {% else %} diff --git a/templates/mod/user.html b/templates/mod/user.html index e774ded7..6b165e6e 100644 --- a/templates/mod/user.html +++ b/templates/mod/user.html @@ -32,11 +32,13 @@ @@ -87,7 +89,7 @@ -{% if logs and logs|count > 0 %} +{% if logs and logs|length > 0 %}
    {% trans 'Group' %}
      - {% for group_value, group_name in config.mod.groups if group_name != 'Disabled' %} -
    • - - -
    • + {% for group_value, group_name in config.mod.groups %} + {% if group_name != 'Disabled' %} +
    • + + +
    • + {% endif %} {% endfor %}
    diff --git a/templates/mod/view_ip.html b/templates/mod/view_ip.html index e6fc59e5..918e7866 100644 --- a/templates/mod/view_ip.html +++ b/templates/mod/view_ip.html @@ -1,11 +1,11 @@ {% if mod|hasPermission(config.mod.view_notes) %}
    - {% set notes_on_record = 'note' ~ (notes|count != 1 ? 's' : '') ~ ' on record' %} - {{ notes|count }} {% trans notes_on_record %} + {% set notes_length = notes|length %} + {{ notes_length }} {% trans %}note on record{% plural notes_length %}notes on record{% endtrans %} - {% if notes|count > 0 %} + {% if notes|length > 0 %}
    {% trans 'IP address' %}
    @@ -71,11 +71,11 @@ {% if mod|hasPermission(config.mod.view_telegrams) %}
    - {% set telegrams_on_record = 'telegram' ~ (telegrams|count != 1 ? 's' : '') ~ ' on record' %} - {{ telegrams|count }} {% trans telegrams_on_record %} + {% set telegrams_length = telegrams|length %} + {{ telegrams_length }} {% trans %}telegram on record{% plural notes_length %}telegrams on record{% endtrans %} - {% if telegrams|count > 0 %} + {% if telegrams|length > 0 %}
    {% trans 'Staff' %}
    @@ -146,10 +146,10 @@ {% endif %} -{% if bans|count > 0 and mod|hasPermission(config.mod.view_ban) %} +{% if bans|length > 0 and mod|hasPermission(config.mod.view_ban) %}
    - {% set bans_on_record = 'ban' ~ (bans|count != 1 ? 's' : '') ~ ' on record' %} - {{ bans|count }} {% trans bans_on_record %} + {% set bans_length = bans|length %} + {{ bans_length }} {% trans %}ban on record{% plural notes_length %}bans on record{% endtrans %} {% for ban in bans %}
    @@ -163,7 +163,15 @@
    {% endif %} -{% if logs|count > 0 %} +{% if mod|hasPermission(config.mod.ban) %} +
    + {% trans 'New ban' %} + {% set redirect = '?/IP/' ~ ip|cloak_ip ~ '#bans' %} + {% include 'mod/ban_form.html' %} +
    +{% endif %} + +{% if logs|length > 0 %}
    History
    {% trans 'Staff' %}
    diff --git a/templates/not_banned.html b/templates/not_banned.html index 07bf7084..61ec9f30 100644 --- a/templates/not_banned.html +++ b/templates/not_banned.html @@ -1,4 +1,5 @@ -{% apply remove_whitespace %} +{% apply spaceless %} +{# Automatically removes unnecessary whitespace #}

    You are not banned!

    Well done on not being terrible!

    diff --git a/templates/post_reply.html b/templates/post_reply.html index 95caa581..28c96cd7 100644 --- a/templates/post_reply.html +++ b/templates/post_reply.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} {# tabs and new lines will be ignored #}

    @@ -18,7 +18,7 @@ {% include 'post/fileinfo.html' %} {% include 'post/post_controls.html' %}

    1 %}style="clear:both"{% endif %}> - {% endapply %}{% if index %}{{ post.body|truncate_body(post.link) }}{% else %}{{ post.body }}{% endif %}{% apply remove_whitespace %} + {% endapply %}{% if index %}{{ post.body|truncate_body(post.link) }}{% else %}{{ post.body }}{% endif %}{% apply spaceless %} {% if post.modifiers['warning message'] %} {{ config.mod.warning_message|sprintf(post.modifiers['warning message']) }} {% endif %} diff --git a/templates/post_thread.html b/templates/post_thread.html index c3ee545c..3f0fc3ab 100644 --- a/templates/post_thread.html +++ b/templates/post_thread.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} {# tabs and new lines will be ignored #}
    @@ -61,7 +61,7 @@ {% include 'post/post_controls.html' %}

    - {% endapply %}{% if index %}{{ post.body|truncate_body(post.link) }}{% else %}{{ post.body }}{% endif %}{% apply remove_whitespace %} + {% endapply %}{% if index %}{{ post.body|truncate_body(post.link) }}{% else %}{{ post.body }}{% endif %}{% apply spaceless %} {% if post.modifiers['warning message'] %} {{ config.mod.warning_message|sprintf(post.modifiers['warning message']) }} {% endif %} diff --git a/templates/post_thread_fileboard.html b/templates/post_thread_fileboard.html index 2752cfaa..7a9206b2 100644 --- a/templates/post_thread_fileboard.html +++ b/templates/post_thread_fileboard.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} {# tabs and new lines will be ignored #} {# we are intentionally breaking the thread_ID convention: the jses need to handle this case differently #} diff --git a/templates/themes/basic/index.html b/templates/themes/basic/index.html index e67ea535..472529fa 100644 --- a/templates/themes/basic/index.html +++ b/templates/themes/basic/index.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} @@ -19,7 +19,7 @@
    - {% if news|count == 0 %} + {% if news|length == 0 %}

    (No news to show.)

    {% else %} {% for entry in news %} diff --git a/templates/themes/catalog/catalog.html b/templates/themes/catalog/catalog.html index 050f8586..66a3aec2 100644 --- a/templates/themes/catalog/catalog.html +++ b/templates/themes/catalog/catalog.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} diff --git a/templates/themes/categories/news.html b/templates/themes/categories/news.html index f8a733ce..a25c288a 100644 --- a/templates/themes/categories/news.html +++ b/templates/themes/categories/news.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} @@ -14,7 +14,7 @@
    - {% if news|count == 0 %} + {% if news|length == 0 %}

    {% trans %}(No news to show.){% endtrans %}

    {% else %} {% for entry in news %} diff --git a/templates/themes/categories/sidebar.html b/templates/themes/categories/sidebar.html index f8db397e..1c2e780e 100644 --- a/templates/themes/categories/sidebar.html +++ b/templates/themes/categories/sidebar.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} diff --git a/templates/themes/frameset/news.html b/templates/themes/frameset/news.html index f88b580e..c929881a 100644 --- a/templates/themes/frameset/news.html +++ b/templates/themes/frameset/news.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} @@ -13,7 +13,7 @@
    - {% if news|count == 0 %} + {% if news|length == 0 %}

    (No news to show.)

    {% else %} {% for entry in news %} diff --git a/templates/themes/frameset/sidebar.html b/templates/themes/frameset/sidebar.html index 95e75375..0fd6bd03 100644 --- a/templates/themes/frameset/sidebar.html +++ b/templates/themes/frameset/sidebar.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} diff --git a/templates/themes/index/index.html b/templates/themes/index/index.html index 216947a9..e42bff0c 100644 --- a/templates/themes/index/index.html +++ b/templates/themes/index/index.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} @@ -46,7 +46,7 @@
    - {% if news|count == 0 %} + {% if news|length == 0 %}

    (No news to show.)

    {% else %} {% for entry in news %} diff --git a/templates/themes/recent/recent.html b/templates/themes/recent/recent.html index 3d89d260..506148fe 100644 --- a/templates/themes/recent/recent.html +++ b/templates/themes/recent/recent.html @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} diff --git a/templates/themes/rss/rss.xml b/templates/themes/rss/rss.xml index c3435d9a..23a3d020 100644 --- a/templates/themes/rss/rss.xml +++ b/templates/themes/rss/rss.xml @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} diff --git a/templates/themes/sitemap/sitemap.xml b/templates/themes/sitemap/sitemap.xml index ce7bac10..687eb3e6 100644 --- a/templates/themes/sitemap/sitemap.xml +++ b/templates/themes/sitemap/sitemap.xml @@ -1,4 +1,4 @@ -{% apply remove_whitespace %} +{% apply spaceless %} {% for board in boards %} diff --git a/tools/rebuild.php b/tools/rebuild.php index 36d5c3da..e6ed10f1 100755 --- a/tools/rebuild.php +++ b/tools/rebuild.php @@ -42,9 +42,8 @@ if(!$options['quiet']) if(!$options['quiet']) echo "Clearing template cache...\n"; - load_twig(); -$twig->clearCacheFiles(); +$twig->getCache()->clear(); if(!$options['quiet']) echo "Regenerating theme files...\n"; diff --git a/tools/rebuild2.php b/tools/rebuild2.php index 2945460c..422e4e92 100755 --- a/tools/rebuild2.php +++ b/tools/rebuild2.php @@ -44,7 +44,7 @@ echo "== Tinyboard + vichan {$config['version']} ==\n"; if ($options['cache']) { echo "Clearing template cache...\n"; load_twig(); - $twig->clearCacheFiles(); + $twig->getCache()->clear(); } if($options['themes']) {