Thinkphp5框架简单理解

article/2025/9/27 20:56:18

说明

该文章来源于同事lu2ker转载至此处,更多文章可参考:https://github.com/lu2ker/

目录

  • 说明
  • TP5框架简单理解
    • 1. 架构总览
      • 1.1 控制器/操作
      • 1.2 MVC模式流程
      • 1.3 类库自动加载
      • 1.4 URL访问检测
      • 1.5 路由模式
        • 1.5.1 普通模式
        • 1.5.2 混合模式
        • 1.5.4 强制路由
      • 1.6 路由定义
        • 1.6.1方式 1:路由到模块/控制器
        • 1.6.2 方式2:路由到重定向地址
        • 1.6.3 方式3:路由到控制器的方法
        • 1.6.4 方式4:路由到类的方法
      • 1.7 路由使用
      • 1.8 路由的其他知识
      • 1.9 其他东西
    • 2.请求相关
      • 2.1 如何获取请求参数的?
      • 2.2 检测变量是否设置
      • 2.3 请求方法
      • 2.4 【▲】请求方法伪装
      • 2.5 伪静态配置效果
      • 2.6 参数绑定
      • 2.7 请求缓存
    • 3. 数据库
    • 4. 模板
      • 4.1 变量输出
      • 4.2 使用函数、默认值
      • 4.3 TP内置标签
    • 5. 日志和错误
    • 6. 杂项
      • 6.1 缓存
      • 6.2 上传规则
    • Controller
    • Request(5.0.18版本)
      • 初始化和构造函数:instance和__construct
      • 方法注入:hook和__call
      • 当前的请求类型:method
      • 获取当前请求的参数:param
      • 获取GET数据:get
      • 获取POST数据:post
      • 获取cookie参数:cookie
      • 获取上传的文件信息:file
      • 被多处调用的方法:input
      • 递归过滤方法:filterValue

TP5框架简单理解

(PS:只做粗略、关键知识的记录,TP程序的开始。详情请阅读官方手册)

1. 架构总览

TP程序的开始

PHP >=5.3.0, PHP7

ThinkPHP5.0应用基于MVC(模型-视图-控制器)的方式来组织。

MVC是一个设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型(M)、视图(V)、控制器(C),它们各自处理自己的任务。

5.0的URL访问受路由决定,如果关闭路由或者没有匹配路由的情况下,则是基于:

http://serverName/index.php/模块/控制器/操作/参数/值…

1.1 控制器/操作

5.0的控制器类比较灵活,可以无需继承任何基础类库。控制器不应该过多的介入业务逻辑处理

一个典型的Index控制器类如下:控制器就是一个类,类里的不同的方法就是不同的操作

namespace app\index\controller;
use think\Request;class Index 
{public function index(){return 'hello,thinkphp!';}public function test(){$name = Request::instance()->param('name');echo "My name is " . $name;}
}

操作方法可以不使用任何参数,如果定义了一个非可选参数,则该参数必须通过用户请求传入,如果是URL请求,则通常是$_GET或者$_POST方式传入。

  • 如上代码第一行是确定了命名空间。什么是命名空间?

在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题。

  1. 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突
  2. 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

而TP5的思想是

ThinkPHP5采用命名空间方式定义和自动加载类库文件,有效的解决了多模块和Composer类库之间的命名空间冲突问题,并且实现了更加高效的类库自动加载机制。

  • 如上代码第二行use就是加载类库,调用TP5写好的Request类,其中实现了一些请求方法。

在这里插入图片描述

相对应的就是上面代码11行的Request::instance()->param('name');即获取客户端传入的参数name

1.2 MVC模式流程

通常一个基于TP开发的CMS,可能有很多个模块,而每个模块都是控制器—模型—视图完整的。控制器根据要求选择调用模型,模型进行业务逻辑处理,交给视图渲染。这个流程。

一个模块下面有多个控制器负责响应请求,而每个控制器其实就是一个独立的控制器类控制器主要负责请求的接收,并调用相关的模型处理,并最终通过视图输出。严格来说,控制器不应该过多的介入业务逻辑处理。

模型类通常完成实际的业务逻辑和数据封装,并返回和格式无关的数据

控制器调用模型类后返回的数据通过视图组装成不同格式的输出。视图根据不同的需求,来决定调用模板引擎进行内容解析后输出还是直接输出。

1.3 类库自动加载

命名空间的路径与类库文件的目录一致,那么就可以实现类的自动加载

如果想调用不同命名空间下的类库的方法,就要先用use给加载上。

1.4 URL访问检测

应用初始化完成后,就会进行URL的访问检测,包括PATH_INFO检测和URL后缀检测。

5.0的URL访问必须是PATH_INFO方式(包括兼容方式)的URL地址,例如:

http://serverName/index.php/index/index/hello/val/value

所以,如果你的环境只能支持普通方式的URL参数访问,那么必须使用

http://serverName/index.php?s=/index/index/hello&val=value

但是,这样也是行的:

http://serverName/index.php/index/index/hello/?val=value

我的环境可以用上面三种方式,都是默认配置。

1.5 路由模式

1.5.1 普通模式

‘url_route_on’ => false,

关闭路由,使用默认的PATH_INFO模式访问URL:如上面 1.4URL访问检测 的第一个
http://serverName/index.php/module/controller/action/param/value/…

1.5.2 混合模式

‘url_route_on’ => true,

‘url_route_must’=> false,

开启路由,也就是允许了自定义路由,同时对没有定义的路由使用默认的普通模式

1.5.4 强制路由

‘url_route_on’ => true,

‘url_route_must’=> true,

这种方式下面必须严格给每一个访问地址定义路由规则(包括首页),否则将抛出异常。

首页的路由规则采用/定义即可,例如下面把网站首页路由输出Hello,world!

Route::get('/',function(){return 'Hello,world!';
});

1.6 路由定义

ThinkPHP5 中支持 5种 路由地址方式定义:

定义方式定义格式
方式1:路由到模块/控制器‘[模块/控制器/操作]?额外参数1=值1&额外参数2=值2…’
方式2:路由到重定向地址‘外部地址’(默认301重定向) 或者 [‘外部地址’,‘重定向代码’]
方式3:路由到控制器的方法‘@[模块/控制器/]操作’
方式4:路由到类的方法‘\完整的命名空间类::静态方法’ 或者 ‘\完整的命名空间类@动态方法’
方式5:路由到闭包函数闭包函数定义(支持参数传入)

1.6.1方式 1:路由到模块/控制器

// 路由到默认或者绑定模块
'blog/:id'=>'blog/read', 				# 意思是如果访问blog/5,就会调用blog/read并传入参数id=5,下面同理
// 路由到index模块
'blog/:id'=>'index/blog/read',
----------------------------------------------
namespace app\index\controller;
class Blog {public function read($id){return 'read:'.$id;}
}

还支持多级控制器:

//多级控制器方式
'blog/:id'=>'index/group.blog/read'
----------------------------------------------
namespace app\index\controller\group;
class Blog {public function read($id){return 'read:'.$id;}
}

1.6.2 方式2:路由到重定向地址

举个例子,如果我们希望avatar/123重定向到/member/avatar/id/123_small的话,只能使用:

'avatar/:id'=>'/member/avatar/id/:id_small'# 区别于 'avatar/:id'=>'avatar/read' ,这个不是采用301重定向的。重定向的外部地址必须以“/”或者http开头的地址。

路由地址采用重定向地址的话,如果要引用动态变量,直接使用动态变量即可。

采用重定向到外部地址通常对网站改版后的URL迁移过程非常有用,例如:

'blog/:id'=>'http://blog.thinkphp.cn/read/:id'

表示当前网站(可能是http://thinkphp.cn )的 blog/123地址会直接重定向到 http://blog.thinkphp.cn/read/123。

1.6.3 方式3:路由到控制器的方法

'blog/:id'=>'@index/blog/read',
-------------------------------------
会执行 Loader::action('index/blog/read');
相当于直接调用 \app\index\controller\blog类的read方法。
namespace app\index\controller;
class Blog {public function read($id){return 'read:'.$id;}
}

1.6.4 方式4:路由到类的方法

'blog/:id'=>'\app\index\service\Blog@read'(动态方法)
或
'blog/:id'=>'\app\index\service\Blog::read',(静态方法)执行的是 \app\index\service\Blog类的read方法。

1.7 路由使用

application目录是这个应用的目录,index目录是这个应用的一个模块,其内的controller目录存放的是这个模块的控制器,同理一般modle目录就存放的模型,view目录就放的视图。(这里是单纯的框架所以没有)

在这里插入图片描述

#index.php
<?php
namespace app\index\controller;
use think\Request;
class Index
{public function index(){echo "hahaha";}public function test(){$name = Request::instance()->param('name');echo "My name is " . $name;}
}

1.8 路由的其他知识

// 使用注解路由
'route_annotation'       => true,class Index
{/*** @param  string  $name 数据名称* @return mixed* @route('hello/:name','get')*/public function hello($name){return 'hello,'.$name;}
}

其余的直接看这里(TP5.1的)就好

1.9 其他东西

tarit关键字关于这个东西,看PHP手册就行,我的目录下有CHM格式的手册;

'default_return_type'=>'json'修改config.php下的这个配置,可以使输出自动进行数据转换处理。Response类会统一处理。

2.请求相关

2.1 如何获取请求参数的?

首先要use一下TP写好的Request类,然后调用的话可以用很多种写法,下面是一种

<?php
namespace app\index\controller;
use think\Request;class Index 		// class Index extends Controller 解释如下:
//如果你继承了系统的控制器基类think\Controller的话,系统已经自动完成了请求对象的构造方法注入了,你可以直接使用$this->request属性调用当前的请求对象。
{/*** @var \think\Request Request实例*/protected $request;/*** 构造方法* @param Request $request Request对象* @access public*/public function __construct(Request $request){$this->request = $request;}public function index(){return $this->request->param('name');}    
}

还可以这些样子:

Request::instance=>param();//获取所有参数[ 结果类型数组],不分请求类型;
Request::instance=>param('name');//获取单个参数[即:直接填写变量名即可];
Request::instance=>get();//获取?后面的参数;
Request::instance=>route();//获取路由里面的参数; 
Request::instance=>post();//获取post请求参数
eg:
public function hello()
{$res=Request::instance()->param();var_dump($res);
}
//这是依赖注入方式,无论是否继承系统的控制器基类,都可以使用操作方法注入。
public function hello(Request $request)
{$res=$request->param();var_dump($res);
}
//也可以使用助手函数
$request = request();

2.2 检测变量是否设置

可以使用has方法来检测一个变量参数是否设置,如下:

Request::instance()->has('id','get');
Request::instance()->has('name','post');

或者使用助手函数(助手函数很棒很简单)

input('?get.id');
input('?post.name');

2.3 请求方法

可以通过Request对象完成全局输入变量的检测、获取和安全过滤,支持包括$_GET$_POST$_REQUEST$_SERVER$_SESSION$_COOKIE$_ENV等系统变量,以及文件上传信息。

方法描述
param获取当前请求的变量
get获取 $_GET 变量
post获取 $_POST 变量
put获取 PUT 变量
delete获取 DELETE 变量
session获取 $_SESSION 变量
cookie获取 $_COOKIE 变量
request获取 $_REQUEST 变量
server获取 $_SERVER 变量
env获取 $_ENV 变量
route获取 路由(包括PATHINFO) 变量
file获取 $_FILES 变量

也可以在获取变量的时候添加过滤方法,例如:

Request::instance()->get('name','','htmlspecialchars'); // 获取get变量 并用htmlspecialchars函数过滤
Request::instance()->param('username','','strip_tags'); // 获取param变量 并用strip_tags函数过滤
Request::instance()->post('name','','org\Filter::safeHtml'); // 获取post变量 并用org\Filter类的safeHtml方法过滤
//可以支持传入多个过滤规则,例如:
Request::instance()->param('username','','strip_tags,strtolower');// 获取param变量 并依次调用strip_tags、strtolower函数过滤

2.4 【▲】请求方法伪装

支持请求类型伪装,可以在POST表单里面提交_method变量,传入需要伪装的请求类型,例如:

<form method="post" action=""><input type="text" name="name" value="Hello"><input type="hidden" name="_method" value="PUT" ><input type="submit" value="提交">
</form>

提交后的请求类型会被系统识别为PUT请求。你可以设置为任何合法的请求类型,包括GETPOSTPUTDELETE等。如果你需要改变伪装请求的变量名,可以修改应用配置文件:

// 表单请求类型伪装变量
'var_method'             => '_m',

2.5 伪静态配置效果

'url_html_suffix' => 'shtml'http://serverName/Home/Blog/read/id/1
等价于
http://serverName/Home/Blog/read/id/1.shtml
如果'url_html_suffix' => ''
则
任何后缀都能正常访问// 关闭伪静态后缀访问
'url_html_suffix' => false,
http://serverName/index/blog/read/id/3.html
id参数的值会被解析为3.html

2.6 参数绑定

就是给控制器下的方法(函数),给上参数,这样在url访问的时候就直接加上这个参数再给个值就能自动获取,不需要写Request。

在这里插入图片描述

2.7 请求缓存

例子:如果设置了这样一条路由,其中指定了cache字段。

Route::get('bind/:id','Index/bind',['cache'=>3600]);

那么只有第一次访问时会走正常的C-M-V流程,也就是会真正去调用控制器下的操作方法。

之后再访问同样路由的话,检测到同样的路由就不会再去调用控制器下的操作方法了,而是直接从缓存中获取响应。很给力。

3. 数据库

相信跟完那几个SQLi漏洞的代码分析,就已经对TP种数据库操作有些了解了,故略。

4. 模板

4.1 变量输出

// index.php 控制器
use think\Controller;
use think\View;
class Index extends Controller
{public function index(){$view = new View();$view->name = 'thinkphp';return $view->fetch();}
}# index.html
<html>Hello,{$name}</html>

可以大致理解为:访问index方法,fetch渲染时会把name变量给传到index.html,而模板引擎解析的{$name}实际上就是<?php echo($name);?>

注意模板标签的{$之间不能有任何的空格,否则标签无效。

输出数组变量的value用{$array.key}

输出对象属性value用{$obj:property}或者${obj->property}

输出其他变量(比如系统变量)以KaTeX parse error: Expected '}', got 'EOF' at end of input: Think开头,比如`{Think.cookie.name}`

4.2 使用函数、默认值

{$name|md5|strtoupper|substr=0,3}
# 解释:多个函数之间用“|”分割编译后即为:
<?php echo (substr(strtoupper(md5($name)),0,3)); ?># 还可以简单的写法
{:substr(strtoupper(md5($name)),0,3)}# 加个默认值
{$user.nickname|default="这家伙很懒,什么也没留下"}

4.3 TP内置标签

内置标签还是全一点把,遇到忘了的直接去开发手册查

PS:这儿有一个简单的MVC代码案例

5. 日志和错误

6. 杂项

6.1 缓存

支持的缓存类型包括file、memcache、wincache、sqlite、redis和xcache。

驱动方式就是指什么形式存 缓存的数据

如果定义了多个缓存驱动:

// 切换到file操作
Cache::store('file')->set('name','value');
Cache::get('name');
// 切换到redis操作
Cache::store('redis')->set('name','value');
Cache::get('name');

在TP类库里面thinkphp\library\think\db\Query.php这个数据库查询类调用Cache比较多。

Session 、Cookie 和 缓存差不多。

6.2 上传规则

默认情况下,会在上传目录下面生成以当前日期为子目录,以微秒时间的md5编码为文件名的文件。

/upload/20160510/42a79759f284b767dfcb2a0197904287.jpg

而且一般都在public/upload/目录下。

还有可能以32位哈希的前两位当子目录。

上传时可以用 f i l e − > r u l e ( ) 自定义文件名生成的规则,如 ‘ file->rule()自定义文件名生成的规则,如` file>rule()自定义文件名生成的规则,如file->rule(‘md5’)->move(‘/home/www/upload/’);`

File类的成员函数move()执行成功后文件成功上传,返回一个File类的对象,失败返回false。可以看看File类都有哪些成员,毕竟是文件相关的类,很有用。

File类继承了PHP的SplFileObject类,因此可以调用SplFileObject类所有的属性和方法。SplFileObject手册解释

Controller

大多是一些模板渲染的方法。从构造函数中就可以看出来,

public function __construct(Request $request = null){$this->view    = View::instance(Config::get('template'), Config::get('view_replace_str'));$this->request = is_null($request) ? Request::instance() : $request;// 控制器初始化$this->_initialize();// 前置操作方法if ($this->beforeActionList) {foreach ($this->beforeActionList as $method => $options) {is_numeric($method) ?$this->beforeAction($options) :$this->beforeAction($method, $options);}}}

刚开始就实例化了View类。想到之前复现的ThinkPHP的SQL注入漏洞,有些测试代码就会调用fetch、assign、display这些方法。而模块开发的开始就是从 application\模块\controller 下面开始的。应用模块的控制器如果继承了Controller类,就能直接调用这些方法进行视图渲染。

这个类还有两个方法:beforeAction和validate

beforeAction是前置操作:设置 beforeActionList属性可以指定某个方法为其他方法的前置操作,数组键名为需要调用的前置方法名,无值的话为当前控制器下所有方法的前置方法。

['except' => '方法名,方法名']
#表示这些方法不使用前置方法,
['only' => '方法名,方法名']
#表示只有这些方法使用前置方法。# demo
protected $beforeActionList = ['first','second' =>  ['except'=>'hello'],'three'  =>  ['only'=>'hello,data'],];# 类内所有方法调用前都会调用first方法
# 类内hello方法不会调用second这个前置方法
# 只有hello,data方法会前置调用three方法。

如果你在自己继承了Controller的控制器代码中定义了protected $beforeActionList,那么它就会在构造函数中foreach处理后,调用beforeAction进行only还是except的判断,最后用call_user_func调用。

call_user_func([$this, $method])

这种写法是对类内方法的调用,这里的$this指向的是继承Controller类的Index类。也就是说回调的函数必须在Index类中定义好了。

validate验证器方法主要还是调用的Validate类,应该是为了方便控制器对数据的验证。

具体流程就是用 加载验证器 的 加载器,来加载验证器。。。。。

如果传入的KaTeX parse error: Undefined control sequence: \library at position 25: …个数组,就先用thinkphp\̲l̲i̲b̲r̲a̲r̲y̲\think\Validate…this里面。不是数组的话就直接调用。

Request(5.0.18版本)

前置PHP知识:PHP中self :: 和 this-> 的用法

前置PHP知识:new static 和 new self的区别 -主要就是有继承的时候的区别

下面只列举部分重要方法

初始化和构造函数:instance和__construct

public static function instance($options = []){if (is_null(self::$instance)) {self::$instance = new static($options);}return self::$instance;}protected function __construct($options = []){foreach ($options as $name => $item) {if (property_exists($this, $name)) {		//类属性覆盖$this->$name = $item;}}if (is_null($this->filter)) {$this->filter = Config::get('default_filter');		//在应用目录下的config.php}// 保存 php://input$this->input = file_get_contents('php://input');}

instance就是Request的初始化方法,编程中这种是叫“单例模式”,目的是为了防止实例化的时候构造方法被多次调用,就先new了一下自己然后返回。

property_exists判断 t h i s ,也就是本类对象是否存在传入的 this,也就是本类对象是否存在传入的 this,也就是本类对象是否存在传入的name属性,存在即赋值。接着还定义了过滤器,并获取了输入流(请求body)

这样初始化调用:$req = Request::instance()->get('a');

方法注入:hook和__call

public static function hook($method, $callback = null){if (is_array($method)) {self::$hook = array_merge(self::$hook, $method);} else {self::$hook[$method] = $callback;}}public function __call($method, $args){if (array_key_exists($method, self::$hook)) {array_unshift($args, $this);return call_user_func_array(self::$hook[$method], $args);} else {throw new Exception('method not exists:' . __CLASS__ . '->' . $method);}}

hook方法和__call魔术方法配合,使得可以在类外面自定义Request的方法。算是扩展性的实现。hook主要是来获取自定义函数的,然后因为这个函数本身不在Request中,所以会调用__call方法,检查这个函数是不是在hook数组里面,在的话就说明这是一个要注入的方法,就将Request类本身的$this对象作为自定义函数的参数传入,通过call_user_func_array进行调用。自定义函数使用闭包的写法:

# application\index\controller\Index.php
public function index(){$req = Request::instance();$callback = function($RR){echo "匿名函数";$RR->test111();};Request::hook('invoke',$callback);$req->invoke();}
# thinkphp\library\think\Request.php添加一个如下方法:
public function test111(){echo "可以调用Request本身的方法";}# 访问index.php/index/输出:匿名函数可以调用Request本身的方法

当前的请求类型:method

public function method($method = false){if (true === $method) {// 获取原始请求类型return IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']);} elseif (!$this->method) {if (isset($_POST[Config::get('var_method')])) {$this->method = strtoupper($_POST[Config::get('var_method')]);$this->{$this->method}($_POST);} elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {$this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);} else {$this->method = IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']);}}return $this->method;}

IS_CLI是用来判断是使用命令行还是浏览器执行的,cli代表命令行。

t h i s − > s e r v e r 和 this->server和 this>server_SERVER的区别应该是:前者提供了程序可定义的请求方法(在create方法中),后者是获取客户端请求的 请求方法。

如果调用method时没传入true,分三种情况:

① 如果配置了var_method,从$_POST[Config::get('var_method')],即$_POST['_method']获取请求方法。

在这里插入图片描述

有意思的是这条语句$this->{$this->method}($_POST);,用花括号包裹 先执行取值在以 t h i s 调用传入 this调用传入 this调用传入_POST。

在这里插入图片描述

② 通过请求包的HTTP头字段X-HTTP-METHOD-OVERRIDE来设置method

在这里插入图片描述

③ 和true === $method时一样

获取当前请求的参数:param

该方法主体中是对请求参数的处理:包括针对不同的请求方法,选择调用Request类里不同的处理方法;还有获取文件上传信息的处理。获取post、get、put、file等请求参数的合并数据。但这些处理都不是方法内实现的,而是调用的Request类的其他成员方法。

获取GET数据:get

支持传入数组:

t h i s − > g e t = a r r a y m e r g e ( this->get = array_merge( this>get=arraymerge(this->get, $name);

获取POST数据:post

public function post($name = '', $default = null, $filter = ''){if (empty($this->post)) {$content = $this->input;if (empty($_POST) && false !== strpos($this->contentType(), 'application/json')) {$this->post = (array) json_decode($content, true);} else {$this->post = $_POST;}}if (is_array($name)) {$this->param       = [];return $this->post = array_merge($this->post, $name);}return $this->input($this->post, $name, $default, $filter);}

比get特别的地方在于,会从php://input输入流中获取数据,这里的$content = $this->input;是在构造函数中初始化的。然后还能用json_decode处理json数据并返回为数组格式的。

获取cookie参数:cookie

会调用filterValue方法过滤数据。而且如果cookie是个数组的话还会使用array_walk_recursive递归调用filterValue

获取上传的文件信息:file

会实例化File类,@return null|array|\think\File 返回这三种类型的数据。具体获取文件的什么信息再看。

被多处调用的方法:input

该方法有一个参数是$filter默认为空,说明支持可设置的过滤器。

处理流程在ThinkPHP5之SQLI审计分析(一)里面看过了。

递归过滤方法:filterValue

private function filterValue(&$value, $key, $filters){$default = array_pop($filters);foreach ($filters as $filter) {if (is_callable($filter)) {// 调用函数或者方法过滤$value = call_user_func($filter, $value);} elseif (is_scalar($value)) {if (false !== strpos($filter, '/')) {// 正则过滤if (!preg_match($filter, $value)) {// 匹配不成功返回默认值$value = $default;break;}} elseif (!empty($filter)) {// filter函数不存在时, 则使用filter_var进行过滤// filter为非整形值时, 调用filter_id取得过滤id$value = filter_var($value, is_int($filter) ? $filter : filter_id($filter));if (false === $value) {$value = $default;break;}}}}return $this->filterExp($value);}

$filters是数组类型的,说明可以进行多个过滤器的处理。在判断了过滤器可以被调用后,就马上用call_user_func来调用过滤器处理数据了。

方法开头会用array_pop弹出默认过滤器,是在getFilter方法将所有接收到的过滤器放到数组里后,又在数组末尾加的那个$default


  1. 利用method的任意方法调用,调用构造函数__construct,且调用时会传入$_POST数据,那么组合起来就是执行method方法可以控制类的成员变量的值。

  2. filterValue中存在 call_user_func函数可以恶意利用,其参数$filters

  3. getFilter方法存在这样$filter = $filter ?: $this->filter;一条语句获取类成员变量filter(由1知可控)。

  4. input方法中存在:先调用getFilter获取到filter,再使用array_walk_recursive递归调用filterValue并传入filter的情况。

综上,如果找到一处先调用method再调用input且的调用点,就能够利用call_user_func造成RCE。

param方法就完美符合条件。


http://chatgpt.dhexx.cn/article/rTEmZ5yg.shtml

相关文章

ThinkPHP框架-2

十、ThinkPHP框架中的模型 模型的作用、处理业务数据、与数据库进行交互。 1、导入数据表 新建tpshop数据库(create database tpshop character set utf8 collate utf8_general_ci) 导入数据表 说明&#xff1a;如果导入sql文件时&#xff0c;有报错&#xff0c;提示类似“…

ThinkPHP框架介绍及应用

一.ThinkPHP介绍 1.1.什么是框架 PHP框架是许多代码的集合&#xff0c;这些代码是程序结构的代码(并不是业务代码)&#xff0c;代码中有许多函数、类、功能类包&#xff0c;框架的代码按照一定标准组成了一个有机的功能体&#xff0c;这个功能体中有许多设计模式如MVC、单例、…

thinkPHP框架学习(速成,一天)

一。TP框架介绍与配置 第一个是最开始沿用的一种结构&#xff0c;它有一个致命的缺点&#xff1a;比如说如果后端程序员在编写的过程中&#xff0c;前端程序就不能做修改&#xff0c;一旦修改了&#xff0c;那么肯定会有冲突。 后来大家进行了改进----把前端脱离出来。 再后来…

【代码审计-PHP】基于Thinkphp框架开发的

前言&#xff1a; 介绍&#xff1a; 博主&#xff1a;网络安全领域狂热爱好者&#xff08;承诺在CSDN永久无偿分享文章&#xff09;。 殊荣&#xff1a;CSDN网络安全领域优质创作者&#xff0c;2022年双十一业务安全保卫战-某厂第一名&#xff0c;某厂特邀数字业务安全研究员&…

thinkphp框架的使用

ThinkPhp知识大全&#xff08;非常详细&#xff09; 转载文章&#xff0c;感觉写的非常好 thinkphp.cn thinkphp 3.2版本 【框架项目部署】 部署一个Shop项目&#xff0c;使用tp框架 步骤&#xff1a; 创建入口文件&#xff1a; 1.在ThinkPHP目录下创建一个入口文件index.…

PHP之ThinkPHP框架

一、框架概述 1、什么是框架 框架就是一些代码类、方法&#xff08;函数&#xff09;、变量、常量的集合&#xff0c;这些代码是功能结构性的代码&#xff08;并非业务代码&#xff09;。业务代码其实就是具体的一些模块的增删改查逻辑代码。 使用框架开发项目&#xff0c;有…

ThinkPHP框架之快速入门

一.创建工程tp&#xff0c;目录结构如下: 在工程下导入thinkphp。 在tp中&#xff0c;可以在任何目录下创建入口文件&#xff0c;也可以把项目初始化到任何目录下. index.php: <?php //定义thindphp的路径 define(THINK_PATH, ./ThinkPHP/); //默认值当前目录下的./Thi…

PHP_thinkPHP框架(1)

能够理解并使用composer PHP一个包管工具 解决源码包 依赖问题 ​ 1.7.3 软件升级 composer self-update 能够安装Thinkphp5.1框架 composer create-project --prefer-dist topthink/think[版本号] 目录名称 ​ 安装之前一定要切换国内源&#xff0c;否则成功的概率很小。 …

使用ThinkPHP框架快速开发网站(多图)

使用ThinkPHP框架快速搭建网站 这一周一直忙于做实验室的网站&#xff0c;基本功能算是完成了。比较有收获的是大概了解了ThinkPHP框架。写一些东西留作纪念吧。如果对于同样是Web方面新手的你有一丝丝帮助&#xff0c;那就更好了挖。 以前用PHP做过一个很蹩脚的网站&#xff0…

ThinkPHP框架完全解析一

第一步&#xff1a;搭建应用和框架目录 文件系统结构如上图所示&#xff0c;新建一个名为tp_an的目录作为我们的应用目录。其中&#xff0c;ThinkPHP这个目录&#xff0c;就是thinkphp框架的目录。所有涉及到框架的开发&#xff0c;都会在ThinkPHP中进行。只是为了方便测试&…

Thinkphp框架初始及安装部署

一、框架概述 1、什么是框架 框架就是一些代码类、方法&#xff08;函数&#xff09;、变量、常量的集合&#xff0c;这些代码是功能结构性的代码&#xff08;并非业务代码&#xff09;。业务代码其实就是具体的一些模块的增删改查逻辑代码。 使用框架开发项目&#xff0c;有…

认识thinkphp框架

https://www.thinkphp.cn/down.html 版本5.0.24 ThinkPHP是一个免费开源的&#xff0c;快速、简单的面向对象的轻量级PHP开发框架 tp5 WEB部署目录&#xff08;或者子目录&#xff09; ├─application 应用目录 │ ├─common 公共模块目录&#xff08;可以更改&#xff09; …

【Java教程系列】IDEA快捷键大全。

自动代码 常用的有fori/sout/psvmTab即可生成循环、System.out、main方法等boilerplate样板代码 。 例如要输入for(User user : users)只需输入user.forTab &#xff1b; 再比如&#xff0c;要输入Date birthday user.getBirthday()只需输入user.getBirthday().varTab即可。…

IDEA快捷键大全(超详细!)

4.1、字体设置 file --> settings --> 输入font --> 设置字体样式以及字号大小。 4.2、快速生成main方法 psvm、main 4.3、快速生成System.out.println() sout 4.4、注意&#xff1a;IDEA是自动保存&#xff0c;不需要ctrl s 4.5、删除一行 ctrl y 4.6、怎…

IDEA的实用快捷键大全

目录 1.常规快捷键 1.1通用类 1.2注释类 1.3操作类 1.4展开与关闭 2.智能补全类快捷键 3.程序结构类快捷键 4.统一操作快捷键 1.常规快捷键 1.1通用类 像 Ctrl C 复制&#xff0c; Ctrl V 粘贴&#xff0c; Ctrl S保存文件&#xff0c; Ctrl X剪切&#xff0c;这种…

IDEA快捷键大全 + 动图演示

目录 一、构建/编译二、文本编辑三、光标操作四、文本选择五、代码折叠六、多个插入符号和范围选择七、辅助编码八、上下文导航九、查找操作十、符号导航十一、代码分析十二、运行和调试十三、代码重构十四、全局 CVS 操作十五、差异查看器十六、工具窗口 一、构建/编译 Ctrl …

Idea快捷键大全(Windows)/Intellij IDEA常用快捷键介绍 Intellij IDEA快捷键大全汇总

Ctrl 快捷键 介绍 Ctrl F 在当前文件进行文本查找 &#xff08;必备&#xff09; Ctrl R 在当前文件进行文本替换 &#xff08;必备&#xff09; Ctrl Z 撤销 &#xff08;必备&#xff09; Ctrl Y 删除光标所在行 或 删除选中的行 &#xff08;必备&#x…

python 相关性检验怎么计算p值_挖掘数据内部联系:相关性分析

相关性表示的是两个观测的数据向量之间的变化关系。一般来讲研究对象(样品或处理组)之间使用距离分析,而元素(物种或环境因子)之间进行相关性分析。两个变量之间的相关性可以用简单相关系数(例如皮尔森相关系数等)进行表示,相关系数越接近1,两个元素相关性越大,相关系数越接…

python 相关性检验怎么计算p值_数据分析---用Python进行相关性分析(兼谈假设检验)...

一、相关关系和相关系数 世上除了因果关系,还有相关关系。 有一个叫“相关系数”的指标来量化两个事物之间的相关程度。 其中相关系数用“r”表示,取值范围介于-1和1之间。 当(X,Y)正相关的时候,r=1;当(X,Y)负相关的时候,r=-1;当(X,Y)不相关的时候,r=0。 当然一般的线性…

python 相关性检验怎么计算p值_机器学习:数据的准备和探索——数据假设检验...

图 | 源网络 文 | 5号程序员 数据假设检验是数理统计学中根据一定假设条件由样本推断总体的一种方法。 那我们啥时候会用到假设检验呢? 大多数情况下,我们无法分辨事物的真伪或者某种说法是否正确,这时就需要进行假设,然后对我们的假设进行检验。 比如,我们想知道被告人是…