PHP在没有匹配类的情况下取消对对象的序列化


PHP unserialize an object without the matching class

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

我想反序列化这些,但类已经更改,一些属性变为私有属性,因此反序列化不再有效。

有没有办法强制对数组或stdClass进行反序列化?(或任何在反序列化时不会导致错误的东西)

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

不是真的,或者至少我会非常害怕在生产中使用这样的东西。但是,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'

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

更新:

我查阅了我压抑的记忆(我曾经面对过这样的事情),并记住了另一个解决方案:

因此,您的SomeClass具有名为$aprivate属性

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();

我认为不用说,你应该省去更多的麻烦,将你的数据转换为一些专用的数据交换格式。

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

你的SVN/GIT/CVS中确实有旧的类,对吧?