PHP的“o”序列化格式是什么?
PHP 7.4 向后不兼容的更改列表包含以下注释:
序列化
o 序列化格式已被删除。由于它从未由 PHP 生成,因此这可能只会破坏手动制作的字符串的反序列化。
(请注意,这指的是 little- o,而不是O用于对象序列化的 big-格式。)
似乎这从未由 PHP 的serialize()函数生成,但是此注释存在的事实意味着它已被unserialize()函数识别。
我做了一个小测试小提琴 (3v4l.org),它表明这不仅仅是big-的同义词O,这将是一个明显的可能性。
小提琴通过输出的错误消息中的差异公开了 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)的提交。
o仍然支持反unserialize()序列化用 PHP3 序列化的对象,但serialize()不再使用o。
2000年,序列化/反序列化代码被重构,产生了我们今天看到的文件。
可能发生的事情是兼容层在此过程中的某个地方出现了故障,并且没有人足够关心 PHP3 的兼容性来修复它。一开始的代码不再适用于过去 15 年发布的任何 PHP 版本。
- Wow - with your update, this is an amazing answer! So much detail, and exactly the kind of historical information I was looking for. In fact, it's so good, I'm going to award a bounty for it, even though your answer is already posted!