diff --git a/application/third_party/Twig/Environment.php b/application/third_party/Twig/Environment.php index 1f80f3a8736..e3243fa4240 100644 --- a/application/third_party/Twig/Environment.php +++ b/application/third_party/Twig/Environment.php @@ -35,17 +35,17 @@ 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 VERSION = '1.44.2'; + const VERSION_ID = 14402; const MAJOR_VERSION = 1; - const MINOR_VERSION = 42; - const RELEASE_VERSION = 4; + const MINOR_VERSION = 44; + const RELEASE_VERSION = 2; const EXTRA_VERSION = ''; protected $charset; diff --git a/application/third_party/Twig/ExpressionParser.php b/application/third_party/Twig/ExpressionParser.php index 9066ade1695..fa480a07cc4 100644 --- a/application/third_party/Twig/ExpressionParser.php +++ b/application/third_party/Twig/ExpressionParser.php @@ -376,7 +376,16 @@ 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)) { + $key = new ConstantExpression($token->getValue(), $token->getLine()); + + // {a} is a shortcut for {a:a} + if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) { + $value = new NameExpression($key->getAttribute('value'), $key->getTemplateLine()); + $node->addElement($value, $key); + continue; + } + } elseif (($token = $stream->nextIf(Token::STRING_TYPE)) || $token = $stream->nextIf(Token::NUMBER_TYPE)) { $key = new ConstantExpression($token->getValue(), $token->getLine()); } elseif ($stream->test(Token::PUNCTUATION_TYPE, '(')) { $key = $this->parseExpression(); @@ -598,6 +607,11 @@ public function parseArguments($namedArguments = false, $definition = false, $al while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) { if (!empty($args)) { $stream->expect(Token::PUNCTUATION_TYPE, ',', '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, ')')) { + break; + } } if ($definition) { @@ -657,7 +671,7 @@ public function parseAssignmentExpression() $stream->expect(Token::NAME_TYPE, 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()); @@ -697,6 +711,8 @@ private function parseTestExpression(\Twig_NodeInterface $node) $arguments = null; if ($stream->test(Token::PUNCTUATION_TYPE, '(')) { $arguments = $this->parseArguments(true); + } elseif ($test->hasOneMandatoryArgument()) { + $arguments = new Node([0 => $this->parsePrimaryExpression()]); } return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine()); @@ -740,7 +756,7 @@ 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); } @@ -770,7 +786,7 @@ 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); + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line); @trigger_error($message, E_USER_DEPRECATED); } @@ -800,7 +816,7 @@ 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); + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line); @trigger_error($message, E_USER_DEPRECATED); } diff --git a/application/third_party/Twig/Extension/AbstractExtension.php b/application/third_party/Twig/Extension/AbstractExtension.php index fa3245b2984..cabe7182c9e 100644 --- a/application/third_party/Twig/Extension/AbstractExtension.php +++ b/application/third_party/Twig/Extension/AbstractExtension.php @@ -65,7 +65,7 @@ public function getGlobals() */ public function getName() { - return \get_class($this); + return static::class; } } diff --git a/application/third_party/Twig/Extension/CoreExtension.php b/application/third_party/Twig/Extension/CoreExtension.php index 5f3cc24a195..b52cb29be13 100644 --- a/application/third_party/Twig/Extension/CoreExtension.php +++ b/application/third_party/Twig/Extension/CoreExtension.php @@ -194,9 +194,9 @@ public function getFilters() new TwigFilter('sort', 'twig_sort_filter'), 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('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]), @@ -244,11 +244,11 @@ public function getTests() 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('same as', null, ['node_class' => '\Twig\Node\Expression\Test\SameasTest', 'one_mandatory_argument' => true]), 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('divisible by', null, ['node_class' => '\Twig\Node\Expression\Test\DivisiblebyTest', 'one_mandatory_argument' => true]), new TwigTest('constant', null, ['node_class' => '\Twig\Node\Expression\Test\ConstantTest']), new TwigTest('empty', 'twig_test_empty'), new TwigTest('iterable', 'twig_test_iterable'), @@ -313,6 +313,8 @@ class_alias('Twig\Extension\CoreExtension', 'Twig_Extension_Core'); use Twig\Markup; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Node; +use Twig\Template; +use Twig\TemplateWrapper; /** * Cycles over a value. @@ -459,7 +461,7 @@ function twig_date_modify_filter(Environment $env, $date, $modifier) * @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 * - * @return \DateTime + * @return \DateTimeInterface */ function twig_date_converter(Environment $env, $date = null, $timezone = null) { @@ -539,15 +541,15 @@ function twig_replace_filter($str, $from, $to = null) */ function twig_round($value, $precision = 0, $method = 'common') { - if ('common' == $method) { + 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; } /** @@ -1214,7 +1216,7 @@ function _twig_escape_js_callback($matches) /* * A few characters have short escape sequences in JSON and JavaScript. - * Escape sequences supported only by JavaScript, not JSON, are ommitted. + * 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 = [ @@ -1231,15 +1233,18 @@ function _twig_escape_js_callback($matches) return $shortMap[$char]; } - // \uHHHH - $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); - $char = strtoupper(bin2hex($char)); - - if (4 >= \strlen($char)) { - return sprintf('\u%04s', $char); + $codepoint = mb_ord($char); + if (0x10000 > $codepoint) { + return sprintf('\u%04X', $codepoint); } - return sprintf('\u%04s\u%04s', substr($char, 0, -4), substr($char, -4)); + // 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); } function _twig_escape_css_callback($matches) @@ -1504,7 +1509,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) { @@ -1560,6 +1565,13 @@ function twig_include(Environment $env, $context, $template, $variables = [], $w if (!$alreadySandboxed = $sandbox->isSandboxed()) { $sandbox->enableSandbox(); } + + 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(); + } + } } $loaded = null; @@ -1693,8 +1705,16 @@ function twig_array_batch($items, $size, $fill = null, $preserveKeys = true) return $result; } -function twig_array_filter($array, $arrow) +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))); + } + + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError('The callable passed to "filter" filter must be a Closure in sandbox mode.'); + } + if (\is_array($array)) { if (\PHP_VERSION_ID >= 50600) { return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); @@ -1707,8 +1727,12 @@ function twig_array_filter($array, $arrow) return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow); } -function twig_array_map($array, $arrow) +function twig_array_map(Environment $env, $array, $arrow) { + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError('The callable passed to the "map" filter must be a Closure in sandbox mode.'); + } + $r = []; foreach ($array as $k => $v) { $r[$k] = $arrow($v, $k); @@ -1717,9 +1741,17 @@ 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) { + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError('The callable passed to the "reduce" filter must be a Closure in sandbox mode.'); + } + 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); } diff --git a/application/third_party/Twig/Extension/ProfilerExtension.php b/application/third_party/Twig/Extension/ProfilerExtension.php index 7b21b9fa555..ad494585b6d 100644 --- a/application/third_party/Twig/Extension/ProfilerExtension.php +++ b/application/third_party/Twig/Extension/ProfilerExtension.php @@ -41,7 +41,7 @@ public function leave(Profile $profile) public function getNodeVisitors() { - return [new ProfilerNodeVisitor(\get_class($this))]; + return [new ProfilerNodeVisitor(static::class)]; } public function getName() diff --git a/application/third_party/Twig/Lexer.php b/application/third_party/Twig/Lexer.php index 697a6cfa1d1..67d94ab927b 100644 --- a/application/third_party/Twig/Lexer.php +++ b/application/third_party/Twig/Lexer.php @@ -117,7 +117,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]* '|'. @@ -499,11 +499,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 = '(?templates[$name])) { diff --git a/application/third_party/Twig/Loader/ChainLoader.php b/application/third_party/Twig/Loader/ChainLoader.php index 25ac55a335b..d1c08670033 100644 --- a/application/third_party/Twig/Loader/ChainLoader.php +++ b/application/third_party/Twig/Loader/ChainLoader.php @@ -52,7 +52,7 @@ public function getLoaders() 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); + @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', static::class), E_USER_DEPRECATED); $exceptions = []; foreach ($this->loaders as $loader) { diff --git a/application/third_party/Twig/Loader/FilesystemLoader.php b/application/third_party/Twig/Loader/FilesystemLoader.php index 19b43a29549..54303ffdabf 100644 --- a/application/third_party/Twig/Loader/FilesystemLoader.php +++ b/application/third_party/Twig/Loader/FilesystemLoader.php @@ -138,7 +138,7 @@ 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); + @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', static::class), E_USER_DEPRECATED); if (null === ($path = $this->findTemplate($name)) || false === $path) { return ''; @@ -180,7 +180,7 @@ public function exists($name) 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); + @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.', static::class), E_USER_DEPRECATED); return false; } diff --git a/application/third_party/Twig/Node/CheckSecurityNode.php b/application/third_party/Twig/Node/CheckSecurityNode.php index cf0a7a13d8a..5a5ae63dd6d 100644 --- a/application/third_party/Twig/Node/CheckSecurityNode.php +++ b/application/third_party/Twig/Node/CheckSecurityNode.php @@ -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") @@ -78,6 +81,8 @@ public function compile(Compiler $compiler) ->write("throw \$e;\n") ->outdent() ->write("}\n\n") + ->outdent() + ->write("}\n") ; } } diff --git a/application/third_party/Twig/Node/EmbedNode.php b/application/third_party/Twig/Node/EmbedNode.php index 05051ecec8a..dde3db1bd39 100644 --- a/application/third_party/Twig/Node/EmbedNode.php +++ b/application/third_party/Twig/Node/EmbedNode.php @@ -23,7 +23,7 @@ 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($name, $index, ?AbstractExpression $variables, $only, $ignoreMissing, $lineno, $tag = null) { parent::__construct(new ConstantExpression('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag); diff --git a/application/third_party/Twig/Node/Expression/BlockReferenceExpression.php b/application/third_party/Twig/Node/Expression/BlockReferenceExpression.php index 0a56849c7aa..7e3c3e484d7 100644 --- a/application/third_party/Twig/Node/Expression/BlockReferenceExpression.php +++ b/application/third_party/Twig/Node/Expression/BlockReferenceExpression.php @@ -25,7 +25,7 @@ class BlockReferenceExpression extends AbstractExpression /** * @param Node|null $template */ - public function __construct(\Twig_NodeInterface $name, $template = null, $lineno, $tag = null) + public function __construct(\Twig_NodeInterface $name, $template, $lineno, $tag = null) { if (\is_bool($template)) { @trigger_error(sprintf('The %s method "$asString" argument is deprecated since version 1.28 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); diff --git a/application/third_party/Twig/Node/Expression/CallExpression.php b/application/third_party/Twig/Node/Expression/CallExpression.php index d202a739532..d0667379d0e 100644 --- a/application/third_party/Twig/Node/Expression/CallExpression.php +++ b/application/third_party/Twig/Node/Expression/CallExpression.php @@ -149,7 +149,16 @@ protected function getArguments($callable, $arguments) $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)) { @@ -254,7 +263,8 @@ private function getCallableParameters($callable, $isVariadic) } 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); } else { $callableName = $r->name; diff --git a/application/third_party/Twig/Node/Expression/GetAttrExpression.php b/application/third_party/Twig/Node/Expression/GetAttrExpression.php index b790bf7af7a..06511c77374 100644 --- a/application/third_party/Twig/Node/Expression/GetAttrExpression.php +++ b/application/third_party/Twig/Node/Expression/GetAttrExpression.php @@ -17,7 +17,7 @@ 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) { diff --git a/application/third_party/Twig/Node/Expression/NameExpression.php b/application/third_party/Twig/Node/Expression/NameExpression.php index d3f7d107fb0..e7be5ff547d 100644 --- a/application/third_party/Twig/Node/Expression/NameExpression.php +++ b/application/third_party/Twig/Node/Expression/NameExpression.php @@ -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) diff --git a/application/third_party/Twig/Node/Expression/Test/DefinedTest.php b/application/third_party/Twig/Node/Expression/Test/DefinedTest.php index 2222e11cfda..e2b3a0b8a90 100644 --- a/application/third_party/Twig/Node/Expression/Test/DefinedTest.php +++ b/application/third_party/Twig/Node/Expression/Test/DefinedTest.php @@ -33,7 +33,7 @@ */ class DefinedTest extends TestExpression { - public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterface $arguments = null, $lineno) + public function __construct(\Twig_NodeInterface $node, $name, ?\Twig_NodeInterface $arguments, $lineno) { if ($node instanceof NameExpression) { $node->setAttribute('is_defined_test', true); diff --git a/application/third_party/Twig/Node/Expression/Test/OddTest.php b/application/third_party/Twig/Node/Expression/Test/OddTest.php index 2dc693a9ae6..189e51e761e 100644 --- a/application/third_party/Twig/Node/Expression/Test/OddTest.php +++ b/application/third_party/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/application/third_party/Twig/Node/Expression/TestExpression.php b/application/third_party/Twig/Node/Expression/TestExpression.php index 8fc31d3aadc..fa3c18fbf75 100644 --- a/application/third_party/Twig/Node/Expression/TestExpression.php +++ b/application/third_party/Twig/Node/Expression/TestExpression.php @@ -16,7 +16,7 @@ class TestExpression extends CallExpression { - public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterface $arguments = null, $lineno) + public function __construct(\Twig_NodeInterface $node, $name, ?\Twig_NodeInterface $arguments, $lineno) { $nodes = ['node' => $node]; if (null !== $arguments) { diff --git a/application/third_party/Twig/Node/ForNode.php b/application/third_party/Twig/Node/ForNode.php index 49409a39b18..111da37ea50 100644 --- a/application/third_party/Twig/Node/ForNode.php +++ b/application/third_party/Twig/Node/ForNode.php @@ -25,7 +25,7 @@ class ForNode extends Node { protected $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, \Twig_NodeInterface $body, ?\Twig_NodeInterface $else, $lineno, $tag = null) { $body = new Node([$body, $this->loop = new ForLoopNode($lineno, $tag)]); diff --git a/application/third_party/Twig/Node/IfNode.php b/application/third_party/Twig/Node/IfNode.php index 4836d91f088..da2ad344a7e 100644 --- a/application/third_party/Twig/Node/IfNode.php +++ b/application/third_party/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(\Twig_NodeInterface $tests, ?\Twig_NodeInterface $else, $lineno, $tag = null) { $nodes = ['tests' => $tests]; if (null !== $else) { diff --git a/application/third_party/Twig/Node/IncludeNode.php b/application/third_party/Twig/Node/IncludeNode.php index 544db81eaf3..d0b6184c86f 100644 --- a/application/third_party/Twig/Node/IncludeNode.php +++ b/application/third_party/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, $only, $ignoreMissing, $lineno, $tag = null) { $nodes = ['expr' => $expr]; if (null !== $variables) { diff --git a/application/third_party/Twig/Node/ModuleNode.php b/application/third_party/Twig/Node/ModuleNode.php index aab2aa33f2d..89d602b97a1 100644 --- a/application/third_party/Twig/Node/ModuleNode.php +++ b/application/third_party/Twig/Node/ModuleNode.php @@ -28,7 +28,7 @@ */ 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(\Twig_NodeInterface $body, ?AbstractExpression $parent, \Twig_NodeInterface $blocks, \Twig_NodeInterface $macros, \Twig_NodeInterface $traits, $embeddedTemplates, $name, $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); diff --git a/application/third_party/Twig/Node/Node.php b/application/third_party/Twig/Node/Node.php index c890feb72da..5ec7a73f4c4 100644 --- a/application/third_party/Twig/Node/Node.php +++ b/application/third_party/Twig/Node/Node.php @@ -40,7 +40,7 @@ public function __construct(array $nodes = [], array $attributes = [], $lineno = { 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); + @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, static::class), E_USER_DEPRECATED); } } $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) { @@ -89,7 +89,7 @@ public function toXml($asDom = false) $dom->appendChild($xml = $dom->createElement('twig')); $xml->appendChild($node = $dom->createElement('node')); - $node->setAttribute('class', \get_class($this)); + $node->setAttribute('class', static::class); foreach ($this->attributes as $name => $value) { $node->appendChild($attribute = $dom->createElement('attribute')); @@ -153,7 +153,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]; @@ -187,7 +187,7 @@ 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))); + throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, static::class)); } return $this->nodes[$name]; @@ -196,7 +196,7 @@ public function getNode($name) public function setNode($name, $node = null) { if (!$node instanceof \Twig_NodeInterface) { - @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, \get_class($this)), E_USER_DEPRECATED); + @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, static::class), E_USER_DEPRECATED); } $this->nodes[$name] = $node; @@ -236,7 +236,7 @@ public function setSourceContext(Source $source) { $this->sourceContext = $source; foreach ($this->nodes as $node) { - if ($node instanceof Node) { + if ($node instanceof self) { $node->setSourceContext($source); } } diff --git a/application/third_party/Twig/Node/SandboxNode.php b/application/third_party/Twig/Node/SandboxNode.php index 2d644c3a137..3dcd4d8fa00 100644 --- a/application/third_party/Twig/Node/SandboxNode.php +++ b/application/third_party/Twig/Node/SandboxNode.php @@ -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/application/third_party/Twig/Node/WithNode.php b/application/third_party/Twig/Node/WithNode.php index f5ae9246ddc..d291dcf9aef 100644 --- a/application/third_party/Twig/Node/WithNode.php +++ b/application/third_party/Twig/Node/WithNode.php @@ -20,7 +20,7 @@ */ class WithNode extends Node { - public function __construct(Node $body, Node $variables = null, $only = false, $lineno, $tag = null) + public function __construct(Node $body, ?Node $variables, $only, $lineno, $tag = null) { $nodes = ['body' => $body]; if (null !== $variables) { diff --git a/application/third_party/Twig/NodeVisitor/SandboxNodeVisitor.php b/application/third_party/Twig/NodeVisitor/SandboxNodeVisitor.php index c9403398f09..9bee9f5cb5c 100644 --- a/application/third_party/Twig/NodeVisitor/SandboxNodeVisitor.php +++ b/application/third_party/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; @@ -102,7 +103,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; diff --git a/application/third_party/Twig/Parser.php b/application/third_party/Twig/Parser.php index 0ea102cc811..9fb6a83a4e6 100644 --- a/application/third_party/Twig/Parser.php +++ b/application/third_party/Twig/Parser.php @@ -299,7 +299,7 @@ public function isReservedMacroName($name) $this->reservedMacroNames = []; $r = new \ReflectionClass($this->env->getBaseTemplateClass()); foreach ($r->getMethods() as $method) { - $methodName = strtolower($method->getName()); + $methodName = strtr($method->getName(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) { $this->reservedMacroNames[] = substr($methodName, 3); @@ -307,7 +307,7 @@ public function isReservedMacroName($name) } } - return \in_array(strtolower($name), $this->reservedMacroNames); + return \in_array(strtr($name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), $this->reservedMacroNames); } public function addTrait($trait) diff --git a/application/third_party/Twig/Sandbox/SecurityPolicy.php b/application/third_party/Twig/Sandbox/SecurityPolicy.php index 31b6c348332..603843591af 100644 --- a/application/third_party/Twig/Sandbox/SecurityPolicy.php +++ b/application/third_party/Twig/Sandbox/SecurityPolicy.php @@ -51,7 +51,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]); } } @@ -93,7 +93,7 @@ public function checkMethodAllowed($obj, $method) } $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/application/third_party/Twig/Template.php b/application/third_party/Twig/Template.php index 3f7447c126c..032efe32699 100644 --- a/application/third_party/Twig/Template.php +++ b/application/third_party/Twig/Template.php @@ -111,8 +111,6 @@ public function getEnvironment() * 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 @@ -366,7 +364,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 +397,7 @@ protected function loadTemplate($template, $templateName = null, $line = null, $ * * @return Template */ - protected function unwrap() + public function unwrap() { return $this; } @@ -628,7 +626,7 @@ protected function getAttribute($object, $item, array $arguments = [], $type = s 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)) { + if ('getenvironment' !== strtr($refMethod->name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')) { $methods[] = $refMethod->name; } } @@ -642,7 +640,7 @@ protected function getAttribute($object, $item, array $arguments = [], $type = s foreach ($methods as $method) { $cache[$method] = $method; - $cache[$lcName = strtolower($method)] = $method; + $cache[$lcName = strtr($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')] = $method; if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) { $name = substr($method, 3); @@ -670,7 +668,7 @@ protected function getAttribute($object, $item, array $arguments = [], $type = s $call = false; if (isset(self::$cache[$class][$item])) { $method = self::$cache[$class][$item]; - } elseif (isset(self::$cache[$class][$lcItem = strtolower($item)])) { + } elseif (isset(self::$cache[$class][$lcItem = strtr($item, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')])) { $method = self::$cache[$class][$lcItem]; } elseif (isset(self::$cache[$class]['__call'])) { $method = $item; diff --git a/application/third_party/Twig/Test/IntegrationTestCase.php b/application/third_party/Twig/Test/IntegrationTestCase.php index 36b36075867..905f9725e39 100644 --- a/application/third_party/Twig/Test/IntegrationTestCase.php +++ b/application/third_party/Twig/Test/IntegrationTestCase.php @@ -247,7 +247,7 @@ protected static function parseTemplates($test) $templates = []; 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/application/third_party/Twig/TokenParser/ApplyTokenParser.php b/application/third_party/Twig/TokenParser/ApplyTokenParser.php index 879879a2b01..c75e5ef8aa9 100644 --- a/application/third_party/Twig/TokenParser/ApplyTokenParser.php +++ b/application/third_party/Twig/TokenParser/ApplyTokenParser.php @@ -22,7 +22,7 @@ * * {% apply upper %} * This text becomes uppercase - * {% endapplys %} + * {% endapply %} */ final class ApplyTokenParser extends AbstractTokenParser { diff --git a/application/third_party/Twig/TwigTest.php b/application/third_party/Twig/TwigTest.php index 5054965fe9a..962872d03eb 100644 --- a/application/third_party/Twig/TwigTest.php +++ b/application/third_party/Twig/TwigTest.php @@ -35,6 +35,7 @@ public function __construct($name, $callable, array $options = []) 'node_class' => '\Twig\Node\Expression\TestExpression', 'deprecated' => false, 'alternative' => null, + 'one_mandatory_argument' => false, ], $options); } @@ -82,6 +83,11 @@ public function getArguments() { return $this->arguments; } + + public function hasOneMandatoryArgument(): bool + { + return (bool) $this->options['one_mandatory_argument']; + } } class_alias('Twig\TwigTest', 'Twig_SimpleTest');