php 详解序列化及反序列化特征

概述

  • php 在定义一个数组,类等很多东西的时候,为了数据传递的方便,都可以对一个对象或者实例进行序列化

对一个数组进行序列化

1
2
3
4
5
6
7
8
<?php
$sites = array('Google', 'Runoob', 'Facebook');
$serialized_data = serialize($sites);
echo $serialized_data . PHP_EOL;
?>

//输出结果
a:3:{i:0;s:6:"Google";i:1;s:6:"Runoob";i:2;s:8:"Facebook";}

对一个进行序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class F{
public $filename='a.txt';
}

$a = new F();
echo $a->filename.'<br />';
echo serialize($a);
?>

//输出结果
a.txt
O:1:"F":1:{s:8:"filename";s:5:"a.txt";}

序列化格式

拿上面这个类的序列化进行举例

1
O:1:"F":1:{s:8:"filename";s:5:"a.txt";}
  • O 序列化对象的类型,其中有

    类型 解释
    a 数组
    b 布尔值
    d 双精度浮点型
    i 整型
    o 普通对象
    r 引用
    s 字符串
    C 自定义对象
    O
    N null值
    R 指针引用
    U Unicode 字符串
  • 1 序列化的类名的(字符串)长度

  • "F"类名本身(字符串形式)

  • 1 是这个类中属性(变量)的数量

  • {s:8:”filename”}s 代表属性名(字符串)的类型

  • {s:8:”filename”}8 代表属性名(字符串)的长度

  • {s:8:”filename”}filename 代表属性名(字符串)本身

  • {s:5:”a.txt”}s 代表属性值(字符串)的类型

  • {s:5:”a.txt”}5 代表属性值(字符串)的长度

  • {s:5:”a.txt”}a.txt 代表属性值(字符串)本身

  • 序列化结束后的属性内容最后是有一个分号的

序列化的访问控制修饰符造成的影响

  • protected 属性被序列化的时候 属性名 会变成 %00*%00属性名
  • private 属性被序列化的时候 属性名 会变成 %00类名%00属性名

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class Ctf{
public $name='Sch0lar';
protected $age='19';
private $flag='get flag';
}
$ctfer=new Ctf(); //实例化一个对象
echo serialize($ctfer);
?>

//输出结果
O:3:"Ctf":3:{s:4:"name";s:7:"Sch0lar";s:6:"*age";s:2:"19";s:9:"Ctfflag";s:8:"get flag";}
//因为 protected 的影响,序列化后的 s:6:"*age" 星号前后有两个不可见的空格
//因为 private 的影响,序列化后的 s:9:"Ctfflag" 会以空格(不可见) + 类名 + 空格(不可见) + 类名 构成

魔术方法

  • 魔术方法是不算在序列化中属性内容或属性数量里边的

序列化特别的魔术方法- __sleep()

  • 如果在序列化的时候,发现其中有特殊的魔术方法,则会触发不同的序列化效果
  • 该方法决定了类中那些属性需要被序列化。如果有此方法,未指明的属性将不会被序列化,若无此方法,则默认全部序列化
  • 如果有 __sleep() 方法时,序列化时该方法最先被调用

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class Ctf{
public $flag='flag{****}';
public $name='cxk';
public $age='10';
public function __sleep(){
return array('flag','age');
}
}
$ctfer=new Ctf();
$ctfer->flag='flag{abedyui}';
$ctfer->name='Sch0lar';
$ctfer->age='18'
echo serialize($ctfer);
?>

//输出结果,只序列化__sleep()声明 flag 和 age
O:3:"Ctf":2:{s:4:"flag";s:13:"flag{abedyui}";s:3:"age";s:2:"18";}

反序列化特别的魔术方法- __wakeup()

  • 序列化时不会调用,反序列化时检测到此魔术方法,便会依据该方法内的改变,对类中的属性信息(包括属性名,属性值)进行变更
  • 如果有 __wakeup() 方法时,反序列化时该方法最先被调用

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
class Ctf{
public $flag='flag{****}';
public $name='cxk';
public $age='10';
public function __wakeup(){
$this->flag='no flag'; //在反序列化时,flag属性将被改变为“no flag”
}
}
$ctfer=new Ctf(); //实例化一个对象
$ctfer->flag='flag{adedyui}';
$ctfer->name='Sch0lar';
$ctfer->age='18'

$str=serialize($ctfer);
echo '<pre>';
var_dump(unserialize($str));
?>

//输出结果
object(Ctf)#2 (3) {
["flag"]=>
string(13) "no flag"
["name"]=>
string(7) "Sch0lar"
["age"]=>
string(2) "18"
}
Author

Resek4

Posted on

2022-02-25

Updated on

2023-01-27

Licensed under

Comments