forked from php/php-src
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix phpGH-8996: DOMNode serialization on PHP ^8.1
PHP 8.1 introduced a seemingly unintentional BC break in ca94d55 by blocking the (un)serialization of DOM objects. This was done because the serialization never really worked and just resulted in an empty object, which upon unserialization just resulted in an object that you can't use. Users can however implement their own serialization methods, but the commit made that impossible as the ACC flag gets passed down to the child class. An approach was tried in php#10307 with a new ACC flag to selectively allow serialization with subclasses if they implement the right methods. However, that was found to be too ad hoc. Instead, let's abuse how the __sleep and __wakeup methods work to throw the exception instead. If the child class implements the __serialize / __unserialize method, then the throwing methods won't be called. Similarly, if the child class implements __sleep and __wakeup, then they're overridden and it doesn't matter that they throw. For the user, this PR has the exact same behaviour for (sub)classes that don't implement the serialization methods: an exception will be thrown. For code that previously implemented subclasses with these methods, this approach will make that code work again. This approach should be both BC preserving and unbreak user's code. For the test: Co-authored-by: wazelin <contact@sergeimikhailov.com>
- Loading branch information
Showing
5 changed files
with
160 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
--TEST-- | ||
GH-8996: DOMNode serialization on PHP ^8.1 | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
|
||
echo "=== __sleep and __wakeup ===\n"; | ||
|
||
class SerializableDomDocumentSleepWakeup extends DOMDocument | ||
{ | ||
private $xmlData; | ||
|
||
public function __sleep(): array | ||
{ | ||
$this->xmlData = $this->saveXML(); | ||
return ['xmlData']; | ||
} | ||
|
||
public function __wakeup(): void | ||
{ | ||
$this->loadXML($this->xmlData); | ||
} | ||
} | ||
|
||
$dom = new SerializableDomDocumentSleepWakeup('1.0', 'UTF-8'); | ||
$dom->loadXML('<tag>value</tag>'); | ||
|
||
$serialized = serialize($dom); | ||
var_dump($serialized); | ||
$unserialized = unserialize($serialized); | ||
|
||
echo "Serialized:\n-----------\n$serialized\n-----------\nRestored:\n-----------\n{$unserialized->saveXml()}"; | ||
|
||
echo "=== __serialize and __unserialize ===\n"; | ||
|
||
class SerializableDomDocumentSerializeUnserialize extends DOMDocument | ||
{ | ||
public function __serialize(): array | ||
{ | ||
return ['xmlData' => $this->saveXML()]; | ||
} | ||
|
||
public function __unserialize(array $data): void | ||
{ | ||
$this->loadXML($data['xmlData']); | ||
} | ||
} | ||
|
||
$dom = new SerializableDomDocumentSerializeUnserialize('1.0', 'UTF-8'); | ||
$dom->loadXML('<tag>value</tag>'); | ||
|
||
$serialized = serialize($dom); | ||
$unserialized = unserialize($serialized); | ||
|
||
echo "Serialized:\n-----------\n$serialized\n-----------\nRestored:\n-----------\n{$unserialized->saveXml()}"; | ||
|
||
?> | ||
--EXPECTF-- | ||
=== __sleep and __wakeup === | ||
string(144) "O:34:"SerializableDomDocumentSleepWakeup":1:{s:43:"%0SerializableDomDocumentSleepWakeup%0xmlData";s:39:"<?xml version="1.0"?> | ||
<tag>value</tag> | ||
";}" | ||
Serialized: | ||
----------- | ||
O:34:"SerializableDomDocumentSleepWakeup":1:{s:43:"%0SerializableDomDocumentSleepWakeup%0xmlData";s:39:"<?xml version="1.0"?> | ||
<tag>value</tag> | ||
";} | ||
----------- | ||
Restored: | ||
----------- | ||
<?xml version="1.0"?> | ||
<tag>value</tag> | ||
=== __serialize and __unserialize === | ||
Serialized: | ||
----------- | ||
O:43:"SerializableDomDocumentSerializeUnserialize":1:{s:7:"xmlData";s:39:"<?xml version="1.0"?> | ||
<tag>value</tag> | ||
";} | ||
----------- | ||
Restored: | ||
----------- | ||
<?xml version="1.0"?> | ||
<tag>value</tag> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--TEST-- | ||
DOM classes are not unserializable | ||
--EXTENSIONS-- | ||
dom | ||
--FILE-- | ||
<?php | ||
|
||
$classes = [ | ||
"DOMXPath", | ||
"DOMDocument", | ||
"DOMNode", | ||
"DOMNameSpaceNode", | ||
]; | ||
|
||
foreach ($classes as $class) | ||
{ | ||
try { | ||
unserialize('O:' . strlen($class) . ':"' . $class . '":0:{}'); | ||
} catch (Exception $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
} | ||
|
||
?> | ||
--EXPECT-- | ||
Unserialization of 'DOMXPath' is not allowed | ||
Unserialization of 'DOMDocument' is not allowed | ||
Unserialization of 'DOMNode' is not allowed | ||
Unserialization of 'DOMNameSpaceNode' is not allowed |