但凡是一个合格的PHP程序员就应该知道Unserialize与Autoload但是要说起二者之间的关系恐怕一清二楚的人就不多了 说个例子假设我们可以拿到第三方的序列化数据但没有相应的类定义代码如下
<?php
$string = O“Foobar”{s“foo”s“”s“bar”s“”}
$result = unserialize($string)
var_dump($result)
/*
object(__PHP_Incomplete_Class)[]
public __PHP_Incomplete_Class_Name => string Foobar (length=)
public foo => string (length=)
public bar => string (length=)
*/
?>当我们反序列化一个对象时如果对象的类定义不存在那么PHP会引入一个未完成类的概念即__PHP_Incomplete_Class此时虽然我们反序列化成功了但还是无法访问对象中的数据否则会出现如下报错信息
The script tried to execute a method or access a property of an incomplete object Please ensure that the class definition of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition
这不是什么难事儿只要做一次强制类型转换变成数组就OK了
<?php
$string = O“Foobar”{s“foo”s“”s“bar”s“”}
$result = (array)unserialize($string)
var_dump($result)
/*
array
__PHP_Incomplete_Class_Name => string Foobar (length=)
foo => string (length=)
bar => string (length=)
*/
?>
不过如果系统激活了Autoload情况会变得复杂些顺便插句话PHP其实提供了一个名为unserialize_callback_func配置选项但意思和autoload差不多这里就不介绍了咱们就说autoload例子如下 <?php
spl_autoload_register(function($name) {
var_dump($name)
})
$string = O“Foobar”{s“foo”s“”s“bar”s“”}
$result = (array)unserialize($string)
var_dump($result)
?>执行上面代码会发现spl_autoload_register被触发了多数时候这是有意义的但如果遇到一个定义不当的spl_autoload_register就悲催了比如说下面这段代码
<?php
spl_autoload_register(function($name) {
include “/path/to/{$name}php”
})
$string = O“Foobar”{s“foo”s“”s“bar”s“”}
$result = (array)unserialize($string)
var_dump($result)
?>
毫无疑问因为找不到类定义文件所以报错 了!改改spl_autoload_register肯定行但前提是你能改如果涉及第三方代码我们就不能擅自做主了此时我们需要一种方法让 unserialize能绕开autoload最简单的方法是把我们需要的类FAKE出来 <?php
spl_autoload_register(function($name) {
include “/path/to/{$name}php”
})
class Foobar {} // Oh Shit!
$string = O“Foobar”{s“foo”s“”s“bar”s“”}
$result = (array)unserialize($string)
var_dump($result)
?>不得不说上面的代码真的很狗屎!那怎么做才好呢?我大致写了一个实现
<?php
spl_autoload_register(function($name) {
include “/path/to/{$name}php”
})
$string = O“Foobar”{s“foo”s“”s“bar”s“”}
$functions = spl_autoload_functions()
foreach ($functions as $function) {
spl_autoload_unregister($function)
}
$result = (array)unserialize($string)
foreach ($functions as $function) {
spl_autoload_register($function)
}
var_dump($result)
?>代码虽然多了点但至少没有FAKE类看上去舒服多了 |