Partially deprecate Serializable

If Serializable is implemented, require that __serialize() and
__unserialize() are implemented as well, else issue a deprecation
warning.

Also deprecate use of PDO::FETCH_SERIALIZE.

RFC: https://wiki.php.net/rfc/phase_out_serializable

Closes GH-6494.
This commit is contained in:
Nikita Popov 2020-12-07 14:20:43 +01:00
parent 5295e368b4
commit 3e6b447979
32 changed files with 136 additions and 28 deletions

View file

@ -254,6 +254,13 @@ PHP 8.1 UPGRADE NOTES
4. Deprecated Functionality
========================================
- Core:
. Implementing the Serializable interface without also implementing
__serialize() and __unserialize() has been deprecated. You should either
implement the new methods (if you only support PHP 7.4 and higher) or
implement both (if you support older PHP versions as well).
RFC: https://wiki.php.net/rfc/phase_out_serializable
- MySQLi:
. The mysqli_driver::$driver_version property has been deprecated. The driver
version is meaningless as it hasn't been updated in more than a decade. Use
@ -263,6 +270,10 @@ PHP 8.1 UPGRADE NOTES
mysqli_get_client_info() without any arguments to obtain the client
library version information.
- PDO:
. The PDO::FETCH_SERIALIZE mode has been deprecated.
RFC: https://wiki.php.net/rfc/phase_out_serializable
========================================
5. Changed Functions
========================================

View file

@ -20,5 +20,6 @@ try {
var_dump($e->getMessage());
}
?>
--EXPECT--
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
string(9) "serialize"

View file

@ -21,4 +21,6 @@ var_dump(unserialize(serialize(Foo::Bar)));
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Fatal error: Enums may not implement the Serializable interface in %s on line %d

View file

@ -19,4 +19,6 @@ var_dump(unserialize(serialize(Foo::Bar)));
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Fatal error: Enums may not implement the Serializable interface in %s on line %d

View file

@ -0,0 +1,23 @@
--TEST--
Serializable deprecation
--FILE--
<?php
interface I extends Serializable {}
abstract class A implements Serializable {}
class C extends A implements I {
public function serialize(): string {}
public function unserialize(string $data) {}
}
class D extends A implements I {
public function serialize(): string {}
public function unserialize(string $data) {}
public function __serialize(): array {}
public function __unserialize(array $data) {}
}
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d

View file

@ -21,6 +21,7 @@ var_dump(unserialize($o));
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
string(20) "C:3:"bar":6:{foobar}"
string(6) "foobar"
object(bar)#%d (0) {

View file

@ -432,6 +432,10 @@ static int zend_implement_serializable(zend_class_entry *interface, zend_class_e
if (!class_type->unserialize) {
class_type->unserialize = zend_user_unserialize;
}
if (!(class_type->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)
&& (!class_type->__serialize || !class_type->__unserialize)) {
zend_error(E_DEPRECATED, "The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary)");
}
return SUCCESS;
}
/* }}}*/

View file

@ -1141,6 +1141,9 @@ static bool pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode
ZEND_FALLTHROUGH;
case PDO_FETCH_CLASS:
if (flags & PDO_FETCH_SERIALIZE) {
php_error_docref(NULL, E_DEPRECATED, "The PDO::FETCH_SERIALIZE mode is deprecated");
}
return 1;
}
}

View file

@ -40,7 +40,10 @@ $stmt = $db->query("SELECT * FROM test");
print_r($stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, "bug44409"));
?>
--EXPECT--
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Deprecated: PDOStatement::fetchAll(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
Method called: bug44409::unserialize('Data from DB')
Array
(

View file

@ -183,6 +183,11 @@ var_dump($stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_CLASSTYPE|PDO::FETCH_SERIAL
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
string(1) "3"
array(3) {
[0]=>
@ -221,6 +226,8 @@ array(4) {
string(172) "a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:7:"BasePri";s:7:"Private";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";}"
}
===FAILURE===
Deprecated: PDOStatement::fetchAll(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
Exception:SQLSTATE[HY000]: General error: cannot unserialize class
===COUNT===
string(1) "3"
@ -249,6 +256,8 @@ array(3) {
}
}
===FETCHCLASS===
Deprecated: PDOStatement::fetchAll(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
TestBase::unserialize(a:3:{s:7:"BasePub";s:6:"Public";s:7:"BasePro";s:9:"Protected";s:7:"BasePri";s:7:"Private";})
TestDerived::unserialize()
TestBase::unserialize(a:5:{s:7:"BasePub";s:13:"DerivedPublic";s:7:"BasePro";s:16:"DerivdeProtected";s:7:"BasePri";s:7:"Private";s:10:"DerivedPub";s:6:"Public";s:10:"DerivedPro";s:9:"Protected";})

View file

@ -13,20 +13,10 @@ MySQLPDOTest::skip();
$pdoDb = MySQLPDOTest::factory();
class myclass implements Serializable {
class myclass {
public function __construct() {
printf("%s()\n", __METHOD__);
}
public function serialize() {
printf("%s()\n", __METHOD__);
return "any data from serialize()";
}
public function unserialize($dat) {
printf("%s(%s)\n", __METHOD__, var_export($dat, true));
return $dat;
}
}
class myclass2 extends myclass { }

View file

@ -120,6 +120,7 @@ $db = MySQLPDOTest::factory();
$db->exec('DROP TABLE IF EXISTS test');
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Creating an object, serializing it and writing it to DB...
myclass::singleton(Creating object)
myclass::__construct(Creating object)
@ -133,6 +134,10 @@ object(myclass)#4 (1) {
}
Using PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE to fetch the object from DB and unserialize it...
Deprecated: PDOStatement::setFetchMode(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
Deprecated: PDOStatement::fetch(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
myclass::unserialize('C:7:"myclass":19:{Data from serialize}')
object(myclass)#%d (1) {
["myprotected":protected]=>

View file

@ -69,6 +69,7 @@ MySQLPDOTest::skip();
print "done!\n";
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Lets see what the Serializeable interface makes our object behave like...
myclass::__construct('Called by script') - note that it must not be called when unserializing
myclass::serialize()
@ -77,14 +78,22 @@ object(myclass)#%d (0) {
}
And now magic PDO using fetchAll(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE)...
Deprecated: PDOStatement::fetchAll(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
myclass::unserialize('Data fetched from DB to be given to unserialize()')
object(myclass)#%d (0) {
}
Deprecated: PDOStatement::fetchAll(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
myclass::unserialize('Data fetched from DB to be given to unserialize()')
object(myclass)#%d (0) {
}
And now PDO using setFetchMode(PDO::FETCH:CLASS|PDO::FETCH_SERIALIZE) + fetch()...
Deprecated: PDOStatement::setFetchMode(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
Deprecated: PDOStatement::fetch(): The PDO::FETCH_SERIALIZE mode is deprecated in %s on line %d
myclass::unserialize('Data fetched from DB to be given to unserialize()')
object(myclass)#%d (0) {
}

View file

@ -48,22 +48,29 @@ echo "\n\n";
var_dump($_SESSION);
?>
--EXPECT--
obj1|C:17:"SerializableClass":65:{a:1:{s:10:"sharedProp";O:8:"stdClass":1:{s:4:"name";s:4:"test";}}}obj2|C:17:"SerializableClass":28:{a:1:{s:10:"sharedProp";r:3;}}
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Warning: session_start(): Session cannot be started after headers have already been sent in %s on line %d
Warning: session_encode(): Cannot encode non-existent session in %s on line %d
Warning: session_decode(): Session data cannot be decoded when there is no active session in %s on line %d
array(2) {
["obj1"]=>
object(SerializableClass)#4 (1) {
object(SerializableClass)#2 (1) {
["sharedProp"]=>
object(stdClass)#5 (1) {
object(stdClass)#1 (1) {
["name"]=>
string(4) "test"
}
}
["obj2"]=>
object(SerializableClass)#6 (1) {
object(SerializableClass)#3 (1) {
["sharedProp"]=>
object(stdClass)#5 (1) {
object(stdClass)#1 (1) {
["name"]=>
string(4) "test"
}

View file

@ -128,6 +128,7 @@ echo "===AutoNA===\n";
var_dump(unserialize('O:22:"autoload_not_available":0:{}'));
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
===O1===
TestOld::__sleep()
string(18) "O:7:"TestOld":0:{}"
@ -152,12 +153,16 @@ object(TestNAOld)#%d (0) {
===NANew===
unserializer(TestNANew)
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Warning: Erroneous data format for unserializing 'TestNANew' in %s005.php on line %d
Notice: unserialize(): Error at offset 19 of 20 bytes in %s005.php on line %d
bool(false)
===NANew2===
unserializer(TestNANew2)
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
TestNew::unserialize()
object(TestNANew2)#%d (0) {
}

View file

@ -44,7 +44,13 @@ echo "Done\n";
?>
--EXPECTF--
%aTEST
-TEST
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
C:1:"c":108:{a:1:{s:1:"a";C:1:"a":81:{a:3:{s:1:"b";C:1:"b":30:{a:2:{s:1:"c";r:1;s:1:"a";r:3;}}s:1:"c";r:1;s:1:"a";r:3;}}}}
bool(true)
bool(true)

View file

@ -53,8 +53,10 @@ print $a->a[1]->b->c . "\n";
?>
Done
--EXPECT--
--EXPECTF--
Test
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
1
2
Done

View file

@ -25,5 +25,6 @@ try {
var_dump($e->getMessage());
}
?>
--EXPECT--
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
string(6) "Failed"

View file

@ -35,6 +35,8 @@ $token = serialize($token);
?>
Done
--EXPECT--
--EXPECTF--
Test
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Done

View file

@ -41,6 +41,7 @@ function ptr2str($ptr)
}
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
array(2) {
[0]=>
int(1)

View file

@ -48,6 +48,7 @@ function ptr2str($ptr)
}
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
array(2) {
[0]=>
object(obj2)#%d (1) {

View file

@ -29,7 +29,11 @@ for ($i = 0; $i < 5; $i++) {
var_dump($data);
?>
--EXPECTF--
Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s on line %d
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Warning: session_start(): Session cannot be started after headers have already been sent in %s on line %d
Warning: session_decode(): Session data cannot be decoded when there is no active session in %s on line %d
Notice: unserialize(): Error at offset 55 of 56 bytes in %s on line %d
bool(false)

View file

@ -34,6 +34,7 @@ var_dump($data);
var_dump($_SESSION);
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
array(2) {
[0]=>
object(obj)#%d (1) {

View file

@ -46,6 +46,8 @@ function ptr2str($ptr)
?>
DONE
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Notice: unserialize(): Error at offset 0 of 3 bytes in %sbug70436.php on line %d
Notice: unserialize(): Error at offset 93 of 94 bytes in %sbug70436.php on line %d

View file

@ -43,7 +43,8 @@ $serialized = serialize([$entry1, $entry2]);
print_r(unserialize($serialized));
?>
--EXPECT--
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Array
(
[0] => Entry Object

View file

@ -19,6 +19,8 @@ var_dump(unserialize($exploit));
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Notice: unserialize(): Unexpected end of serialized data in %s on line %d
Notice: unserialize(): Error at offset 49 of 50 bytes in %s on line %d

View file

@ -21,7 +21,8 @@ $recovered = unserialize($data);
var_export($recovered);
?>
--EXPECT--
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
a:4:{i:0;N;i:1;N;i:2;s:6:"endcap";i:3;R:4;}
array (
0 => NULL,

View file

@ -134,6 +134,8 @@ Warning: unserialize(): Maximum depth of 256 exceeded. The depth limit can be ch
Notice: unserialize(): Error at offset 2309 of 2574 bytes in %s on line %d
bool(false)
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Nested unserialize combined depth limit:
Warning: unserialize(): Maximum depth of 256 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d
@ -142,6 +144,8 @@ Notice: unserialize(): Error at offset 1157 of 1294 bytes in %s on line %d
bool(false)
bool(true)
bool(true)
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Nested unserialize overridden depth limit:
Warning: unserialize(): Maximum depth of 256 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d

View file

@ -18,7 +18,8 @@ var_dump($s = serialize($data));
var_dump(unserialize($s));
?>
--EXPECT--
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
string(18) "a:2:{i:0;N;i:1;N;}"
array(2) {
[0]=>

View file

@ -19,6 +19,7 @@ try {
echo "Done";
?>
--EXPECT--
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
C::serialize() must return a string or NULL
Done

View file

@ -19,6 +19,8 @@ var_dump(unserialize($exploit));
?>
DONE
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
Notice: unserialize(): Unexpected end of serialized data in %sbug72663.php on line %d
Notice: unserialize(): Error at offset 49 of 50 bytes in %sbug72663.php on line %d

View file

@ -46,6 +46,7 @@ foreach($tests as $data)
?>
--EXPECTF--
Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d
==========
string(6) "String"
Test::__construct(String)