CTF Web题部分PHP魔术方法总结(Magic Methods)


简单介绍

方法名描述
__sleep()执行序列化serialize()时,先会调用这个函数
__wakeup()执行反序列化unserialize()时,先会调用这个函数
__get()当获得一个类的成员变量时调用
__set()当设置一个类的成员变量时调用
__isset()当对不可访问属性调用isset()或empty()时调用
__unset()当对不可访问属性调用unset()时被调用。
__construct()类的构造函数
__destruct()类的析构函数
__call()在对象中调用一个不可访问方法时调用
__callStatic()用静态方式中调用一个不可访问方法时调用
__autoload()尝试加载未定义的类
__toString()在将一个对象转化成字符串时自动调用

详细介绍

__sleep()

当你使用一个序列化函数serialize()的时候,该函数会检查代码中是否存在__sleep()函数。一旦存在这个函数便会优先执行__sleep(),然后再去执行原来的序列化,serialize()找sleep(),但是sleep也控制着serialize()的返回值,把握着把柄呢。

此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

注意点以及作用点

__sleep() 不能返回父类的私有成员的名字。
__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。

Example

<?php
class Person
{
    public $sex;
    public $name;
    public $age;

    public function __construct($name="",  $age=25, $sex='男')
    {
        $this->name = $name;
        $this->age  = $age;
        $this->sex  = $sex;
    }

    /**
     * @return array
     */
    public function __sleep() {
        echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>";
        $this->name = base64_encode($this->name);
        return array('name', 'age'); // 这里必须返回一个数值,里边的元素表示返回的属性名称,这边控制只返回两个数值。
    }
}

$person = new Person('1998'); // 初始赋值
echo serialize($person);
echo '<br/>';

输出结果

当在类外部使用serialize()时会调用这里的__sleep()方法
O:6:“Person”:2:{s:4:“name”;s:8:“MTk5OA==”;s:3:“age”;i:25;}

__wakeup()

理解: 当进行unserialize()反序列化之后立即被调用

存在漏洞

当在反序列化字符串当中如果表示属性个数的值大于其真实值,则跳过该魔术方法

例如XCTF这题

class xctf{ //类
public $flag = '111';//public定义flag变量公开可见
public function __wakeup(){
exit('bad requests');
}
?code=

如果单纯构造:O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}
并不能绕过__wakeup()的执行
如果构造:O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;} 便能绕过

__get()

书上是这样写的:

在程序运行过程中,在对象的外部获取私有成员的属性值,它有一个必要参数,即私有成员属性名,它返回一个允许对象在外部使用值。这个方法同样不需要主动调用,可以在方法前加上private关键字,防止用户直接调用

理解便是:
访问私有属性private、以及不存在的属性时被调用

__set()

书上是这样写的:

__set()方法:在程序运行过程中为私有的成员属性设置值,它不需要任何返回值。__set()方法包含两个参数,分别表示变量名称和变量值。两个参数不可省略,这个方法不需要主动调用,可以在方法前加上private关键字修饰,防止用户直接去调用。

理解便是:
__set( $property, $value )` 方法用来设置私有属性, 给一个未定义的属性赋值时,此方法会被触发,传递的参数是被设置的属性名和值。
Example

<?php
class Person
{
    private $name;
    private $age;

    public function __construct($name="",  $age=25)
    {
        $this->name = $name;
        $this->age  = $age;
    }

    /**
     * 声明魔术方法需要两个参数,真接为私有属性赋值时自动调用,并可以屏蔽一些非法赋值
     * @param $property
     * @param $value
     */
    public function __set($property, $value) {
        if ($property=="age")
        {
            if ($value > 150 || $value < 0) {
                return;
            }
        }
        $this->$property = $value;
    }

    /**
     * 在类中声明说话的方法,将所有的私有属性说出
     */
    public function say(){
        echo "我叫".$this->name.",今年".$this->age."岁了";
    }
}

$Person=new Person("小明", 25); //注意,初始值将被下面所改变
//自动调用了__set()函数,将属性名name传给第一个参数,将属性值”李四”传给第二个参数
$Person->name = "小红";     //赋值成功。如果没有__set(),则出错。
//自动调用了__set()函数,将属性名age传给第一个参数,将属性值26传给第二个参数
$Person->age = 16; //赋值成功
$Person->age = 160; //160是一个非法值,赋值失效
$Person->say();  //输出:我叫小红,今年16岁了

输出结果

我叫小红,今年16岁了

__isset()

理解:

用于检测变量是否存在,如果存在则返回true,否则返回false,用处便是为了对共有的成员属性进行检测,但不对私有的成员属性进行检测

__unset()

理解:

用于删除指定的变量,unset()函数可以对公有的成员属性进行删除操作,但是对于私有的成员属性还需依靠__unset()进行删除

Example:

void_unset(string name)

__construct()

php中构造方法是对象创建完成后第一个被对象自动调用的方法。在每个类中都有一个构造方法,如果没有显示地声明它,那么类中都会默认存在一个没有参数且内容为空的构造方法。

1、 构造方法的作用

通常构造方法被用来执行一些有用的初始化任务,如对成员属性在创建对象时赋予初始值。

2、 构造方法的在类中的声明格式


function __constrct([参数列表]){

    方法体 //通常用来对成员属性进行初始化赋值
}

3、 在类中声明构造方法需要注意的事项

1、在同一个类中只能声明一个构造方法,原因是,PHP不支持构造函数重载。

2、构造方法名称是以两个下画线开始的__construct()

Example:

<?php
    class Person
    {                                                                      
            public $name;        
            public $age;        
            public $sex;        
                                                                 
        /**
         * 显示声明一个构造方法且带参数
*/                                                                                      
        public function __construct($name="", $sex="男", $age=22)
        {      
            $this->name = $name;
            $this->sex = $sex;
            $this->age = $age;
        }
        /**
         * say 方法
         */
        public function say()
        { 
            echo "我叫:" . $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age;
        }   
    }
$Person1 = new Person();
echo $Person1->say(); //输出:我叫:,性别:男,年龄:22

$Person2 = new Person("1998");
echo $Person2->say(); //输出:我叫:1998,性别:男,年龄:22

$Person3 = new Person("李四","男",25);
echo $Person3->say(); //输出:我叫:李四,性别:男,年龄:25

__destruct()

理解:

简称回收垃圾函数,当所有方法执行完成后被调用,当对象不能被访问时就会自动启动垃圾回收机制,收回对象占用的内存空间。而析构函数正是在垃圾回收机制回收对象之前调用的。

__call()

书面表达:

当程序试图调用不存在或不可见的成员方法时,PHP会先调用__call()方法来存储方法名以及其参数。__call()方法包含两个参数,即方法名和方法参数。其中,方法参数是以数组的形式存在的

理解便是

调用了不存在或不可见的成员方法(注意调用时需要给定两个参数,方法名以及方法参数,输出的便会是不存在的方法名以及以数组形式输出的方法参数)

__callStatic()

理解:

当调用的静态方法不存在或权限不足时自动触发该方法

注意与__call()的区别:

__call()
   当对象访问不存在的方法时,__call()方法会被自动调用
__callStatic()
   当对象访问不存在的静态方法时,__callStatic()方法会被自动调用

一般使用::调用静态类

__autoload()

书面表达

能够自动实例化需要使用的类,当程序要用到一个类,但该类还没有被实例化时,利用该方法便能自动查找和该类名称相同的文件

理解

单纯的导类必备魔术方法

__toString()

书面表达

当使用echo或者print输出对象时,将对象转化成字符串

Example

<?php

class people{
    public function __toString(){
        return "I am toString module";
    }
}
$peo = new people();
echo $peo;
?>

输出

I am toString module

::的用法

外部调用类方法,或参数。只需要去找到::后面的方法即可,直接调用

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值