ThinkPHP框架 3.2.3学习记录

ThinkPHP 3.2.3

目录结构

1
2
3
4
5
├─index.php       入口文件
├─README.md README文件
├─Application 应用目录
├─Public 资源文件目录
└─ThinkPHP 框架目录

其中框架目录ThinkPHP的结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
├─ThinkPHP 框架系统目录(可以部署在非web目录下面)
│ ├─Common 核心公共函数目录
│ ├─Conf 核心配置目录
│ ├─Lang 核心语言包目录
│ ├─Library 框架类库目录
│ │ ├─Think 核心Think类库包目录
│ │ ├─Behavior 行为类库目录
│ │ ├─Org Org类库包目录
│ │ ├─Vendor 第三方类库目录
│ │ ├─ ... 更多类库目录
│ ├─Mode 框架应用模式目录
│ ├─Tpl 系统模板目录
│ ├─LICENSE.txt 框架授权协议文件
│ ├─logo.png 框架LOGO文件
│ ├─README.txt 框架README文件
│ └─ThinkPHP.php 框架入口文件

入口文件

入口文件是应用的单一入口,对应用的所有请求都定向到应用入口文件,系统会从URL参数中解析当前请求的模 块、控制器和操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------

// 应用入口文件

// 检测PHP环境
if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !');

// 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false
define('APP_DEBUG',True);

// 定义应用目录
define('APP_PATH','./Application/');

// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';

// 亲^_^ 后面不需要任何代码了 就是如此简单

看到后面引用 ./ThinkPHP/ThinkPHP.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------

//----------------------------------
// ThinkPHP公共入口文件
//----------------------------------

// 记录开始运行时间
$GLOBALS['_beginTime'] = microtime(TRUE);
// 记录内存初始使用
define('MEMORY_LIMIT_ON',function_exists('memory_get_usage'));
if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage();

// 版本信息
const THINK_VERSION = '3.2.3';

// URL 模式定义
const URL_COMMON = 0; //普通模式
const URL_PATHINFO = 1; //PATHINFO模式
const URL_REWRITE = 2; //REWRITE模式
const URL_COMPAT = 3; // 兼容模式

// 类文件后缀
const EXT = '.class.php';

// 系统常量定义
defined('THINK_PATH') or define('THINK_PATH', __DIR__.'/');
defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/');
defined('APP_STATUS') or define('APP_STATUS', ''); // 应用状态 加载对应的配置文件
defined('APP_DEBUG') or define('APP_DEBUG', false); // 是否调试模式

if(function_exists('saeAutoLoader')){// 自动识别SAE环境
defined('APP_MODE') or define('APP_MODE', 'sae');
defined('STORAGE_TYPE') or define('STORAGE_TYPE', 'Sae');
}else{
defined('APP_MODE') or define('APP_MODE', 'common'); // 应用模式 默认为普通模式
defined('STORAGE_TYPE') or define('STORAGE_TYPE', 'File'); // 存储类型 默认为File
}

defined('RUNTIME_PATH') or define('RUNTIME_PATH', APP_PATH.'Runtime/'); // 系统运行时目录
defined('LIB_PATH') or define('LIB_PATH', realpath(THINK_PATH.'Library').'/'); // 系统核心类库目录
defined('CORE_PATH') or define('CORE_PATH', LIB_PATH.'Think/'); // Think类库目录
defined('BEHAVIOR_PATH')or define('BEHAVIOR_PATH', LIB_PATH.'Behavior/'); // 行为类库目录
defined('MODE_PATH') or define('MODE_PATH', THINK_PATH.'Mode/'); // 系统应用模式目录
defined('VENDOR_PATH') or define('VENDOR_PATH', LIB_PATH.'Vendor/'); // 第三方类库目录
defined('COMMON_PATH') or define('COMMON_PATH', APP_PATH.'Common/'); // 应用公共目录
defined('CONF_PATH') or define('CONF_PATH', COMMON_PATH.'Conf/'); // 应用配置目录
defined('LANG_PATH') or define('LANG_PATH', COMMON_PATH.'Lang/'); // 应用语言目录
defined('HTML_PATH') or define('HTML_PATH', APP_PATH.'Html/'); // 应用静态目录
defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH.'Logs/'); // 应用日志目录
defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH.'Temp/'); // 应用缓存目录
defined('DATA_PATH') or define('DATA_PATH', RUNTIME_PATH.'Data/'); // 应用数据目录
defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH.'Cache/'); // 应用模板缓存目录
defined('CONF_EXT') or define('CONF_EXT', '.php'); // 配置文件后缀
defined('CONF_PARSE') or define('CONF_PARSE', ''); // 配置文件解析方法
defined('ADDON_PATH') or define('ADDON_PATH', APP_PATH.'Addon');

// 系统信息
if(version_compare(PHP_VERSION,'5.4.0','<')) {
ini_set('magic_quotes_runtime',0);
define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()? true : false);
}else{
define('MAGIC_QUOTES_GPC',false);
}
define('IS_CGI',(0 === strpos(PHP_SAPI,'cgi') || false !== strpos(PHP_SAPI,'fcgi')) ? 1 : 0 );
define('IS_WIN',strstr(PHP_OS, 'WIN') ? 1 : 0 );
define('IS_CLI',PHP_SAPI=='cli'? 1 : 0);

if(!IS_CLI) {
// 当前文件名
if(!defined('_PHP_FILE_')) {
if(IS_CGI) {
//CGI/FASTCGI模式下
$_temp = explode('.php',$_SERVER['PHP_SELF']);
define('_PHP_FILE_', rtrim(str_replace($_SERVER['HTTP_HOST'],'',$_temp[0].'.php'),'/'));
}else {
define('_PHP_FILE_', rtrim($_SERVER['SCRIPT_NAME'],'/'));
}
}
if(!defined('__ROOT__')) {
$_root = rtrim(dirname(_PHP_FILE_),'/');
define('__ROOT__', (($_root=='/' || $_root=='\\')?'':$_root));
}
}

// 加载核心Think类
require CORE_PATH.'Think'.EXT;
// 应用初始化
Think\Think::start();

这里主要是设置一些环境变量,然后加载require CORE_PATH.'Think'.EXT;

核心文件主要是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
["core"]=>
array(11) {
[0]=>
string(45) "E:\XP\WWW\think\ThinkPHP/Common/functions.php"
[1]=>
string(40) "./Application/Common/Common/function.php"
[2]=>
string(53) "E:\XP\WWW\think\ThinkPHP\Library/Think/Hook.class.php"
[3]=>
string(52) "E:\XP\WWW\think\ThinkPHP\Library/Think/App.class.php"
[4]=>
string(59) "E:\XP\WWW\think\ThinkPHP\Library/Think/Dispatcher.class.php"
[5]=>
string(54) "E:\XP\WWW\think\ThinkPHP\Library/Think/Route.class.php"
[6]=>
string(59) "E:\XP\WWW\think\ThinkPHP\Library/Think/Controller.class.php"
[7]=>
string(53) "E:\XP\WWW\think\ThinkPHP\Library/Think/View.class.php"
[8]=>
string(69) "E:\XP\WWW\think\ThinkPHP\Library/Behavior/BuildLiteBehavior.class.php"
[9]=>
string(73) "E:\XP\WWW\think\ThinkPHP\Library/Behavior/ParseTemplateBehavior.class.php"
[10]=>
string(74) "E:\XP\WWW\think\ThinkPHP\Library/Behavior/ContentReplaceBehavior.class.php"
}

ThinkPHP框架内解析路由的文件在Route.class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP路由解析类
*/
class Route {

// 路由检测
public static function check(){
$depr = C('URL_PATHINFO_DEPR');
$regx = preg_replace('/\.'.__EXT__.'$/i','',trim($_SERVER['PATH_INFO'],$depr));
// 分隔符替换 确保路由定义使用统一的分隔符
if('/' != $depr){
$regx = str_replace($depr,'/',$regx);
}
// URL映射定义(静态路由)
$maps = C('URL_MAP_RULES');
if(isset($maps[$regx])) {
$var = self::parseUrl($maps[$regx]);
$_GET = array_merge($var, $_GET);
return true;
}
// 动态路由处理
$routes = C('URL_ROUTE_RULES');
if(!empty($routes)) {
foreach ($routes as $rule=>$route){
if(is_numeric($rule)){
// 支持 array('rule','adddress',...) 定义路由
$rule = array_shift($route);
}
if(is_array($route) && isset($route[2])){
// 路由参数
$options = $route[2];
if(isset($options['ext']) && __EXT__ != $options['ext']){
// URL后缀检测
continue;
}
if(isset($options['method']) && REQUEST_METHOD != strtoupper($options['method'])){
// 请求类型检测
continue;
}
// 自定义检测
if(!empty($options['callback']) && is_callable($options['callback'])) {
if(false === call_user_func($options['callback'])) {
continue;
}
}
}
if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由
if($route instanceof \Closure) {
// 执行闭包
$result = self::invokeRegx($route, $matches);
// 如果返回布尔值 则继续执行
return is_bool($result) ? $result : exit;
}else{
return self::parseRegex($matches,$route,$regx);
}
}else{ // 规则路由
$len1 = substr_count($regx,'/');
$len2 = substr_count($rule,'/');
if($len1>=$len2 || strpos($rule,'[')) {
if('$' == substr($rule,-1,1)) {// 完整匹配
if($len1 != $len2) {
continue;
}else{
$rule = substr($rule,0,-1);
}
}
$match = self::checkUrlMatch($regx,$rule);
if(false !== $match) {
if($route instanceof \Closure) {
// 执行闭包
$result = self::invokeRule($route, $match);
// 如果返回布尔值 则继续执行
return is_bool($result) ? $result : exit;
}else{
return self::parseRule($rule,$route,$regx);
}
}
}
}
}
}
return false;
}

// 检测URL和规则路由是否匹配
private static function checkUrlMatch($regx,$rule) {
$m1 = explode('/',$regx);
$m2 = explode('/',$rule);
$var = array();
foreach ($m2 as $key=>$val){
if(0 === strpos($val,'[:')){
$val = substr($val,1,-1);
}

if(':' == substr($val,0,1)) {// 动态变量
if($pos = strpos($val,'|')){
// 使用函数过滤
$val = substr($val,1,$pos-1);
}
if(strpos($val,'\\')) {
$type = substr($val,-1);
if('d'==$type) {
if(isset($m1[$key]) && !is_numeric($m1[$key]))
return false;
}
$name = substr($val, 1, -2);
}elseif($pos = strpos($val,'^')){
$array = explode('-',substr(strstr($val,'^'),1));
if(in_array($m1[$key],$array)) {
return false;
}
$name = substr($val, 1, $pos - 1);
}else{
$name = substr($val, 1);
}
$var[$name] = isset($m1[$key])?$m1[$key]:'';
}elseif(0 !== strcasecmp($val,$m1[$key])){
return false;
}
}
// 成功匹配后返回URL中的动态变量数组
return $var;
}

// 解析规范的路由地址
// 地址格式 [控制器/操作?]参数1=值1&参数2=值2...
private static function parseUrl($url) {
echo "-------------------------------";
var_dump($url);
$var = array();
if(false !== strpos($url,'?')) { // [控制器/操作?]参数1=值1&参数2=值2...
$info = parse_url($url);
$path = explode('/',$info['path']);
parse_str($info['query'],$var);
}elseif(strpos($url,'/')){ // [控制器/操作]
$path = explode('/',$url);
}else{ // 参数1=值1&参数2=值2...
parse_str($url,$var);
}
if(isset($path)) {
$var[C('VAR_ACTION')] = array_pop($path);
if(!empty($path)) {
$var[C('VAR_CONTROLLER')] = array_pop($path);
}
if(!empty($path)) {
$var[C('VAR_MODULE')] = array_pop($path);
}
}
return $var;
}

// 解析规则路由
// '路由规则'=>'[控制器/操作]?额外参数1=值1&额外参数2=值2...'
// '路由规则'=>array('[控制器/操作]','额外参数1=值1&额外参数2=值2...')
// '路由规则'=>'外部地址'
// '路由规则'=>array('外部地址','重定向代码')
// 路由规则中 :开头 表示动态变量
// 外部地址中可以用动态变量 采用 :1 :2 的方式
// 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'),
// 'new/:id'=>array('/new.php?id=:1',301), 重定向
private static function parseRule($rule,$route,$regx) {
// 获取路由地址规则
$url = is_array($route)?$route[0]:$route;
// 获取URL地址中的参数
$paths = explode('/',$regx);
// 解析路由规则
$matches = array();
$rule = explode('/',$rule);
foreach ($rule as $item){
$fun = '';
if(0 === strpos($item,'[:')){
$item = substr($item,1,-1);
}
if(0===strpos($item,':')) { // 动态变量获取
if($pos = strpos($item,'|')){
// 支持函数过滤
$fun = substr($item,$pos+1);
$item = substr($item,0,$pos);
}
if($pos = strpos($item,'^') ) {
$var = substr($item,1,$pos-1);
}elseif(strpos($item,'\\')){
$var = substr($item,1,-2);
}else{
$var = substr($item,1);
}
$matches[$var] = !empty($fun)? $fun(array_shift($paths)) : array_shift($paths);
}else{ // 过滤URL中的静态变量
array_shift($paths);
}
}

if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转
if(strpos($url,':')) { // 传递动态参数
$values = array_values($matches);
$url = preg_replace_callback('/:(\d+)/', function($match) use($values){ return $values[$match[1] - 1]; }, $url);
}
header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301);
exit;
}else{
// 解析路由地址
$var = self::parseUrl($url);
// 解析路由地址里面的动态参数
$values = array_values($matches);
foreach ($var as $key=>$val){
if(0===strpos($val,':')) {
$var[$key] = $values[substr($val,1)-1];
}
}
$var = array_merge($matches,$var);
// 解析剩余的URL参数
if(!empty($paths)) {
preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){ $var[strtolower($match[1])]=strip_tags($match[2]);}, implode('/',$paths));
}
// 解析路由自动传入参数
if(is_array($route) && isset($route[1])) {
if(is_array($route[1])){
$params = $route[1];
}else{
parse_str($route[1],$params);
}
$var = array_merge($var,$params);
}
$_GET = array_merge($var,$_GET);
}
return true;
}

// 解析正则路由
// '路由正则'=>'[控制器/操作]?参数1=值1&参数2=值2...'
// '路由正则'=>array('[控制器/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...')
// '路由正则'=>'外部地址'
// '路由正则'=>array('外部地址','重定向代码')
// 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式
// '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'),
// '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向
private static function parseRegex($matches,$route,$regx) {
// 获取路由地址规则
$url = is_array($route)?$route[0]:$route;
$url = preg_replace_callback('/:(\d+)/', function($match) use($matches){return $matches[$match[1]];}, $url);
if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转
header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301);
exit;
}else{
// 解析路由地址
$var = self::parseUrl($url);
// 处理函数
foreach($var as $key=>$val){
if(strpos($val,'|')){
list($val,$fun) = explode('|',$val);
$var[$key] = $fun($val);
}
}
// 解析剩余的URL参数
$regx = substr_replace($regx,'',0,strlen($matches[0]));
if($regx) {
preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){
$var[strtolower($match[1])] = strip_tags($match[2]);
}, $regx);
}
// 解析路由自动传入参数
if(is_array($route) && isset($route[1])) {
if(is_array($route[1])){
$params = $route[1];
}else{
parse_str($route[1],$params);
}
$var = array_merge($var,$params);
}
$_GET = array_merge($var,$_GET);
}
return true;
}

// 执行正则匹配下的闭包方法 支持参数调用
static private function invokeRegx($closure, $var = array()) {
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = array();
array_shift($var);
foreach ($params as $param){
if(!empty($var)) {
$args[] = array_shift($var);
}elseif($param->isDefaultValueAvailable()){
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}

// 执行规则匹配下的闭包方法 支持参数调用
static private function invokeRule($closure, $var = array()) {
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = array();
foreach ($params as $param){
$name = $param->getName();
if(isset($var[$name])) {
$args[] = $var[$name];
}elseif($param->isDefaultValueAvailable()){
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}

}

一些函数

直接看看这个吧ThinkPHP中的常用方法汇总总结:M方法,D方法,U方法,I方法

A快速实例化Action类库

B执行行为类

C配置参数存取方法

D快速实例化Model类库

F快速简单文本数据存取方法

L 语言参数存取方法

M快速高性能实例化模型

R快速远程调用Action类方法

S快速缓存存取方法

U URL动态生成和重定向方法

W 快速Widget输出方法

D函数实例化的是你当前项目的Lib/Model下面的模块。如果该模块不存在的话,直接返回实例化Model的对象(意义就与M()函数相同)。而M只返回,实例化Model的对象。它的$name参数作为数据库的表名来处理对数据库的操作。

路由规则

普通模式

http://localhost/?m=home&c=user&a=login&var=value

m参数表示模块,c参数表示控制器,a参数表示操作(当然这些参数都是可以配置的),后面的表示其他GET参数。

PATHINFO 模式

http://localhost/index.php/home/user/login/var/value/

PATHINFO地址的前三个参数分别表示模块/控制器/操作.

REWRITE模式

http://localhost/home/user/login/var/value

REWRITE模式是在PATHINFO模式的基础上添加了重写规则的支持,可以去掉URL地址里面的入口文件 index.php,但是需要额外配置WEB服务器的重写规则。

兼容模式

http://localhost/?s=/home/user/login/var/value

其中参数s来自于ThinkPHP->Conf->convention.php中的VAR_PATH_INFO设置,可以更改兼容模式变量的名称定义

CTFSHOW

web569

http://localhost/index.php/Home/Index/index/name/123/
http://localhost/index.php?m=Home&c=Index&f=index&name=123
http://localhost/index.php?s=Home/Index/index/name/123
http://localhost/Home/Index/index/name/123/

=> index.php/Admin/Login/ctfshowLogin

web 570

闭包路由,在Common/Conf/config.php

1
2
3
4
5
'URL_ROUTE_RULES' => array(
'ctfshow/:f/:a' =>function($f,$a){
call_user_func($f, $a);
}
)

web 571

Home\Conf\IndexController.class.php下找到代码

1
2
3
4
5
6
7
8
9
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index($n=''){
$this->show('balabalabala'.$n.'balabala','utf-8');
}

}

跟进show

1
2
3
protected function show($content,$charset='',$contentType='',$prefix='') {
$this->view->display('',$charset,$contentType,$content,$prefix);
}

继续跟进display

1
2
3
4
5
6
7
8
9
10
11
public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
G('viewStartTime');
// 视图开始标签
Hook::listen('view_begin',$templateFile);
// 解析并获取模板内容
$content = $this->fetch($templateFile,$content,$prefix);
// 输出模板内容
$this->render($content,$charset,$contentType);
// 视图结束标签
Hook::listen('view_end');
}

这里有两个函数,一个fetch和一个render

跟进fetch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public function fetch($templateFile='',$content='',$prefix='') {
if(empty($content)) {
$templateFile = $this->parseTemplate($templateFile);
// 模板文件不存在直接返回
if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile);
}else{
defined('THEME_PATH') or define('THEME_PATH', $this->getThemePath());
}
// 页面缓存
ob_start();
ob_implicit_flush(0);
if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板
$_content = $content;
// 模板阵列变量分解成为独立变量
extract($this->tVar, EXTR_OVERWRITE);
// 直接载入PHP模板
empty($_content)?include $templateFile:eval('?>'.$_content);
}else{
// 视图解析标签
$params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix);
Hook::listen('view_parse',$params);
}
// 获取并清空缓存
$content = ob_get_clean();
// 内容过滤标签
Hook::listen('view_filter',$content);
// 输出模板文件
return $content;
}

发现不对劲了,这里:

1
empty($_content)?include $templateFile:eval('?>'.$_content);

非常好eval

web 572

上来提示没有源码,如何获取黑客的蛛丝马迹?

所以是到日志里面读文件,thinkphp的日志路径在/Application/Runtime/Logs/Home/目录下面,所以….

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[ 2021-04-15T14:49:32+08:00 ] 127.0.0.1 /index.php?showctf=%3C?php%20phpinfo();?%3E
INFO: [ app_init ] --START--
INFO: Run Behavior\BuildLiteBehavior [ RunTime:0.000039s ]
INFO: [ app_init ] --END-- [ RunTime:0.000738s ]
INFO: [ app_begin ] --START--
INFO: Run Behavior\ReadHtmlCacheBehavior [ RunTime:0.000712s ]
INFO: [ app_begin ] --END-- [ RunTime:0.000868s ]
INFO: [ view_parse ] --START--
INFO: [ template_filter ] --START--
INFO: Run Behavior\ContentReplaceBehavior [ RunTime:0.000071s ]
INFO: [ template_filter ] --END-- [ RunTime:0.000204s ]
INFO: Run Behavior\ParseTemplateBehavior [ RunTime:0.008833s ]
INFO: [ view_parse ] --END-- [ RunTime:0.009135s ]
INFO: [ view_filter ] --START--
INFO: Run Behavior\WriteHtmlCacheBehavior [ RunTime:0.000468s ]
INFO: [ view_filter ] --END-- [ RunTime:0.000591s ]
INFO: [ app_end ] --START--
INFO: Run Behavior\ShowPageTraceBehavior [ RunTime:0.000964s ]
INFO: [ app_end ] --END-- [ RunTime:0.001181s ]

后门都贴到脸上了(

web 573

GitHub Issues 最新版本3.2.3存在order by注入漏洞
修正一处可能的安全隐患

?id[where]=id=-1 union select 1,group_concat(flag4s),3,4 from flags

web 574

加了点小米辣,然后…
?id=-1) union select 1,group_concat(flag4s),3,4 from flags%23

web 575

1
2
3
4
5
6
7
$user= unserialize(base64_decode(cookie('user')));
if(!$user || $user->id!==$id){
$user = M('Users');
$user->find(intval($id));
cookie('user',base64_encode(serialize($user->data())));
}
$this->show($user->username);

看到这个show我就蠢蠢欲动(

其他地方的一些ThinkPHP题目

[RoarCTF 2019]Simple Upload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 <?php
namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller
{
public function index()
{
show_source(__FILE__);
}
public function upload()
{
$uploadFile = $_FILES['file'] ;

if (strstr(strtolower($uploadFile['name']), ".php") ) {
return false;
}

$upload = new \Think\Upload();// 实例化上传类
$upload->maxSize = 4096 ;// 设置附件上传大小
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
$upload->rootPath = './Public/Uploads/';// 设置附件上传目录
$upload->savePath = '';// 设置附件上传子目录
$info = $upload->upload() ;
if(!$info) {// 上传错误提示错误信息
$this->error($upload->getError());
return;
}else{// 上传成功 获取上传文件信息
$url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
echo json_encode(array("url"=>$url,"success"=>1));
}
}
}

乍一看确实无懈可击,啥都拦截了,白名单也用上了

遇事不决,RTFM
直接进行一个手册的读
然后审审框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 默认上传配置
* @var array
*/
private $config = array(
'mimes' => array(), //允许上传的文件MiMe类型
'maxSize' => 0, //上传的文件大小限制 (0-不做限制)
'exts' => array(), //允许上传的文件后缀
'autoSub' => true, //自动子目录保存文件
'subName' => array('date', 'Y-m-d'), //子目录创建方式,[0]-函数名,[1]-参数,多个参数使用数组
'rootPath' => './Uploads/', //保存根路径
'savePath' => '', //保存路径
'saveName' => array('uniqid', ''), //上传文件命名规则,[0]-函数名,[1]-参数,多个参数使用数组
'saveExt' => '', //文件保存后缀,空则使用原后缀
'replace' => false, //存在同名是否覆盖
'hash' => true, //是否生成hash编码
'callback' => false, //检测文件是否存在回调,如果存在返回文件信息数组
'driver' => '', // 文件上传驱动
'driverConfig' => array(), // 上传驱动配置
);

emmm,找半天,没找到allowExts,感觉emmmm???

尼玛,看了半天. 不过现在一个问题就是文件传上去了该怎么访问?
文件名并不给我

Refence

ThinkPHP中的常用方法汇总总结:M方法,D方法,U方法,I方法
ctfshow ThinkPHP篇—3.2.3

作者

UPON2021

发布于

2023-04-05

更新于

2023-05-10

许可协议

# 相关文章
  1.CRLF + SSRF
评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...