Fix a PHP 8.5 chr() deprecation when decoding octal string escapes

PHP 8.5 deprecates passing a value outside the [0, 255] range to chr().
The string-escape decoder in the lexer accepts up to three octal digits,
so an escape such as "\777" (= 511) reaches chr() out of range and emits:

    chr(): Providing a value not in-between 0 and 255 is deprecated ...

chr() already constrains the value with "% 256", so applying "% 256"
explicitly preserves the exact byte while silencing the deprecation. The
hex escape branch is unaffected because it is capped at two digits (0xff).
This commit is contained in:
Derrick Austin
2026-06-12 23:18:21 -04:00
committed by Fabien Potencier
parent 7f9714a13e
commit 153094b601
3 changed files with 14 additions and 1 deletions
+1
View File
@@ -1,5 +1,6 @@
# 3.28.0 (2026-XX-XX)
* Fix a PHP 8.5 `chr()` deprecation when decoding an octal string escape sequence larger than `\377` (such as `"\777"`)
* Mark `Twig\Markup` as `@final`; it will be final in Twig 4.0
* Reduce memory usage and speed up the context restoration compiled at the end of `for` loops
* Allow calling a macro with a dynamic name via the dot operator (`macros.(name)(args)`)
+1 -1
View File
@@ -435,7 +435,7 @@ class Lexer
while ($i + 1 < $length && ctype_digit($str[$i + 1]) && $str[$i + 1] < '8' && \strlen($octal) < 3) {
$octal .= $str[++$i];
}
$result .= \chr(octdec($octal));
$result .= \chr(octdec($octal) % 256);
} else {
trigger_deprecation('twig/twig', '3.12', 'Character "%s" should not be escaped; the "\" character is ignored in Twig 3 but will not be in Twig 4. Please remove the extra "\" character at position %d in "%s" at line %d.', $nextChar, $i + 1, $this->source->getName(), $this->lineno);
$result .= $nextChar;
+12
View File
@@ -209,6 +209,18 @@ class LexerTest extends TestCase
EOF,
"\065\x64",
];
yield 'octal escape overflowing a single byte is constrained with % 256' => [
<<<'EOF'
{{ '\777' }}
EOF,
"\xff",
];
yield 'octal escape exactly equal to 256 wraps around to a NUL byte' => [
<<<'EOF'
{{ '\400' }}
EOF,
"\x00",
];
yield [
<<<'EOF'
{{ 'App\\Test' }}