PHP 7.4向后不兼容的更改列表包含以下注释:
序列化
o序列化格式已被删除。由于它从来不是由PHP生成的,这可能只会破坏手工编制的字符串的非序列化。
(注意,这指的是小-o
格式,而不是用于对象序列化的大-O
格式。(
这似乎从未由PHP的serialize()
函数生成,但这个注释的存在意味着它被unserialize()
函数识别。
我做了一个小测试fiddle(3v4l.org(,这表明这不仅仅是big-O
的同义词,这是一种明显的可能性。
fiddle通过输出的错误消息中的差异来公开PHP中的更改。在PHP中>=7.4我们在位置0(遇到o
的地方(得到错误,而在7.4之前,在位置5(数据所在的地方(报告了错误。这意味着o
被识别,但数据的格式错误,这与我上面已经推导出的内容有关。
那么,o
序列化格式是什么?它反序列化为什么?如果PHP本身并没有生成它,为什么它支持这样的功能?
最初,PHP 3使用o:<num_fields>:{<fields>}
来序列化对象。
以下程序适用于PHP 4.0.0,可以从PHP.net/releases/index.PHP下载(Windows二进制文件仍然适用于Windows 10!(:
<?php
var_dump(unserialize('o:0:{}'));
输出:
X-Powered-By: PHP/4.0.0
Content-type: text/html
object(stdClass)(0) {
}
我能够将对象序列化格式的原始实现追溯到1999年的提交。请参阅php3api_var_serialize。
同年晚些时候,对象序列化格式被更改为包含为准备PHP 4而序列化的对象的类名。此提交将序列化格式更改为o:<classname_length>:"<class_name>":<num_fields>:{<fields>}
这使得PHP3和PHP4的输出不兼容:PHP4将无法取消对用PHP3序列化的对象的序列化。因此,添加了另一个提交,将o
更改为O
(小写o更改为大写o(。unserialize()
仍然支持o
取消序列化用PHP3序列化的对象,但serialize()
不再使用o
。
2000年,对序列化/非序列化代码进行了重构,生成了我们今天看到的文件。
可能发生的情况是,在这一过程中,兼容性层在某个地方断了,没有人足够关心PHP3兼容性来修复它。最初的代码不再适用于过去15年中发布的任何PHP版本。