【问题标题】:unserialize() stopped working after adding Serializable interface添加 Serializable 接口后 unserialize() 停止工作
【发布时间】:2019-07-10 12:01:02
【问题描述】:

我有一个使用 serialize() 存储在 MySql 中的对象。

现在我已经通过实现Serializable 接口更新了类定义,但我无法反序列化对象,因为:

Erroneous data format for unserializing 'ClassName'

此类的调试方法unserialize() 没有帮助 - 它甚至没有被调用。

举个例子,假设我有旧的 (A) 和新的 (B​​) 类声明:

<?php

 class A {
     public $hello = "world";
 }

  class B implements Serializable {
     public $hello = "world";
     public function serialize() {}
     public function unserialize($serialized) { throw new Exception("test"); }
 }

现在当我尝试反序列化数据时:

$data1 = 'O:1:"A":1:{s:5:"hello";s:5:"world";}';
$data2 = 'O:1:"B":1:{s:5:"hello";s:5:"world";}';

var_dump(unserialize($data1));
var_dump(unserialize($data2));

我明白了

object(A)#2 (1) {
  ["hello"]=>
  string(5) "world"
}
<br />
<b>Warning</b>:  Erroneous data format for unserializing 'B' in <b>[...][...]</b> on line <b>20</b><br />
<br />
<b>Notice</b>:  unserialize(): Error at offset 11 of 36 bytes in <b>[...][...]</b> on line <b>20</b><br />
bool(false)

【问题讨论】:

  • 是否安装了任何框架和/或扩展?
  • 不,它是纯 php 7.3
  • PHP 的序列化有时非常难以预测,并且充满了细微差别。我的猜测是实现序列化接口以某种方式改变了序列化过程(通过改变要使用的数据)它不再像以前没有使用接口时一样,因此序列化抱怨无效数据。如果可能,最好迁移到 json。
  • 对这个问题投赞成票真的不再合适。它包含重现问题的完整 MCVE。

标签: php oop serialization


【解决方案1】:

问题在于实现Serializable 的类和未实现接口的类使用不同的序列化格式

没有实现接口的类会使用“O notation”:

O:1:"A":1:{s:5:"hello";s:5:"world";}

而实现Serializable 的类将使用“C 表示法”。你的B 类,序列化后看起来像这样:

C:1:"B":12:{s:5:"world";}

反序列化不起作用,因为您试图反序列化到“错误”的定义。

由于旧行为的安全隐患,此更改发生在 5.6,was reported as a bug and the response was wontfix

据我所知,您尝试执行的操作仅适用于 PHP 5.3 到 5.5。文档曾经提到,对于实现 Serializable 的类,在调用 unserialize() 之前调用了 __wakeup() 方法,但这是 5.6 中删除的部分内容。

您需要使用一些解决方法来反序列化该数据,从长远来看,我会将序列化数据迁移到更安全、更便携的格式,例如 JSON。

【讨论】:

    猜你喜欢
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 2017-11-25
    • 2021-11-08
    相关资源
    最近更新 更多