由于笔者是刚入门thinkphp,所以学习时对照thinkphp的官网,各位读者也可以对照官网学习。还麻烦各位笔者一键三连,谢谢。
1.请求对象
当前的请求对象由think\Request
类负责,该类不需要单独实例化调用,通常使用依赖注入即可。在其它场合则可以使用think\facade\Request
静态类操作。
项目里面应该使用app\Request
对象,该对象继承了系统的think\Request
对象,但可以增加自定义方法或者覆盖已有方法。项目里面已经在provider.php
中进行了定义,所以你仍然可以和之前一样直接使用容器和静态代理操作请求对象。
构造方法注入
一般适用于没有继承系统的控制器类的情况。
php
<?php
namespace app\index\controller;
use think\Request;
class Index
{
/**
* @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');
}
}
操作方法注入
另外一种选择是在每个方法中使用依赖注入。
php
<?php
namespace app\index\controller;
use think\Request;
class Index
{
public function index(Request $request)
{
return $request->param('name');
}
}
无论是否继承系统的控制器基类,都可以使用操作方法注入。
静态调用
在没有使用依赖注入的场合,可以通过Facade
机制来静态调用请求对象的方法(注意use
引入的类库区别)。
php
<?php
namespace app\index\controller;
use think\facade\Request;
class Index
{
public function index()
{
return Request::param('name');
}
}
该方法也同样适用于依赖注入无法使用的场合。
助手函数
为了简化调用,系统还提供了request
助手函数,可以在任何需要的时候直接调用当前请求对象。
php
<?php
namespace app\index\controller;
class Index
{
public function index()
{
return request()->param('name');
}
}
自定义请求对象
你可以在项目里面自定义Request对象,修改已有的方法或者增加新的方法,默认已经在项目里面为你准备了app\Request
类,你只需要直接修改该类就可以为你的项目单独自定义请求对象。
自定义请求对象不支持为多应用的某个应用自定义,只能是全局自定义,如果你需要为某个应用定义不同的请求对象,可以在入口文件里面修改。例如:
php
// 执行HTTP应用并响应
$request = new app\common\Request();
$http = (new App())->http;
$response = $http->run($request);
$response->send();
$http->end($response);
php
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Request;
use think\facade\View;
use think\facade\Route;
class RequestTest extends BaseController{
//使用类有两种方式
//1.先use再直接拿类名使用
//2.直接使用:空间名\类名
public function test (){
echo "1-----测试成功~~~~";
//通过请求对象来获取请求信息
//使用请求类得到请求对象 think\Request
//1.获取请求对象-静态获取
dump(Request::method());
}
public function test1(\think\Request $request){
//2.动态获取请求对象,参数绑定
dump($request->method());
}
//3.继承父类的request属性(就是请求对象)
public function test2(){
dump($this->request->method());
}
//请求方法
public function test3(){
//客户端ip地址
dump($this->request->ip());
//当前访问的域名
dump($this->request->host());
//当前请求的url地址
dump($this->request->url());
//当前请求的路由信息
dump($this->request->route());
//当前请求的请求类型
dump($this->request->isGet());
//当前请求的请求参数
dump($this->request->param());
}
public function test4(){
//get请求
//http://localhost:8000/RequestTest/test4?123
dump($this->request->get());
//pathinfo请求
//http://localhost:8000/RequestTest/test4/123=123
dump($this->request->pathinfo());
//通用请求
dump($this->request->param());
}
public function add(){
dump($this->request->method());
if($this->request->isPost()){
//获取表单提交的数据
$post=$this->request->param();//什么都不传默认获取全部数据
$postName=$this->request->param('name');
dump($post);
dump($postName);
}else{//get请求,展示表单
}
return View::fetch();
}
}
?>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/RequestTest/add" method="post">
姓名:<input type="text" name="name"><br>
性别:<input type="radio" name="sex" value="male">男
<input type="radio" name="sex" value="female">女<br>
年龄:<input type="number" name="age"><br>
邮箱:<input type="email" name="email"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobby[]" value="reading"> 阅读
<input type="checkbox" name="hobby[]" value="swimming"> 游泳
<input type="checkbox" name="hobby[]" value="running"> 跑步<br>
学历:
<select name="education">
<option value="primary">小学</option>
<option value="middle">初中</option>
<option value="high">高中</option>
<option value="college">大学</option>
</select><br>
<input type="submit" value="提交">
<a href="/RequestTest/run">跳</a>
</form>
</body>
</html>
2.请求信息
Request
对象支持获取当前的请求信息,包括:
方法 | 含义 |
---|---|
host |
当前访问域名或者IP |
scheme |
当前访问协议 |
port |
当前访问的端口 |
remotePort |
当前请求的REMOTE_PORT |
protocol |
当前请求的SERVER_PROTOCOL |
contentType |
当前请求的CONTENT_TYPE |
domain |
当前包含协议的域名 |
subDomain |
当前访问的子域名 |
panDomain |
当前访问的泛域名 |
rootDomain |
当前访问的根域名 |
url |
当前完整URL |
baseUrl |
当前URL(不含QUERY_STRING) |
query |
当前请求的QUERY_STRING参数 |
baseFile |
当前执行的文件 |
root |
URL访问根地址 |
rootUrl |
URL访问根目录 |
pathinfo |
当前请求URL的pathinfo信息(含URL后缀) |
ext |
当前URL的访问后缀 |
time |
获取当前请求的时间 |
type |
当前请求的资源类型 |
method |
当前请求类型 |
rule |
当前请求的路由对象实例 |
对于上面的这些请求方法,一般调用无需任何参数,但某些方法可以传入true
参数,表示获取带域名的完整地址,例如
php
use think\facade\Request;
// 获取完整URL地址 不带域名
Request::url();
// 获取完整URL地址 包含域名
Request::url(true);
// 获取当前URL(不含QUERY_STRING) 不带域名
Request::baseFile();
// 获取当前URL(不含QUERY_STRING) 包含域名
Request::baseFile(true);
// 获取URL访问根地址 不带域名
Request::root();
// 获取URL访问根地址 包含域名
Request::root(true);
获取当前控制器/操作
可以通过请求对象获取当前请求的控制器/操作名。
方法 | 含义 |
---|---|
controller |
当前请求的控制器名 |
action |
当前请求的操作名 |
获取当前控制器
php
Request::controller();
返回的是控制器的驼峰形式(首字母大写),和控制器类名保持一致(不含后缀)。
如果需要返回小写可以使用
Request::controller(true);
如果要返回小写+下划线的方式,可以使用
php
parse_name(Request::controller());
获取当前操作
php
Request::action();
返回的是当前操作方法的实际名称,如果需要返回小写可以使用
php
Request::action(true);
如果要返回小写+下划线的方式,可以使用
php
parse_name(Request::action());
如果使用了多应用模式,可以通过下面的方法来获取当前应用
php
app('http')->getName();
3.输入变量
可以通过Request
对象完成全局输入变量的检测、获取和安全过滤,支持包括$_GET
、$_POST
、$_REQUEST
、$_SERVER
、$_SESSION
、$_COOKIE
、$_ENV
等系统变量,以及文件上传信息。
php
use think\facade\Request;
检测变量是否设置
可以使用has
方法来检测一个变量参数是否设置,如下:
php
Request::has('id','get');
Request::has('name','post');
变量检测可以支持所有支持的系统变量,包括get/post/put/request/cookie/server/session/env/file
。
变量获取
变量获取使用\think\Request
类的如下方法及参数:
变量类型方法('变量名/变量修饰符','默认值','过滤方法')
变量类型方法包括:
方法 | 描述 |
---|---|
param | 获取当前请求的变量 |
get | 获取 $_GET 变量 |
post | 获取 $_POST 变量 |
put | 获取 PUT 变量 |
delete | 获取 DELETE 变量 |
session | 获取 SESSION 变量 |
cookie | 获取 $_COOKIE 变量 |
request | 获取 $_REQUEST 变量 |
server | 获取 $_SERVER 变量 |
env | 获取 $_ENV 变量 |
route | 获取 路由(包括PATHINFO) 变量 |
middleware | 获取 中间件赋值/传递的变量 |
file | 获取 $_FILES 变量 |
all V6.0.8+ |
获取包括 $_FILES 变量在内的请求变量,相当于param+file |
获取PARAM
变量
PARAM
类型变量是框架提供的用于自动识别当前请求的一种变量获取方式,是系统推荐的获取请求参数的方法,用法如下:
php
// 获取当前请求的name变量
Request::param('name');
// 获取当前请求的所有变量(经过过滤)
Request::param();
// 获取当前请求未经过滤的所有变量
Request::param(false);
// 获取部分变量
Request::param(['name', 'email']);
param
方法会把当前请求类型的参数和路由变量以及GET请求合并,并且路由变量是优先的。
其它的输入变量获取方法和param
方法用法基本一致。
你无法使用get方法获取路由变量,例如当访问地址是
php
http://localhost/index.php/index/index/hello/name/thinkphp
下面的用法是错误的
php
echo Request::get('name'); // 输出为空
正确的用法是
php
echo Request::param('name'); // 输出thinkphp
除了
server
和env
方法的变量名不区分大小写(会自动转为大写后获取),其它变量名区分大小写。
默认值
获取输入变量的时候,可以支持默认值,例如当URL中不包含$_GET['name']
的时候,使用下面的方式输出的结果比较。
php
Request::get('name'); // 返回值为null
Request::get('name',''); // 返回值为空字符串
Request::get('name','default'); // 返回值为default
前面提到的方法都支持在第二个参数中传入默认值的方式。
变量过滤
框架默认没有设置任何全局过滤规则,你可以在
app\Request
对象中设置filter
全局过滤属性:
php
namespace app;
class Request extends \think\Request
{
protected $filter = ['htmlspecialchars'];
}
也支持使用Request
对象进行全局变量的获取过滤,过滤方式包括函数、方法过滤,以及PHP内置的Types of filters,我们可以设置全局变量过滤方法,支持设置多个过滤方法,例如:
php
Request::filter(['strip_tags','htmlspecialchars']),
也可以在获取变量的时候添加过滤方法,例如:
php
Request::get('name','','htmlspecialchars'); // 获取get变量 并用htmlspecialchars函数过滤
Request::param('username','','strip_tags'); // 获取param变量 并用strip_tags函数过滤
Request::post('name','','org\Filter::safeHtml'); // 获取post变量 并用org\Filter类的safeHtml方法过滤
可以支持传入多个过滤规则,例如:
php
Request::param('username','','strip_tags,strtolower'); // 获取param变量 并依次调用strip_tags、strtolower函数过滤
如果当前不需要进行任何过滤的话,可以使用
php
// 获取get变量 并且不进行任何过滤 即使设置了全局过滤
Request::get('name', '', null);
对于body中提交的
json
对象,你无需使用php://input
去获取,可以直接当做表单提交的数据使用,因为系统已经自动处理过了
获取部分变量
如果你只需要获取当前请求的部分参数,可以使用:
php
// 只获取当前请求的id和name变量
Request::only(['id','name']);
采用
only
方法能够安全的获取你需要的变量,避免额外变量影响数据处理和写入。
only
方法可以支持批量设置默认值,如下:
php
// 设置默认值
Request::only(['id'=>0,'name'=>'']);
表示id
的默认值为0,name
的默认值为空字符串。
默认获取的是当前请求参数(PARAM
类型变量),如果需要获取其它类型的参数,可以在第二个参数传入,例如:
php
// 只获取GET请求的id和name变量
Request::only(['id','name'], 'get');
// 等效于
Request::get(['id', 'name']);
// 只获取POST请求的id和name变量
Request::only(['id','name'], 'post');
// 等效于
Request::post(['id', 'name']);
也支持排除某些变量后获取,例如
php
// 排除id和name变量
Request::except(['id','name']);
同样支持指定变量类型获取:
php
// 排除GET请求的id和name变量
Request::except(['id','name'], 'get');
// 排除POST请求的id和name变量
Request::except(['id','name'], 'post');
变量修饰符
支持对变量使用修饰符功能,可以一定程度上简单过滤变量,更为严格的过滤请使用前面提过的变量过滤功能。
用法如下:
Request::变量类型('变量名/修饰符');
支持的变量修饰符,包括:
修饰符 | 作用 |
---|---|
s | 强制转换为字符串类型 |
d | 强制转换为整型类型 |
b | 强制转换为布尔类型 |
a | 强制转换为数组类型 |
f | 强制转换为浮点类型 |
下面是一些例子:
php
Request::get('id/d');
Request::post('name/s');
Request::post('ids/a');
中间件变量
可以在中间件里面设置和获取请求变量的值,这个值的改变不会影响PARAM
变量的获取。
php
<?php
namespace app\http\middleware;
class Check
{
public function handle($request, \Closure $next)
{
if ('think' == $request->name) {
$request->name = 'ThinkPHP';
}
return $next($request);
}
}
助手函数
为了简化使用,还可以使用系统提供的input
助手函数完成上述大部分功能。
判断变量是否定义
php
input('?get.id');
input('?post.name');
获取PARAM参数
php
input('param.name'); // 获取单个参数
input('param.'); // 获取全部参数
// 下面是等效的
input('name');
input('');
获取GET参数
php
// 获取单个变量
input('get.id');
// 使用过滤方法获取 默认为空字符串
input('get.name');
// 获取全部变量
input('get.');
使用过滤方法
php
input('get.name','','htmlspecialchars'); // 获取get变量 并用htmlspecialchars函数过滤
input('username','','strip_tags'); // 获取param变量 并用strip_tags函数过滤
input('post.name','','org\Filter::safeHtml'); // 获取post变量 并用org\Filter类的safeHtml方法过滤
使用变量修饰符
php
input('get.id/d');
input('post.name/s');
input('post.ids/a');
4.请求类型
获取请求类型
在很多情况下面,我们需要判断当前操作的请求类型是GET
、POST
、PUT
、DELETE
或者HEAD
,一方面可以针对请求类型作出不同的逻辑处理,另外一方面有些情况下面需要验证安全性,过滤不安全的请求。
请求对象Request
类提供了下列方法来获取或判断当前请求类型:
用途 | 方法 |
---|---|
获取当前请求类型 | method |
判断是否GET请求 | isGet |
判断是否POST请求 | isPost |
判断是否PUT请求 | isPut |
判断是否DELETE请求 | isDelete |
判断是否AJAX请求 | isAjax |
判断是否PJAX请求 | isPjax |
判断是否JSON请求 | isJson |
判断是否手机访问 | isMobile |
判断是否HEAD请求 | isHead |
判断是否PATCH请求 | isPatch |
判断是否OPTIONS请求 | isOptions |
判断是否为CLI执行 | isCli |
判断是否为CGI模式 | isCgi |
method
方法返回的请求类型始终是大写,这些方法都不需要传入任何参数。
没有必要在控制器中判断请求类型再来执行不同的逻辑,完全可以在路由中进行设置。
请求类型伪装
支持请求类型伪装,可以在POST
表单里面提交_method
变量,传入需要伪装的请求类型,例如:
html
<form method="post" action="">
<input type="text" name="name" value="Hello">
<input type="hidden" name="_method" value="PUT" >
<input type="submit" value="提交">
</form>
提交后的请求类型会被系统识别为PUT
请求。
你可以设置为任何合法的请求类型,包括
GET
、POST
、PUT
和DELETE
等,但伪装变量_method
只能通过POST请求进行提交。
如果要获取原始的请求类型,可以使用
php
Request::method(true);
在命令行下面执行的话,请求类型返回的始终是
GET
。
如果你需要改变伪装请求的变量名,可以修改自定义Request类的varMethod
属性:
AJAX/PJAX
伪装
可以对请求进行AJAX
请求伪装,如下:
php
http://localhost/index?_ajax=1
或者PJAX
请求伪装
php
http://localhost/index?_pjax=1
如果你需要改变伪装请求的变量名,可以修改自定义Request类的varAjax
和varPjax
属性:
_ajax
和_pjax
可以通过GET/POST/PUT
等请求变量伪装。
5.HTTP头信息
可以使用Request
对象的header
方法获取当前请求的HTTP
请求头信息,例如:
php
$info = Request::header();
echo $info['accept'];
echo $info['accept-encoding'];
echo $info['user-agent'];
也可以直接获取某个请求头信息,例如:
php
$agent = Request::header('user-agent');
HTTP
请求头信息的名称不区分大小写,并且_
会自动转换为-
,所以下面的写法都是等效的:
php
$agent = Request::header('user-agent');
$agent = Request::header('USER_AGENT');
6.伪静态
URL伪静态通常是为了满足更好的SEO效果,ThinkPHP支持伪静态URL设置,可以通过设置url_html_suffix
参数随意在URL的最后增加你想要的静态后缀,而不会影响当前操作的正常执行。例如,我们在route.php
中设置
php
'url_html_suffix' => 'shtml'
的话,我们可以把下面的URL
php
http://serverName/blog/read/id/1
变成
php
http://serverName/blog/read/id/1.shtml
后者更具有静态页面的URL特征,但是具有和前面的URL相同的执行效果,并且不会影响原来参数的使用。
默认情况下,伪静态的设置为html
,如果我们设置伪静态后缀为空字符串,
php
'url_html_suffix'=>''
则支持所有的静态后缀访问,如果要获取当前的伪静态后缀,可以使用Request
对象的ext
方法。
例如:
php
http://serverName/blog/3.html
http://serverName/blog/3.shtml
http://serverName/blog/3.xml
http://serverName/blog/3.pdf
都可以正常访问。
我们可以在控制器的操作方法中获取当前访问的伪静态后缀,例如:
php
$ext = Request::ext();
如果希望支持多个伪静态后缀,可以直接设置如下:
php
// 多个伪静态后缀设置 用|分割
'url_html_suffix' => 'html|shtml|xml'
那么,当访问 http://serverName/blog/3.pdf
的时候会报系统错误。
如果要关闭伪静态访问,可以设置
php
// 关闭伪静态后缀访问
'url_html_suffix' => false,
关闭伪静态访问后,不再支持伪静态方式的URL访问,并且伪静态后缀将会被解析为最后一个参数的值,例如:
php
http://serverName/blog/read/id/3.html
最终的id参数的值将会变成 3.html
。
7.参数绑定
参数绑定是把当前请求的变量作为操作方法(也包括架构方法)的参数直接传入,参数绑定并不区分请求类型。
参数绑定传入的值会经过全局过滤,如果你有额外的过滤需求可以在操作方法中单独处理。
参数绑定方式默认是按照变量名进行绑定,例如,我们给Blog
控制器定义了两个操作方法read
和archive
方法,由于read
操作需要指定一个id
参数,archive
方法需要指定年份(year
)和月份(month
)两个参数,那么我们可以如下定义:
php
<?php
namespace app\controller;
class Blog
{
public function read($id)
{
return 'id=' . $id;
}
public function archive($year, $month='01')
{
return 'year=' . $year . '&month=' . $month;
}
}
注意这里的操作方法并没有具体的业务逻辑,只是简单的示范。
URL的访问地址分别是:
php
http://serverName/index.php/blog/read/id/5
http://serverName/index.php/blog/archive/year/2016/month/06
两个URL地址中的id
参数和year
和month
参数会自动和read
操作方法以及archive
操作方法的同名参数
绑定。
变量名绑定不一定由访问URL决定,路由地址也能起到相同的作用
输出的结果依次是:
php
id=5
year=2016&month=06
按照变量名进行参数绑定的参数必须和URL中传入的变量名称一致,但是参数顺序不需要一致。也就是说
php
http://serverName/index.php/blog/archive/month/06/year/2016
和上面的访问结果是一致的,URL中的参数顺序和操作方法中的参数顺序都可以随意调整,关键是确保参数名称一致即可。
如果用户访问的URL地址是:
php
http://serverName/index.php/blog/read
那么会抛出下面的异常提示: 参数错误:id
报错的原因很简单,因为在执行read操作方法的时候,id参数是必须传入参数的,但是方法无法从URL地址中获取正确的id参数信息。由于我们不能相信用户的任何输入,因此建议你给read方法的id参数添加默认值,例如:
php
public function read($id = 0)
{
return 'id=' . $id;
}
这样,当我们访问 http://serverName/index.php/blog/read/
的时候 就会输出
php
id=0
始终给操作方法的参数定义默认值是一个避免报错的好办法(依赖注入参数除外)
为了更好的配合前端规范,支持自动识别小写+下划线的请求变量使用驼峰注入,例如:
php
http://serverName/index.php/blog/read/blog_id/5
可以使用下面的方式接收blog_id
变量,所以请确保在方法的参数使用驼峰(首字母小写)规范。
php
public function read($blogId = 0)
{
return 'id=' . $blogId;
}
8.请求缓存
支持请求缓存功能,支持对GET请求设置缓存访问,并设置有效期。
请求缓存仅对GET请求有效
有两种方式可以设置请求缓存:
路由设置
可以在路由规则里面调用cache
方法设置当前路由规则的请求缓存,例如:
php
// 定义GET请求路由规则 并设置3600秒的缓存
Route::get('new/:id','News/read')->cache(3600);
第二次访问相同的路由地址的时候,会自动获取请求缓存的数据响应输出,并发送304
状态码。
默认请求缓存的标识为当前访问的pathinfo
地址,可以定义请求缓存的标识,如下:
php
// 定义GET请求路由规则 并设置3600秒的缓存
Route::get('new/:id','News/read')->cache(
[ 'new/:id/:page', 3600]
);
:id
、:page
表示使用当前请求的param
参数进行动态标识替换,也就是根据id
和page
变量进行3600
秒的请求缓存。
如果
cache
参数传入false
,则表示关闭当前路由的请求缓存(即使开启全局请求缓存)。
php
// 定义GET请求路由规则 并关闭请求缓存(即使开启了全局请求缓存)
Route::get('new/:id','News/read')->cache(false);
支持给一组路由设置缓存标签
php
// 定义GET请求路由规则 并设置3600秒的缓存
Route::get('new/:id','News/read')->cache(
[ 'new/:id/:page', 3600, 'page']
);
这样可以在需要的时候统一清理缓存标签为page
的请求缓存。
全局请求缓存
如果需要开启全局请求缓存,只需要在全局(或者应用)的中间件定义文件middleware.php
中增加
php
'think\middleware\CheckRequestCache',
然后只需要在route.php
配置文件中设置全局缓存的有效时间(秒):
php
'request_cache_expire' => 3600,
就会自动根据当前请求URL地址(只针对GET请求类型)进行请求缓存,全局缓存有效期为3600秒。
如果需要对全局缓存设置缓存规则,可以直接设置request_cache_key
参数,例如:
php
'request_cache_key' => '__URL__',
'request_cache_expire' => 3600,
缓存标识支持下面的特殊定义
标识 | 含义 |
---|---|
__CONTROLLER__ |
当前控制器名 |
__ACTION__ |
当前操作名 |
__URL__ |
当前完整URL地址(包含域名) |
全局请求缓存支持设置排除规则,使用方法如下:
php
'request_cache_key' => true,
'request_cache_expire' => 3600,
'request_cache_except' => [
'/blog/index',
'/user/member',
],
排除规则为不使用请求缓存的地址(不支持变量)开头部分(不区分大小写)。
php
public function run(){
//URL生成
echo Route::buildUrl()."<br>";
//生成当前控制器的URL
echo Route::buildUrl('add')."<br>";
//访问其他控制器的URL
echo Route::buildUrl('Index/index')."<br>";
//其他应用下的URL
echo Route::buildUrl('admin/index/index')."<br>";
//访问时带参数
echo Route::buildUrl('add', ['id' => 123])."<br>";
//访问时带多个参数
echo Route::buildUrl('add', ['id' => 123, 'name' => 'thinkphp'])."<br>";
//config下的route.ph可以修改静态路由规则
//修改伪静态后缀名
echo Route::buildUrl('RequestTest/test', [], '.shtml')."<br>";
//带上域名
echo Route::buildUrl('RequestTest/test', [], '.shtml')->domain('www.thinkphp.cn')."<br>";
return "跳过";
}
如果您在浏览文章的时候发现了错误,还请您在评论区留言,笔者看到后会在第一时间处理,谢谢。