Description
Since c82acef, the unserialize_callback_func INI entry uses OnUpdateStrNotEmpty instead of OnUpdateString. OnUpdateStrNotEmpty returns FAILURE for an empty value, so the entry can no longer be set back to its default empty value at runtime.
ini_set() returns false and leaves the previous value in place, silently. Since the default value is empty, this breaks the usual save/restore idiom: the callback stays installed process-wide and fires for unrelated unserialize() calls later on.
The following code:
<?php
function my_callback($name) { echo "callback fired for $name\n"; }
// Save the current value and install our own, the usual save/restore idiom.
$prev = ini_set('unserialize_callback_func', 'my_callback');
var_dump($prev);
// Restore it. $prev is "" here, since that is the default value.
var_dump(ini_set('unserialize_callback_func', $prev));
var_dump(ini_get('unserialize_callback_func'));
// The callback is still installed and fires for unrelated code.
$o = unserialize('O:20:"SomeNotExistingClass":0:{}');
Resulted in this output:
string(0) ""
bool(false)
string(11) "my_callback"
callback fired for SomeNotExistingClass
Warning: unserialize(): Function my_callback() hasn't defined the class it was called for in /tmp/repro.php on line 13
But I expected this output instead:
string(0) ""
string(11) "my_callback"
string(0) ""
ini_set('unserialize_callback_func', null) fails the same way.
ini_restore('unserialize_callback_func') still works, so it is usable as a workaround, but it resets to the php.ini value rather than to the saved one.
The change looks unintended: the commit message only mentions avoiding a reallocation, php.ini-production and php.ini-development still ship unserialize_callback_func = empty, and there is no UPGRADING/NEWS entry. This is currently breaking Symfony on the 8.6 nightly, where the idiom is used in Cache, Config, Messenger, Security and VarExporter.
Note that output_handler received the same OnUpdateString -> OnUpdateStrNotEmpty swap in e0221be, though it is PHP_INI_PERDIR|PHP_INI_SYSTEM so the runtime impact is not the same.
PHP Version
PHP 8.6.0-dev (master, 5d58876). Works as expected on 8.5.8.
Operating System
Linux
Description
Since c82acef, the
unserialize_callback_funcINI entry usesOnUpdateStrNotEmptyinstead ofOnUpdateString.OnUpdateStrNotEmptyreturnsFAILUREfor an empty value, so the entry can no longer be set back to its default empty value at runtime.ini_set()returnsfalseand leaves the previous value in place, silently. Since the default value is empty, this breaks the usual save/restore idiom: the callback stays installed process-wide and fires for unrelatedunserialize()calls later on.The following code:
Resulted in this output:
But I expected this output instead:
ini_set('unserialize_callback_func', null)fails the same way.ini_restore('unserialize_callback_func')still works, so it is usable as a workaround, but it resets to the php.ini value rather than to the saved one.The change looks unintended: the commit message only mentions avoiding a reallocation,
php.ini-productionandphp.ini-developmentstill shipunserialize_callback_func =empty, and there is noUPGRADING/NEWSentry. This is currently breaking Symfony on the 8.6 nightly, where the idiom is used in Cache, Config, Messenger, Security and VarExporter.Note that
output_handlerreceived the sameOnUpdateString->OnUpdateStrNotEmptyswap in e0221be, though it isPHP_INI_PERDIR|PHP_INI_SYSTEMso the runtime impact is not the same.PHP Version
PHP 8.6.0-dev (master, 5d58876). Works as expected on 8.5.8.
Operating System
Linux