PHP 反序列化一个没有匹配类的对象 [英] PHP unserialize an object without the matching class
问题描述
我有包含序列化对象的数据库行.
I have database rows containing serialized objects.
我想反序列化这些,但类已更改,某些属性变为私有,因此反序列化不再有效.
I want to deserialize these, but the class has changed, some properties went private so the deserialization no longer works.
有没有办法强制反序列化为数组或 stdClass?(或任何不会导致反序列化错误的东西)
Is there a way to force deserialization to an array or a stdClass? (or anything that won't cause an error upon deserialization)
我想避免使用脚本迁移数据.我宁愿与以旧格式序列化的对象向后兼容.
I want to avoid migrating data with a script. I'd rather have backward compatibility with the objects serialized in the old format.
推荐答案
不是真的,或者至少我会非常害怕在生产中使用这样的东西.但是,unserialize
将使用自动加载系统或 unserialize_callback_func
ini 设置中指定的函数名称.因此,只需稍加修改,您就可以完成这项工作:
Not really, or at least i would be pretty afraid to use something like this in production.
However, unserialize
will use the autoload system or the function name specified in the unserialize_callback_func
ini setting. So with a little hacking you can make this work:
// 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'
您可以使用类似的方法将数据迁移到更方便的格式.
You can use something like this to migrate your data to a little more handy format.
我已经咨询了我压抑的记忆(我曾经遇到过这样的事情)并想起了另一个解决方案:
I've consulted with my repressed memories on this (i've faced something like this once) and remembered an other solution:
所以你的 SomeClass
有一个名为 $a
So you have your SomeClass
with a private
property named $a
class SomeClass {
private $a;
public function getA(){
return $this->a;
}
}
你有它的序列化版本:
$str = 'O:9:"SomeClass":1:{s:1:"a";s:1:"b";}';
当你反序列化它并转储结果时,它看起来像这样,这是不好的:
When you unserialize it, and dump the result it will look like this, which is no good:
$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()
中重新分配它们:
Now, when an object get's unserialized, php will call it's __wakeup
magic method. The data you need is there in the object, but not under the private property but a similarly named public one. You can't reach that with the $this->a
since it will look for the wrong one,
however the method get_object_vars()
will return these properties and you can reassign them inside a __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();
我认为不用说,您应该避免进一步的麻烦并将您的数据转换为某种专用的数据交换格式.
I think it's needless to say that you should save yourself the further headache and convert your data to some dedicated data exchange format.
这篇关于PHP 反序列化一个没有匹配类的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!