2.序列化漏洞之魔法方法
什么是魔法方法
PHP 将所有以 __
(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __
为前缀。
魔法方法是不显示的调用而是由某种特定的条件出发的
下面是官方给出来的说明和使用的魔法方法
https://www.php.net/manual/zh/language.oop5.magic.php
__construct魔法方法
__construct
类会在每次创建新对象时先调用此方法
所以非常适合在使用对象之前做一些初始化工作
简单理解就是__construct
会在类里面自动执行
列如:
1 |
|
结果
__sleep()和__wakeup()魔法方法
__sleep()
和__wakeup()
其实是一样的就是被调用的函数不一样serialize()
函数会检查类中是否存在一个魔术方法 __sleep()
,如果存在,该方法会先被调用unserialize()
函数会检查类中是否存在一个魔术方法 __wakeup()
,如果存在,该方法会先被调用
__sleep()魔法方法实咧
serialize()
函数会检查类中是否存在一个魔术方法 __sleep()
,如果存在,该方法会先被调用,然后才执行序列化操作
此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误
注意
__sleep() 不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。
用于
方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
实咧:
1 |
|
结果:
如果我把__sleep()
里面的内容注释掉他会返回什么
代码
1 |
|
结果
__wakeup()魔法方法实咧
unserialize()
才会触发__wakeup()
魔法方法unserialize()
函数会检查类中是否存在一个魔术方法 __wakeup()
,如果存在,该方法会先被调用
他和__sleep()
是一样的
1 |
|
结果
__destruct()魔法方法
__destruct()
这个函数在对象被销毁前会被执行
下面参数会用到unset()
函数,他是删除销毁一个变量函数等等
咧:
1 |
|
结果
__toString()魔法方法
__toString()
用于一个类被当成字符串时应怎样回应,
通俗简单来说就是叫一个对象用输出的函数当做字符串来输出
注意
此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误
这个通俗的来讲就是如果没有__toString()
直接输出对象就会报错
列:
1 |
|
结果
如果我不用__toString()
会怎么样下面我就测试一下
1 |
|
结果他就报错了
__call()魔法方法
当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用__call()
在给不可访问属性赋值时,__set() 会被调用。
读取不可访问属性的值时,__get() 会被调用。
等等
通俗来说就是你访问一个对象中没有的东西就会调用__call()
作用
为了避免当调用的方法不存在时产生错误,而意外的导致程序中止,可以使用 __call() 方法来避免。
__call($a,$b)
他有两个参数,也可以不带$a
,就是你调用一个对象里面没有的属性的名,那么$a
就是属性的名$b
,就是你调用一个对象里面没有的属性的名,并传递参数那这个$b
就是被传的参数,应为参数很多$b
就是一个数组
下面访问一个对象里面不存在的属性和方法,__call()
就会被执行
咧:
1 |
|
结果
下面访问一个对象里面不存在的方法,__call()
就不会被执行
咧:
1 |
|
结果
__callStatic魔法方法
__callStatic
方法在调用对象静态方法不存在的时候被调用
__callStatic
和__call()
是一样的__call()
就是一个是访问普通的类内容不存在会被调用__callStatic
方法在调用对象静态方法不存在的时候被调用
作用
为了避免当调用的静态方法不存在时产生错误,而意外的导致程序中止,可以使用 __callStatic
方法来避免。
__callStatic($a,$b)
他有两个参数,也可以不带$a
,就是你调用一个对象里面没有的属性的名,那么$a
就是属性的名$b
,就是你调用一个对象里面没有的属性的名,并传递参数那这个$b
就是被传的参数,应为参数很多$b
就是一个数组
咧:
1 |
|
结果
__get()魔法方法
类的成员属性被设定为 private 后,如果我们试图在外面调用它则会出现“不能访问某个私有属性”的错误。那么为了解决这个问题,我们可以使用魔术方法 __get()
用于
在程序运行过程中,通过它可以在对象的外部获取私有成员属性的值。
__get($a)
他有一个参数$a
参数传入你要获取的成员属性的名称,返回获取的属性值
咧:
1 |
|
结果
__set魔法方法
在类外赋值一个类内的私有属性和给一个未定义的属性赋值时,此方法会被触发
简单来说就是你放一个私有的或者给他赋值或者没有这个属性,此方法会被触发
__set($a,$b)
他有两个参数,也可以不带$a
,就是你调用一个对象里面没有的属性的名,那么$a
就是属性的名$b
,就是你调用一个对象里面没有的属性的名,并传递参数那这个$b
就是被传的参数,应为参数很多$b
就是一个数组
咧:
1 |
|
结果