序列化

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。通俗来讲就是将变量或对象转换成字符串。

反序列化

很好理解,就是将序列化反过来,通过unserialize()函数重新把字符串变回php原来的值。


多说无益,直接看例子。
先看序列化

<?php
class person
{
    var $name;
    var $age;
    var $sex;
    private $admin=233;
    protected $id=123;

    function act()
    {
        echo 'hello,world';
    }
}
$p1=new person();

$p1->name='xiaolong';
$p1->age=21;
$p1->sex='man';

$result=serialize($p1);  //序列化
echo $result;
?>

运行结果

O:6:"person":3:{s:4:"name";s:8:"xiaolong";s:3:"age";i:21;s:3:"sex";s:3:"man";s:13:"personadmin";i:233;s:5:"*id";i:123;}
O代表'object',如果是A的话代表数组
6代表类名是6个字符串,person代表类名,3代表类中有3个属性(变量)
s:4:"name";代表string类型的4字符串长度的属性名(int的话是i)
s:8:"xiaolong";代表string类型的8字符串长度的属性的值
...
private的属性,序列化后的格式为 %00类名%00属性名 (%00代表空格,也算一个字符)
protected的属性,序列化后的格式 %00*%00属性名

ps:序列化不保存对象的方法


再来看反序列化

<?php
class person
{
    var $name;
    var $age;
    var $sex;
    private $admin=233;
    protected $id=123;

    function act()
    {
        echo 'hello,world';
    }
}
$p1=new person();

$p1->name='xiaolong';
$p1->age=21;
$p1->sex='man';

$result=serialize($p1);  //序列化
$unresult=unserialize($result); //反序列化
echo $unresult->name;
echo '<br/>';
echo $unresult->act();
?>

运行结果

xiaolong
hello,world

接下来介绍几个魔术方法(也叫魔法函数)

  • __construct() 在创建(new)对象时自动调用
  • __destruct() 在对象销毁(反序列化)时调用
  • __sleep() 在序列化对象前调用
  • __toString() 当对象被当做字符串使用时调用
  • __wakeup() 在反序列化时被调用,但当序列化字符串表示对象属性个数的数字值大于真实类中属性的个数时就会跳过__wakeup的执行


    举例

    __destruct()

    <?php
    class xiaolong
    {
      var $number=23;
    
      function __destruct()
      {
          echo 'hello';
      }
    }
    $a=$_GET['number'];
    $fxlh=unserialize($a);
    ?>

    运行结果
    请输入图片描述

试想一下,如果__destruct()中不是hello而是命令执行,那就会执行我们的恶意代码

class xiaolong
{
    var $number='';

    function __destruct()
    {
        eval($this->number);
    }
}
$a=$_GET['number'];
$fxlh=unserialize($a);
?>

运行结果
请输入图片描述


__sleep()

<?php
class xiaolong
{
    var $number=23;

    function __sleep()
    {
        echo 'hello';
    }
}
$p3=new xiaolong();
serialize($p3);
?>

运行结果
hello


__wakeup()

<?php
class xiaolong
{
    var $number=23;

    function __wakeup()
    {
        echo 'hello';
    }
}
$a=$_GET['number'];
$fxlh=unserialize($a);
?>

运行结果
请输入图片描述

当序列化字符串表示对象属性个数的数字值大于真实类中属性的个数时会跳过__wakeup的执行

请输入图片描述

因为在反序列化时会检查存不存在__wakeup()函数,如果存在就会调用,这时我们就可以通过这个方法来绕过。

可以看到反序列化本身没什么威力,要配合这些魔术方法才能产生威力

最后修改:2023 年 12 月 15 日
如果觉得我的文章对你有用,请随意赞赏