PHP 的"o"序列化格式是干什么用的?



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版本。

最新更新