下面的图片在学习的过程种截取的b站-橙子科技,师傅们可以在b站查看
目录标题
一、php面向对象基础
前置条件
- **面向对象:**一个直接呈现的结果 如游戏:王者荣耀
- **面向过程:**一个过程事件
序列化主要针对的是面向对象的过程 ,面向对象->类
- 变量(属性):如var $a=1
- 函数(方法):function A()
<?php
class A(){ #类
var $a;
var $b='track' #属性
function xxx(){ #方法
.......
}
echo $this->b; # $this是内置方法,调用当前类下的变量
}
?>
定义变量
<?php
class A(){
var $a; //基础定义
public $a; //全部可用
private $b; //外部不可用,只使用于当前类下
protected $c; //内部和子类可用
}
赋值与输出
<?php
class A{ //类
var $a; //属性
var $b;
function jineg($var1){ //方法,$var是变量
echo $this->a; //指向
echo $var1; //输出传入的变量
}
}
$i = new A();
$i -> a= 'hello';
$i -> b= 'track';
$i-> jineg("hyhy");
print_r($i);
/*
hellohyhyA Object
(
[a] => hello
[b] => track
)
*/
?>
二、序列化基础知识
序列化与赋值
<?php
class A{
var $a;
var $b;
function jineg(){
echo $this->a;
}
}
$i = new A();
$i -> a= 'hello';
$i -> b= 'track';
echo serialize($i);
?>
结果:
O:1(类的数量):"A":2(属性数量):{s(字符串):1((字符长度):"a";s:5:"hello";s:1:"b";s:5:"track";}
//对象 字符类型 变量名 值
三、魔术方法
首先在学习魔术方法,需要了解他们是如何被利用,即每个方法的触发点在哪,触发效果是什么,触发优先级是什么,如xx之前/xx之后
常见魔术方法
__construct()
- 触发时机:只触发一次,当对象创建时(即使用
new
关键字)会自动调用,即创建一个类 如:$a= new A(); - 反序列化中的行为:在反序列化时不会自动调用。
示例
class A{
var $cmd="system('id');";
public function _construct(){
eval($this->$cmd); #执行命令
}
}
$a=new A(); #当对象被实例化后,会自动调用函数
echo serialize($a);
__destruct()-析构函数
- 触发时机:当对象被销毁时会自动调用。反序列化之后/实例化对象后
- 反序列化中的行为:这是反序列化漏洞中最常利用的魔术方法之一,因为只要对象生命周期结束,就会触发此方法。
如下会触发两次,一次是实例化对象,一次是反序列化
代码如下
<?php
class A{
var $cmd="system('id');";
public function _destruct(){
eval($this->$cmd); #执行命令
}
}
$aaa=new A();
echo serialize($aaa); #O:1:"A":1:{s:3:"cmd";s:13:"system('id');";}
#$ser=$_GET['aaa'];
#unserialize($ser);
?>
__toString()-常用来构造pop链
- 触发时机:当一个对象被当作字符串使用时会自动调用。
- 反序列化中的行为:如果反序列化后的对象在某个上下文中被当作字符串处理,则会触发该方法。
class A{
var $user='hello';
public function __toString(){ //当一个对象(类)被当作字符串使用时会自动调用
return "track";
}
}
$a= new A();
print_r($a);
echo serialize($a); #O:1:"A":1:{s:4:"user";s:5:"hello";}
echo $a; #track 当执行时会把$a当作字符串打印,即会调用该方法
__invoke()-常用于构造pop链
- 触发时机:当脚本尝试将对象作为函数调用时会自动调用。
- 反序列化中的行为:如果反序列化后的对象在某个上下文中被当作函数调用,则会触发该方法。
function B(){
echo '没有调用方法';
}
class A{
public $user='hello';
public function __invoke(){ #当对象被当作函数执行调用
echo "调用了该方法";
}
}
B(); #没有调用方法
$a=new A();
$a(); #调用了该方法,因为该对象被当作一个函数执行
__sleep()
- 触发时机:在对象被序列化前会自动调用。
- 反序列化中的行为:虽然它在序列化时调用,但可以影响最终序列化的数据,从而间接影响反序列化。
会在对象被序列化之前触发,最终返回两个值
__wakeup()
- 触发时机:在对象被反序列化之前会自动调用。
- 反序列化中的行为:这是另一个常被利用的方法,因为它在反序列化过程中会被立即调用,用于重新建立数据库连接或其他资源初始化。
用一段代码解释
class A{
public $user;
public $pass;
public function _wakeup(){ #当反序列化执行之前会调用
system($this->$user);
}
}
#$x=$_GET['xx'];
#unserialize($x);
$a=new A();
$a->user="id"; #赋值
echo serialize($a); #调用_wakeup()方法
#O:1:"A":2:{s:4:"user";s:2:"id";s:4:"pass";N;}
#碰到这样的题目,其实可以简写
class B{
public $user='id';
}
echo serialize(new B());
#O:1:"B":1:{s:4:"user";s:2:"id";}
三、魔术方法-错误调用
__call()
- 触发时机:当调用一个不可访问或不存在的方法时会自动调用。 方法-函数
- 反序列化中的行为:如果反序列化后的对象尝试调用一个不存在的方法,会触发该方法。
如下,第一个变量返回方法,第二个返回属性,即返回值为 callxxx,a
__callStatic()
静态调用,作用和call相同,只不过调用方法不一样
__get() 和 __set()
- 触发时机:当尝试访问或设置一个不可访问或不存在的属性时会自动调用。
- 反序列化中的行为:如果反序列化后的对象尝试访问或设置这样的属性,会触发这些方法。
如下会返回var2
set会给不存在的赋值
__isset()和 __unset()
- 触发时机:当对一个不可访问或不存在的属性使用**
isset()
或unset()
**时会自动调用。 - 反序列化中的行为:类似地,在反序列化后,如果对对象的属性进行这些操作,会触发相应的方法。
调用的属性不可用
__clone()
- 触发时机:当对象被克隆时会自动调用。
- 反序列化中的行为:如果反序列化后的对象被克隆,会触发该方法。
这里会自动触发clone方法,因为克隆了一个新类
四、pop链
不可用
[外链图片转存中…(img-POOwJUJ1-1746499615004)]
__clone()
- 触发时机:当对象被克隆时会自动调用。
- 反序列化中的行为:如果反序列化后的对象被克隆,会触发该方法。
这里会自动触发clone方法,因为克隆了一个新类