ThinkPHP框架学习之基础篇

admin 2023年8月3日19:05:15评论24 views字数 8375阅读27分55秒阅读模式

最近梳理几个PHP框架,ThinkPHP在渗透测试项目中还是有可能遇得到(最近在梳理公司内外部资产就看到其身影),先学习其基础使用,本篇算是水文吧,有错误之处欢迎指出。

0x1、ThinkPHP概述

ThinkPHP是一款开源的PHP框架,被广泛应用于Web应用程序的开发。以下是对ThinkPHP框架的介绍:
  1. 高效性能:ThinkPHP框架采用了严格的代码优化和缓存技术,具有出色的性能表现。它支持多种缓存机制(如文件缓存、Memcached、Redis等),可以提升网站的响应速度和并发处理能力。
  2. MVC架构:ThinkPHP框架采用经典的MVC(Model-View-Controller)软件架构,将业务逻辑、数据处理和页面展示分离,提供了良好的代码组织结构和高度的可扩展性。这使得团队合作开发更加便捷,并且方便进行代码重用和维护。
  3. 强大的数据库支持:ThinkPHP框架内置了全面的数据库操作方法,支持主流的数据库系统(如MySQL、SQLite、SQL Server等),提供了便捷的数据库连接、查询、更新等功能。
  4. 丰富的功能扩展:ThinkPHP框架提供了丰富的功能扩展,包括认证与授权、缓存管理、表单验证、文件上传、邮件发送、数据分页等,使开发人员能够快速实现常见的功能需求,节约开发时间。
  5. 完善的文档与社区支持:ThinkPHP框架具有详细的官方文档,提供了全面的框架说明和开发指南,可以帮助开发人员快速上手。此外,框架还有活跃的社区支持,开发者可以在社区中获取问题解答、分享经验和交流思想。
  6. 跨平台兼容性:ThinkPHP框架支持跨平台开发,并且兼容多种操作系统(如Windows、Linux、Unix等)和Web服务器(如Apache、Nginx等),使得开发人员能够在不同的环境中灵活运行和部署项目。
总体来说,ThinkPHP框架是一款功能强大、易于上手的PHP开发框架,适用于各种规模的Web应用程序开发。它以高效性能、良好的扩展性和丰富的功能特性受到广大开发者的青睐,并且拥有庞大的用户社区支持。

0x2、代码获取和目录结构

获取ThinkPHP代码的方式有很多,比如Docker、Github、Google等等,这里通过composer的方式获取代码环境。
composer create-project topthink/think=5.0.24
ThinkPHP框架学习之基础篇
切换到public目录,在当前目录下启用终端,输入php -S 0.0.0.0:80。注意这里需要配置PHP的环境变量。
ThinkPHP框架学习之基础篇
目录截图如下(windows下的截图):
ThinkPHP框架学习之基础篇
目录结构的详细介绍如下:
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 命令行入口文件
注意:ThinkPHP的入口文件为public/index.php,实际部署网站的时候对外的访问目录为public,它负责处理所有进入应用程序的Web请求。每个请求都必须经过该文件进行路由和分发。以下是该文件的基本结构:
<?php// [ 应用入口文件 ]// 定义应用目录define('APP_PATH', __DIR__ . '/../application/');// 加载框架引导文件require __DIR__ . '/../thinkphp/start.php';
  • 第一行定义了应用程序根目录的路径。默认情况下,该路径设置为public目录的父目录,即应用程序的根目录。
  • 第二行加载框架的入口文件。该文件包含了所有必要的类和函数,以及自动加载器和错误处理程序等功能。
  • 在入口文件加载完成后,它会调用框架核心的启动程序thinkApp::run()方法。该方法负责初始化应用程序,并将请求传递给路由处理程序进行路由匹配和分发。路由和分发过程完成后,应用程序执行对应的控制器和动作方法,并输出结果。
ThinkPHP框架学习之基础篇
ThinkPHP的执行流程如下:
ThinkPHP框架学习之基础篇

0x3、调试模式和访问方式

(1)启用调试模式

为了直接看到代码的测试效果,可以考虑启用ThinkPHP的调试模式,在应用程序的配置文件config/app.php中,修改debug选项为true,修改app_trace选项为true:
ThinkPHP框架学习之基础篇
重新访问该网站,就会在页面的右下角看到thinkphp的logo以及页面响应时间。
ThinkPHP框架学习之基础篇
点击该logo就会看到调试小窗口。
ThinkPHP框架学习之基础篇
当访问的URL存在不合理的参数就会报如下的提示。
ThinkPHP框架学习之基础篇
注意:在实际项目中,如果出现这中页面会泄露当前服务器的相关信息,上线的项目必须关闭。

(2)访问方式

ThinkPHP在没有启用强制路由的情况下的典型访问URL为:
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
上面的URL请求中,其中:
  • index.php 为应用的入口文件,注意入口文件可以被隐藏,
  • Index为模块名称,模块在ThinkPHP中的概念其实就是应用目录下面的子目录,而官方的规范是目录名小写,因此模块全部采用小写命名,无论URL是否开启大小写转换,模块名都会强制小写。
ThinkPHP框架学习之基础篇
  • think为控制器,在thinkphp中就是一个类的名称;
ThinkPHP框架学习之基础篇
  • app代表某种操作,可以理解为控制器(后面讲解什么是控制器)下定义的函数。
  • nvokefunction&function=call_user_func_arra y&vars[0]=phpinfo&vars[1][]=-1%20and%20it%27ll%20execute%20the%20phpinfo 为参数名和参数值
如果直接访问入口文件的话,由于URL中没有模块、控制器和操作,因此系统会访问默认模块(index)下面的默认控制器(Index)的默认操作(index),因此下面的访问是等效的:
http://127.0.0.1/index.phphttp://127.0.0.1/index.php/index/index/index
ThinkPHP框架学习之基础篇

0x4、控制器和路由

(1)控制器

ThinkPHP中的控制器是用于处理用户请求并返回响应的重要组成部分。它们是MVC架构的一部分,用于将应用程序的业务逻辑与其表示层分离。
  • ThinkPHP的控制器负责处理请求并将响应数据返回给客户端。控制器是一个类,它继承了框架的基础控制器类每个控制器都映射到一个URL路由,并包含一组动作方法来处理不同的请求。当请求发送到特定路由时,相应的控制器和动作方法将被调用。
  • 在控制器中,开发者可以定义其控制器逻辑并与模型或应用程序的其他组件交互。控制器可以访问请求参数、会话数据和其他应用程序资源。
  • ThinkPHP还提供了一种名为“约定优于配置”的特性,这意味着如果您遵循一定的控制器和动作方法的命名约定,框架将自动路由请求到正确的控制器和动作方法。
ThinkPHP默认的控制器为application/index/controller/index.php,在该文件中新建一个printDate方法和sayHello方法:
<?phpnamespace 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 . '!'; }}
访问该方法需要定位到该函数的路由:http://127.0.0.1/index.php/index/index/printDate
ThinkPHP框架学习之基础篇
注意:这里再啰嗦一遍,访问的URL中:http://127.0.0.1/index.php/index/index/printDate,index.php为入口文件,第一个index为模块名称,第二个index为控制器,printDate为操作。截图如下:
ThinkPHP框架学习之基础篇
那么如何传递参数呢?比如执行sayHello操作。需要传递参数,其中参数名为name,参数值这里输入cream。最后的URL即为:
http://127.0.0.1/index.php/index/index/sayHello/name/cream
ThinkPHP框架学习之基础篇
如果不输入参数cream,那么就会使用默认的参数“World”。
ThinkPHP框架学习之基础篇
如果有多组参数呢?比如如下的操作:
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

ThinkPHP框架学习之基础篇

注意:
  • 参数的形式是:参数名1/参数值1/参数名2/参数值2……

  • 请求方式1和请求方式2的效果是一样的,且变量s的名称的可以配置的.


(2)路由

大家有没有发现请求方式2比较长,模块+控制器+参数对构成的URL显示冗长,且不方便使用,这个时候就需要用到路由。ThinkPHP路由是指在应用程序中定义URL和请求处理程序之间的映射关系。在ThinkPHP中,路由是由应用程序的路由表配置文件定义的。路由表指定了不同的URL模式以及在处理不同URL时应该调用哪个控制器和方法。ThinkPHP支持多种路由风格,例如传统的PathInfo模式、兼容模式(支持PathInfo和查询字符串)、路由模式(支持正则表达式)等。这些路由风格可以通过应用程序配置文件进行设置。通过路由,您可以将URL重定向到特定的控制器和动作方法。此外,您还可以使用路由变量来匹配特定的URL模式,并将URL参数传递到控制器中。
总之,路由在ThinkPHP中是非常重要的,因为它指定了应用程序的URL结构和请求处理方式。通过设置路由,您可以实现可读性更好的URL,并促进应用程序的可维护性和可扩展性。 打开应用程序的路由配置文件route.php,添加以下内容:
return[    'hello/:name'=>'index/index/sayHello',];
该路由规则表示所有hello开头的并且带参数的访问都会路由到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
在浏览器中访问发现原来的URL开始报错(非法请求),只访问hello会提示模块不存在,后面添加参数后才正常访问。

ThinkPHP框架学习之基础篇

http://127.0.0.1/index.php/hello报错的原因是路由没有正确匹配到,可以修改路由规则:
return [    // 添加路由规则,路由到index控制器的sayHello操作方法,路由参数name为可选    'hello/[:name]' => 'index/index/sayHello',];
使用[]把路由规则中的变量包起来,就表示该变量为可选,接下来就可以正常访问了

ThinkPHP框架学习之基础篇

除了上面定义路由的方式外,还可以采用动态定义路由(Route类)规则。在配置文件(application/route.php)的开头直接添加下面的方法:

<?phpuse thinkRoute;Route::rule('hello/[:name]','index/index/sayHello');
访问效果和上面一样。
最后一个问题,如果想让下面三个URL的访问都是正常的,该怎么办呢?
http://127.0.0.1/index.php/index/index/sayHello/name/creamhttp://127.0.0.1/index.php/hello/cream)http://127.0.0.1/index.php/hello
要解决这个问题需要考虑完整匹配!前面定义的路由是只要以hello开头就能进行匹配,如果需要完整匹配,可以使用下面的定义:
<?phpuse thinkRoute;Route::rule('hello/[:name]$','index/sayHello');
或者
return     // 添加路由规则,路由到index控制器的sayHello操作方法,路由参数name为可选    'hello/[:name]$' => 'index/index/sayHello',    //使用[]把路由规则中的变量包起来,就表示该变量为可选,接下来就可以正常访问了];
路由规则以$结尾的时候就表示当前路由规则需要完整匹配。
这里针对控制器和路由功能重新练习一遍吧。
<?phpnamespace appindexcontroller;class User{    public function index($id){        echo 'user id:'.$id;    }}

ThinkPHP框架学习之基础篇

直接在浏览器中访问:
http://127.0.0.1/index.php/index/User/index/id/123

ThinkPHP框架学习之基础篇

设置路由,内容如下:
<?phpuse thinkRoute;Route::rule("/user/[:id]","index/User/index");

我看到有些文章里使用Route::get('/hello', 'HelloController')和Route::post('/hello', 'HelloController'),其实也就是发送数据的方式不一样。上面的代码可以换成如下的形式:

<?phpuse thinkRoute;Route::post("/user/","index/User/index");
或者
<?phpuse thinkRoute;Route::rule("/user/","index/User/index","post");

ThinkPHP框架学习之基础篇

除了可以在路由规则中定义请求方式,还可以定义URL后缀之类的条件,例如
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”的参数,并使用正则表达式指定该参数必须是数字。
添加了如下的控制器代码:
<?phpnamespace 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/>'; }}
访问的URL为:
http://127.0.0.1/index.php/index/Blog/read/id/2

ThinkPHP框架学习之基础篇

以路由的方式访问:

http://127.0.0.1/index.php/blog/2.html

ThinkPHP框架学习之基础篇

0x5、参考

https://www.kancloud.cn/thinkphp/thinkphp5_quickstart/478279https://www.cnblogs.com/SecurityHacker/p/17418063.html


原文始发于微信公众号(99Sec):ThinkPHP框架学习之基础篇

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年8月3日19:05:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ThinkPHP框架学习之基础篇https://cn-sec.com/archives/1931825.html

发表评论

匿名网友 填写信息