最近梳理几个PHP框架,ThinkPHP在渗透测试项目中还是有可能遇得到(最近在梳理公司内外部资产就看到其身影),先学习其基础使用,本篇算是水文吧,有错误之处欢迎指出。
0x1、ThinkPHP概述
-
高效性能:ThinkPHP框架采用了严格的代码优化和缓存技术,具有出色的性能表现。它支持多种缓存机制(如文件缓存、Memcached、Redis等),可以提升网站的响应速度和并发处理能力。 -
MVC架构:ThinkPHP框架采用经典的MVC(Model-View-Controller)软件架构,将业务逻辑、数据处理和页面展示分离,提供了良好的代码组织结构和高度的可扩展性。这使得团队合作开发更加便捷,并且方便进行代码重用和维护。 -
强大的数据库支持:ThinkPHP框架内置了全面的数据库操作方法,支持主流的数据库系统(如MySQL、SQLite、SQL Server等),提供了便捷的数据库连接、查询、更新等功能。 -
丰富的功能扩展:ThinkPHP框架提供了丰富的功能扩展,包括认证与授权、缓存管理、表单验证、文件上传、邮件发送、数据分页等,使开发人员能够快速实现常见的功能需求,节约开发时间。 -
完善的文档与社区支持:ThinkPHP框架具有详细的官方文档,提供了全面的框架说明和开发指南,可以帮助开发人员快速上手。此外,框架还有活跃的社区支持,开发者可以在社区中获取问题解答、分享经验和交流思想。 -
跨平台兼容性:ThinkPHP框架支持跨平台开发,并且兼容多种操作系统(如Windows、Linux、Unix等)和Web服务器(如Apache、Nginx等),使得开发人员能够在不同的环境中灵活运行和部署项目。
0x2、代码获取和目录结构
composer create-project topthink/think=5.0.24
think WEB部署目录(或者是www,网站的跟目录)
├─application 应用目录
│ ├─common 公共模块目录(可以更改)
│ ├─module_name 模块目录
│ │ ├─config.php 模块配置文件
│ │ ├─common.php 模块函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ └─ ... 更多类库目录
│ │
│ ├─command.php 命令行工具配置文件
│ ├─common.php 公共函数文件
│ ├─config.php 公共配置文件
│ ├─route.php 路由配置文件
│ ├─tags.php 应用行为扩展定义文件
│ └─database.php 数据库配置文件
│
├─public WEB目录(对外访问目录)
│ ├─index.php 入口文件
│ ├─router.php 快速测试文件
│ └─.htaccess 用于apache的重写
│
├─thinkphp 框架系统目录
│ ├─lang 语言文件目录
│ ├─library 框架类库目录
│ │ ├─think Think类库包目录
│ │ └─traits 系统Trait目录
│ │
│ ├─tpl 系统模板目录
│ ├─base.php 基础定义文件
│ ├─console.php 控制台入口文件
│ ├─convention.php 框架惯例配置文件
│ ├─helper.php 助手函数文件
│ ├─phpunit.xml phpunit配置文件
│ └─start.php 框架入口文件
│
├─extend 扩展类库目录
├─runtime 应用的运行时目录(可写,可定制)
├─vendor 第三方类库目录(Composer依赖库)
├─build.php 自动生成定义文件(参考)
├─composer.json composer 定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行入口文件
// [ 应用入口文件 ]
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
-
第一行定义了应用程序根目录的路径。默认情况下,该路径设置为public目录的父目录,即应用程序的根目录。 -
第二行加载框架的入口文件。该文件包含了所有必要的类和函数,以及自动加载器和错误处理程序等功能。 -
在入口文件加载完成后,它会调用框架核心的启动程序thinkApp::run()方法。该方法负责初始化应用程序,并将请求传递给路由处理程序进行路由匹配和分发。路由和分发过程完成后,应用程序执行对应的控制器和动作方法,并输出结果。
0x3、调试模式和访问方式
(1)启用调试模式
(2)访问方式
http://target/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值...]
另外,ThinkPHP5取消了URL模式的概念,普通的URL模式访问不再被支持,但参数可以通过普通URL模式传递:
http://target/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值...]
http://192.168.8.89/index.php?s=/Index/think/app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1%20and%20it%27ll%20execute%20the%20phpinfo
-
index.php 为应用的入口文件,注意入口文件可以被隐藏, -
Index为模块名称,模块在ThinkPHP中的概念其实就是应用目录下面的子目录,而官方的规范是目录名小写,因此模块全部采用小写命名,无论URL是否开启大小写转换,模块名都会强制小写。
-
think为控制器,在thinkphp中就是一个类的名称;
-
app代表某种操作,可以理解为控制器(后面讲解什么是控制器)下定义的函数。 -
nvokefunction&function=call_user_func_arra y&vars[0]=phpinfo&vars[1][]=-1%20and%20it%27ll%20execute%20the%20phpinfo 为参数名和参数值
http://127.0.0.1/index.phphttp://127.0.0.1/index.php/index/index/index
0x4、控制器和路由
(1)控制器
-
ThinkPHP的控制器负责处理请求并将响应数据返回给客户端。控制器是一个类,它继承了框架的基础控制器类。每个控制器都映射到一个URL路由,并包含一组动作方法来处理不同的请求。当请求发送到特定路由时,相应的控制器和动作方法将被调用。 -
在控制器中,开发者可以定义其控制器逻辑并与模型或应用程序的其他组件交互。控制器可以访问请求参数、会话数据和其他应用程序资源。 -
ThinkPHP还提供了一种名为“约定优于配置”的特性,这意味着如果您遵循一定的控制器和动作方法的命名约定,框架将自动路由请求到正确的控制器和动作方法。
namespace appindexcontroller;
class Index
{
public function index()
{
return '<style type="text/css">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5<br/><span style="font-size:30px">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style="font-size:22px;">[ V5.0 版本由 <a href="http://www.qiniu.com" target="qiniu">七牛云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="ad_bd568ce7058a1091"></think>';
}
public function printDate()
{
echo date("F j, Y, g:i a"),"<br>";
echo "hello cream!!";
}
public function sayHello($name = 'World')
{
return 'Hello,' . $name . '!';
}
}
public function printNameAge($name = 'cream',$age = '18')
{
return $name." is ".$age."!";
}
请求方法1:http://127.0.0.1/index.php/index/index/printNameAge/name/daxiao/age/200
请求方式2:http://127.0.0.1/index.php/?s=index/index/printNameAge/name/daxiao/age/200
-
参数的形式是:参数名1/参数值1/参数名2/参数值2……
-
请求方式1和请求方式2的效果是一样的,且变量s的名称的可以配置的.
(2)路由
return[
'hello/:name'=>'index/index/sayHello',
];
原来的URL访问地址:http://127.0.0.1/index.php/index/index/sayHello/name/cream
添加路由后的URL地址:http://127.0.0.1/index.php/hello/cream或者http://127.0.0.1/hello/cream
return [
// 添加路由规则,路由到index控制器的sayHello操作方法,路由参数name为可选
'hello/[:name]' => 'index/index/sayHello',
];
使用[]把路由规则中的变量包起来,就表示该变量为可选,接下来就可以正常访问了
除了上面定义路由的方式外,还可以采用动态定义路由(Route类)规则。在配置文件(application/route.php)的开头直接添加下面的方法:
use thinkRoute;
Route::rule('hello/[:name]','index/index/sayHello');
http://127.0.0.1/index.php/index/index/sayHello/name/cream
http://127.0.0.1/index.php/hello/cream)
http://127.0.0.1/index.php/hello
要解决这个问题需要考虑完整匹配!前面定义的路由是只要以hello开头就能进行匹配,如果需要完整匹配,可以使用下面的定义:
use thinkRoute;
Route::rule('hello/[:name]$','index/sayHello');
return
// 添加路由规则,路由到index控制器的sayHello操作方法,路由参数name为可选
'hello/[:name]$' => 'index/index/sayHello',
//使用[]把路由规则中的变量包起来,就表示该变量为可选,接下来就可以正常访问了
];
路由规则以$结尾的时候就表示当前路由规则需要完整匹配。
namespace appindexcontroller;
class User
{
public function index($id)
{
echo 'user id:'.$id;
}
}
http://127.0.0.1/index.php/index/User/index/id/123
use thinkRoute;
Route::rule("/user/[:id]","index/User/index");
我看到有些文章里使用Route::get('/hello', 'HelloController')和Route::post('/hello', 'HelloController'),其实也就是发送数据的方式不一样。上面的代码可以换成如下的形式:
use thinkRoute;
Route::post("/user/","index/User/index");
use thinkRoute;
Route::rule("/user/","index/User/index","post");
return [
// 定义路由的请求类型和后缀
'blog/[:id]' => ['blog/read', ['method' => 'get', 'ext' => 'html','id'=>'d+']],
];
或者
use thinkRoute;
Route::get('blog/:id', 'blog/read', ['ext' => 'html'], ['id' => 'd+']);
上面的规则含义是:允许HTTP GET请求匹配以“/blog/”开头,后跟数字参数的URL。规则将该请求传递到名为blog的控制器的名为read的动作方法。我们还指定了一个扩展名为“html”的参数,并使用正则表达式指定该参数必须是数字。
namespace appindexcontroller;
use thinkRequest;
class Blog
{
public function read($id)
{
$request=Request::instance();
echo 'Blog ID: ' . $id . '<br/>';
echo 'Extension: ' . $request->ext() . '<br/>';
echo 'URL: ' . $request->url() . '<br/>';
}
}
http://127.0.0.1/index.php/index/Blog/read/id/2
以路由的方式访问:
http://127.0.0.1/index.php/blog/2.html
0x5、参考
https://www.kancloud.cn/thinkphp/thinkphp5_quickstart/478279https://www.cnblogs.com/SecurityHacker/p/17418063.html
原文始发于微信公众号(99Sec):ThinkPHP框架学习之基础篇
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论