PHP反序列化一个没有匹配类的对象

3

我有一些包含序列化对象的数据库行。

我想要反序列化它们,但是类已经更改,某些属性变为私有,因此反序列化操作不再有效。

是否有一种方法可以强制反序列化成数组或stdClass?(或任何不会在反序列化时导致错误的内容)

我希望避免使用脚本迁移数据。我宁愿与旧格式中序列化的对象保持向后兼容性。


3
不是要挖苦什么的,但是:这就是为什么你不应该把代码存储在数据库中... :) - deceze
@deceze 同意。再也不要了!-_- - Matthieu Napoli
这就是为什么不要将对象存储为序列化字符串到数据库中的原因。 - GordonM
2个回答

12

不是很确定,或者说我很怕在生产环境中使用这样的东西。 不过,unserialize 会使用自动加载系统或在 unserialize_callback_func ini 设置中指定的函数名称。因此,只需进行一些小的修改就可以使其正常工作:

// this a serialized object with the class "SomeMissingClass"
$str = 'O:16:"SomeMissingClass":1:{s:1:"a";s:1:"b";}';
ini_set('unserialize_callback_func', 'define_me'); // set your callback_function

// unserialize will pass in the desired class name
function define_me($classname) {
    // just create a class that has some nice accessors to it
    eval("class $classname extends ArrayObject {}");
}
$object = unserialize($str);
print $object['a']; // should print 'b'

您可以使用类似以下的方法将数据迁移到更方便的格式。

更新:

我在这个问题上咨询了我的压抑记忆(我曾经遇到过类似的问题)并想起了另一个解决方案:

所以你有一个名为$aprivate属性的SomeClass

class SomeClass {
    private $a;
    public function getA(){
        return $this->a;
    }
}

而您拥有它的序列化版本:

$str = 'O:9:"SomeClass":1:{s:1:"a";s:1:"b";}';

当你反序列化它并输出结果,它会看起来像这样,这是不好的:
$a = unserialize($str);
var_dump($a->getA()); // prints 'null'
var_dump($a);
/* 
prints:
object(SomeClass)#1 (2) {
   ["a":"SomeClass":private]=>
   NULL
   ["a"]=>
   string(1) "b"
}
*/

当一个对象被反序列化时,php会调用它的__wakeup神奇方法。你需要的数据存储在对象中,但不是私有属性而是同名的公共属性。你不能通过$this->a来访问它,因为它会查找错误的属性,然而方法get_object_vars()将返回这些属性,你可以在__wakeup()内重新分配它们。
class SomeClass {
    private $a;
    public function getA(){
        return $this->a;
    }
    public function __wakeup(){
        foreach (get_object_vars($this) as $k => $v) {
            $this->{$k} = $v;
        }
    }
}
$str = 'O:9:"SomeClass":1:{s:1:"a";s:1:"b";}';
$a = unserialize($str);
print $a->getA();

我认为无需多说,你应该将数据转换成专门的数据交换格式,以免进一步头痛。

1
哇,这既聪明又可怕! - GordonM
谢谢你提供这些疯狂的想法!太棒了,我会用它来平滑地迁移到比序列化对象更合理的数据格式 :) - Matthieu Napoli

-1

除了手动修改数据库中的数据(这总是一个冒险的选择),我认为你唯一的选择就是将类代码回滚到旧版本,提取数据,然后以更明智的方式重新存储它,以便在未来的代码修订中更容易处理。

你的 SVN/GIT/CVS 中有旧的类吗?


是的,我希望尽可能避免迁移步骤,就像我之前说的那样。 - Matthieu Napoli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接