Fix PHP 8.1+ implicit float-to-int deprecation in sandboxed array access

This commit is contained in:
Fabien Potencier
2026-05-24 17:33:48 +02:00
parent 12f0dc2a1e
commit 33690a4a28
3 changed files with 63 additions and 0 deletions
+1
View File
@@ -1,5 +1,6 @@
# 3.27.0 (2026-XX-XX)
* Fix PHP 8.1+ implicit float-to-int deprecation triggered by sandboxed `ArrayAccess` attribute access with a float key
* Restrict allowed classes in `Twig\Profiler\Profile::unserialize()` to prevent arbitrary class instantiation
* Escape root profile name in `HtmlDumper`
* Deprecate the `Twig\Sandbox\SourcePolicyInterface` interface with no replacement
+4
View File
@@ -1698,6 +1698,10 @@ final class CoreExtension extends AbstractExtension
try {
$env->getExtension(SandboxExtension::class)->checkPropertyAllowed($object, $arrayItem, $lineno, $source);
} catch (SecurityNotAllowedPropertyError $propertyNotAllowedError) {
// The methodCheck path expects $item to be a string; stringify it here
// to avoid PHP 8.1+ implicit float-to-int deprecations on downstream
// array key lookups (e.g. isset($cache[$class][$item])).
$item = (string) $item;
goto methodCheck;
}
}
+58
View File
@@ -191,6 +191,64 @@ class SandboxTest extends TestCase
}
}
/**
* @dataProvider provideNonStringArrayAccessKeys
*/
public function testSandboxNonStringKeyAccessDoesNotTriggerImplicitConversionDeprecation(string $template, string $expectedKey)
{
$loader = new ArrayLoader(['t' => $template]);
$twig = new Environment($loader);
$twig->addExtension(new SandboxExtension(new SecurityPolicy(allowedFilters: ['escape']), true));
$obj = new class implements \ArrayAccess {
public function offsetGet($k): mixed
{
return null;
}
public function offsetExists($k): bool
{
return false;
}
public function offsetSet($k, $v): void
{
}
public function offsetUnset($k): void
{
}
};
// Promote E_DEPRECATED to an ErrorException so PHP 8.1's implicit
// float-to-int conversion notice (or any future similar notice) fails
// the test instead of slipping through error_log and leaking the
// sandboxed key value.
set_error_handler(static function (int $errno, string $msg) {
throw new \ErrorException($msg, 0, $errno);
}, \E_DEPRECATED);
try {
$twig->render('t', ['obj' => $obj]);
$this->fail('Expected SecurityNotAllowedPropertyError');
} catch (SecurityNotAllowedPropertyError $e) {
$this->assertSame($expectedKey, $e->getPropertyName());
} finally {
restore_error_handler();
}
}
public static function provideNonStringArrayAccessKeys(): iterable
{
// Float key: the one that triggers the implicit conversion deprecation
// on PHP 8.1+ before the fix.
yield 'float key' => ['{{ obj[3.14] }}', '3'];
// Bool keys: do not deprecate today but serve as regression guards
// and exercise the same coercion branch.
yield 'true key' => ['{{ obj[true] }}', '1'];
yield 'false key' => ['{{ obj[false] }}', '0'];
}
/**
* @group legacy
*/