最近感觉自己学的很难受,甚至在想自己还要不要学了,一直学的没什么效果吧。。。
今天重新学一下序列化的内容吧
一、概念
- 什么是序列化和反序列化?
- 为什么要序列化和反序列化?
序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。
1、常用的函数是serialize和unserialize函数
(注意数组的输出要用print_r)
从输出可以看出,反序列化的结果种a代表数组,3代表三个变量,括号内的s表示字符串,1等数字表示变量名及变量的长度;同时可以看到反序列化的数组经过序列化回到原来的数组值
当数组值包含如双引号、单引号或冒号等字符时,它们被反序列化后,可能会出现问题。为了克服这个问题,一个巧妙的技巧是使用base64_encode和base64_decode
$a = array();
//序列化
$b = base64_encode(serialize($a));
//反序列化
$c = unserialize(base64_decode($b));
但是base64编码将增加字符串的长度。为了克服这个问题,可以和gzcompress(压缩字符串)一起使用。
function my_serialilze($a)//序列化函数
{
return base64_encode(gzcompress(serialize($a)));
}
function my_unserialize($b)//反序列化函数
{
return unserialize(gzuncompress(base64_decode($b)));
}
2、json_encode 和 json_decode
使用json_encode和json_decode格式输出要比serialize和unserialize格式快得多。
JSON格式是可读的。
JSON格式比serialize返回数据结果小。
JSON格式是开放的、可移植的。其他语言也可以使用它。
<?php
$a=array('a'=>'fanfan','b'=>'xixi','c'=>'abab');
echo $b=serialize($a);
echo '<br />';
echo $b1=json_encode($a);
echo '<br />';
print_r($c=unserialize($b));
echo '<br />';
print_r($c=json_decode($b1));
可以看到json_encode输出的长度明显要短一些
3、var_export 和 eval
var_export 函数把变量作为一个字符串输出;
eval把字符串当成PHP代码来执行,反序列化得到最初变量的内容。
echo $b2=var_export($a,true);
eval('$my_var='. $b . ';');
print_r($my_var);//这个应该不对吧,不是很明白,是有错的
4、wddx_serialize_value 和 wddx deserialize
wddx_serialize_value函数可以序列化数组变量,并以XML字符串形式输出。
echo $b3=wddx_serialize_value($a);
//输出结果:<wddxPacket version='1.0'><header/><data><struct><var name='a'><string>fanfan</string></var><var name='b'><string>xixi</string></var><var name='c'><string>abab</string></var></struct></data></wddxPacket>
二、php的几个魔术方法
魔术方法 如何调用
__wakeup() 当调用unserialize()函数时自动调用
__construct() 当一个类被创建时自动调用
__destruct() 当一个类被销毁时自动调用
__tostring() 当把一个类当作字符串使用时自动调用
__sleep() 当调用serialize()函数时自动调用
__invoke() 当把一个类当作函数使用时自动调用
__call() 当要调用的方法不存在或权限不足时自动调用
还有几个知识点:
__wakeup()的漏洞:如果一个类的实际属性个数小于序列化的属性个数的话,就会跳过不执行__wakeup()函数(还需要补充)
__construct()函数常用于构造方法
如果在类中定义的成员修饰符是private,则正确的序列化是%00类名%00成员名
如果在类中定义的成员修饰符是protected,则正确的序列化是%00%00成员名
1、_construct():构造函数,当类实例化时用来初始化对象或是赋初值;每次通过new运算符创建对象时自动被调用;
2、_destruct()(与_construct函数相对应):析构函数,当对象所有引用都被删除或是对象被显示销毁时,系统会自动执行析构函数;
3、与序列化直接相关的函数
- _sleep
当进行类序列化操作时,调用serialize()函数会先检查类种是否存在_sleep()函数,存在的话会先调用_sleep(),再执行序列化操作;_sleep()函数会返回一个数组,其中包含对象中所有应被序列化的变量名称,如果该方法未返回任何内容,则NULL被序列化,并产生一个错误。
<?php
class FAN{
public $a;
public $b;
public $c;
public function __construct($a,$b){
$this->a = $a;
$this->b = $b;
}
public function __sleep(){
$this->c = $this->a.$this->b;
return array('a','c');//返回了a,c,也就是下面的ver和verweb
}
}
$c = new FAN('ver','web');
$d = serialize($c);
echo $d;//O:3:"FAN":2:{s:1:"a";s:3:"ver";s:1:"c";s:6:"verweb";}
当调用unserialize()函数时会先检查是否存在_wakeup()函数,如果存在的话,会在成功重构对象后调用_wakeup(),多用于与数据库重新建立连接上。
<?php
class FAN{
public $a;
public $b;
public $c;
public function __construct($a,$b){
$this->a = $a;
$this->b = $b;
}
public function __weakup()
{
$this->b = $this->a . $this->c;
}
}
$d='O:3:"FAN":2:{s:1:"a";s:3:"ver";s:1:"c";s:6:"verweb";}';
var_dump(unserialize($d));
//object(FAN)#1 (3) {
["a"]=>
string(3) "ver"
["b"]=>
NULL//因为没有对a和c传参,所以是NULLS
["c"]=>
string(6) "verweb"
}
以上只是相关的简单操作,接下来会重点学习对于某些操作会出现的问题,以及剩下的几个魔术方法及其调用关系,session机制,和重新学习phar://协议