ThinkPHP3.2.3变量
首先我们来学习如何在ThinkPHP中使用变量和对变量进行过滤。
在Web开发过程中,我们经常需要获取系统变量或者用户提交的数据,这些变量数据错综复杂,而且一不小心就容易引起安全隐患,但是如果利用好ThinkPHP提供的变量获取功能,就可以轻松的获取和驾驭变量了。
获取变量
虽然你仍然可以在开发过程中使用传统方式获取各种系统变量,例如:
$id = $_GET['id']; // 获取get变量
$name = $_POST['name']; // 获取post变量
$value = $_SESSION['var']; // 获取session变量
$name = $_COOKIE['name']; // 获取cookie变量
$file = $_SERVER['PHP_SELF']; // 获取server变量
但是我们不建议直接使用传统方式获取,因为没有统一的安全处理机制,后期如果调整的话,改起来会比较麻烦。所以,更好的方式是在框架中统一使用I函数进行变量获取和过滤。
I方法是ThinkPHP用于更加方便和安全的获取系统输入变量,可以用于任何地方,用法格式如下:
I('变量类型.变量名/修饰符',['默认值'],['过滤方法'],['额外数据源'])
变量类型是指请求方式或者输入类型,包括:
**变量类型 含义**
get 获取GET参数
post 获取POST参数
param 自动判断请求类型获取GET、POST或者PUT参数
request 获取REQUEST 参数
put 获取PUT 参数
session 获取 $_SESSION 参数
cookie 获取 $_COOKIE 参数
server 获取 $_SERVER 参数
globals 获取 $GLOBALS参数
path 获取 PATHINFO模式的URL参数
data 获取 其他类型的参数,需要配合额外数据源参数
注意:变量类型不区分大小写。
变量名则严格区分大小写。
默认值和过滤方法均属于可选参数。
我们以GET变量类型为例,说明下I方法的使用:
echo I('get.id'); // 相当于 $_GET['id']
echo I('get.name'); // 相当于 $_GET['name']
支持默认值:
echo I('get.id',0); // 如果不存在$_GET['id'] 则返回0
echo I('get.name',''); // 如果不存在$_GET['name'] 则返回空字符串
采用方法过滤:
// 采用htmlspecialchars方法对$_GET['name'] 进行过滤,如果不存在则返回空字符串
echo I('get.name','','htmlspecialchars');
支持直接获取整个变量类型,例如:
// 获取整个$_GET 数组
I('get.');
用同样的方式,我们可以获取post或者其他输入类型的变量,例如:
I('post.name','','htmlspecialchars'); // 采用htmlspecialchars方法对$_POST['name'] 进行过滤,如果不存在则返回空字符串
I('session.user_id',0); // 获取$_SESSION['user_id'] 如果不存在则默认为0
I('cookie.'); // 获取整个 $_COOKIE 数组
I('server.REQUEST_METHOD'); // 获取 $_SERVER['REQUEST_METHOD']
param变量类型是框架特有的支持自动判断当前请求类型的变量获取方式,例如:
echo I('param.id');
如果当前请求类型是GET,那么等效于 $_GET[‘id’],如果当前请求类型是POST或者PUT,那么相当于获取 $_POST[‘id’] 或者 PUT参数id。
由于param类型是I函数默认获取的变量类型,因此事实上param变量类型的写法可以简化为:
I('id'); // 等同于 I('param.id')
I('name'); // 等同于 I('param.name')
path类型变量可以用于获取PATHINFO方式的URL参数(必须是PATHINFO模式参数有效,无论是GET还是POST方式都有效),例如:
当前访问URL地址是
http://serverName/index.php/New/2013/06/01
那么我们可以通过
echo I('path.1'); // 输出2013
echo I('path.2'); // 输出06
echo I('path.3'); // 输出01
变量过滤
如果你没有在调用I函数的时候指定过滤方法的话,系统会采用默认的过滤机制(由DEFAULT_FILTER配置),事实上,该参数的默认设置是:
// 系统默认的变量过滤机制'DEFAULT_FILTER' => 'htmlspecialchars'
也就说,I方法的所有获取变量如果没有设置过滤方法的话都会进行htmlspecialchars过滤,那么:
// 等同于 htmlspecialchars($_GET['name'])
I('get.name');
同样,该参数也可以设置支持多个过滤,例如:
'DEFAULT_FILTER' => 'strip_tags,htmlspecialchars'
设置后,我们在使用:
// 等同于 htmlspecialchars(strip_tags($_GET['name']))
I('get.name');
如果我们在使用I方法的时候 指定了过滤方法,那么就会忽略DEFAULT_FILTER的设置,例如:
// 等同于 strip_tags($_GET['name'])
echo I('get.name','','strip_tags');
I方法的第三个参数如果传入函数名,则表示调用该函数对变量进行过滤并返回(在变量是数组的情况下自动使用array_map进行过滤处理),否则会调用PHP内置的filter_var方法进行过滤处理,例如:
I('post.email','',FILTER_VALIDATE_EMAIL);
表示 会对$_POST[‘email’] 进行 格式验证,如果不符合要求的话,返回空字符串。
(关于更多的验证格式,可以参考 官方手册的filter_var用法。)
或者可以用下面的字符标识方式:
I('post.email','','email');
可以支持的过滤名称必须是filter_list方法中的有效值(不同的服务器环境可能有所不同),可能支持的包括:
intbooleanfloatvalidate_regexp
validate_url
validate_email
validate_ipstringstripped
encoded
special_chars
unsafe_raw
email
url
number_int
number_float
magic_quotes
callback
也可以支持正则匹配过滤,例如:
// 采用正则表达式进行变量过滤I(‘get.name’,‘’,‘/1+$/’);
I('get.id',0,'/^\d+$/');
如果正则匹配不通过的话,则返回默认值。
在有些特殊的情况下,我们不希望进行任何过滤,即使DEFAULT_FILTER已经有所设置,可以使用:
// 下面两种方式都不采用任何过滤方法I('get.name','','');
I('get.id','',false);
一旦过滤参数设置为空字符串或者false,即表示不再进行任何的过滤。
变量修饰符
I函数支持对变量使用修饰符功能,可以更好的过滤变量。
用法如下:
I('变量类型.变量名/修饰符');
例如:
I('get.id/d');
I('post.name/s');
I('post.ids/a');
可以使用的修饰符包括:
**修饰符 作用**
s 强制转换为字符串类型
d 强制转换为整形类型
b 强制转换为布尔类型
a 强制转换为数组类型
f 强制转换为浮点类型
ThinkPHP3.2.3路由
ThinkPHP框架对URL有一定的规范,所以如果你希望定制你的URL格式的话,就需要好好了解下内置的路由功能了,它能让你的URL变得更简洁和有内涵。
路由定义
路由定义一般包括三个配置参数:
**参数 描述**
URL_ROUTER_ON 开启路由,设置为true后路由规则定义生效
URL_ROUTE_RULES 路由规则定义
URL_MAP_RULES 静态路由(URL映射)定义
要使用路由功能,前提是你的URL支持PATH_INFO(或者兼容URL模式也可以,采用普通URL模式的情况下不支持路由功能),并且在应用(或者模块)配置文件中开启路由:
'URL_ROUTER_ON' => true, //开启路由
然后就是配置路由规则了,使用URL_ROUTE_RULES参数进行配置,配置格式是一个数组,每个元素都代表一个路由规则,例如:
'URL_ROUTE_RULES'=>array(
'news/:year/:month/:day' => array('News/archive', 'status=1'),
'news/:id' => 'News/read',
'news/read/:id' => '/news/:1',
),
系统会按定义的顺序依次匹配路由规则,一旦匹配到的话,就会定位到路由定义中的模块、控制器和操作方法去执行(可以传入其他的参数),并且后面的规则不会继续匹配。
路由规则一般是配置在模块的配置文件中(模块名/Conf/config.php),这样的话路由规则仅针对当前模块,并且URL中匹配的路由不能省略当前模块名(除了默认模块外)。如果需要定义全局的路由规则,就需要把路由配置定义在公共模块的配置文件中(Common/Conf/config.php),但全局路由定义的路由规则中必须包含明确的模块。
路由规则的定义方式如下:
'路由表达式'=>'路由地址和额外参数'
路由表达式
路由表达式包括规则路由和正则路由的定义表达式,只能使用字符串。
**表达式 示例**
正则表达式 /^blog\/(\d+)$/
规则表达式 blog/:id
正则表达式
路由表达式支持的正则定义必须以“/”开头,否则就视为规则表达式。也就是说如果采用
'#^blog\/(\d+)$#'
方式定义的正则表达式不会被支持,而会被认为是规则表达式进行解析,从而无法正确匹配。
'/^new\/(\d{4})\/(\d{2})$/' => 'News/achive?year=:1&month=:2',
对于正则表达式中的**每个变量(即正则规则中的子模式)**部分,如果需要在后面的路由地址中引用,可以采用:1、:2这样的方式,序号就是子模式的序号。
更多的关于如何定义正则表达式就不在本文的描述范畴了。
规则表达式
规则路由比正则路由更方便定义和容易理解,规则表达式通常包含静态地址和动态地址,或者两种地址的结合,例如下面都属于有效的规则表达式:
'my' =>'Member/myinfo', // 静态地址路由 类似于之前版本的简单路由
'blog/:id' =>'Blog/read', // 静态地址和动态地址结合
'new/:year/:month/:day'=>'News/read', // 静态地址和动态地址结合
':user/:blog_id'=>'Blog/read',// 全动态地址
规则表达式的定义以“/”为参数分割符(无论你的URL_PATHINFO_DEPR设置是什么,请确保在定义规则表达式的时候统一使用“/”进行URL参数分割)。
每个参数中以“:”开头的参数都表示动态参数,并且会自动对应一个GET参数,例如:id表示该处匹配到的参数可以使用
G
E
T
[
′
i
d
′
]
方
式
获
取
,
:
y
e
a
r
:
m
o
n
t
h
:
d
a
y
则
分
别
对
应
_GET['id']方式获取,:year :month :day 则分别对应
GET[′id′]方式获取,:year:month:day则分别对应_GET[‘year’] $_GET[‘month’] $_GET[‘day’]。
数字约束
支持对变量的类型检测,但仅仅支持数字类型的约束定义,例如
'blog/:id\d'=>'Blog/read',
表示只会匹配数字参数,如果你需要更加多的变量类型检测,请使用正则表达式定义来解决。
规则排除
非数字变量支持简单的排除功能,主要是起到避免解析混淆的作用,例如:
'news/:cate^add-edit-delete'=>'News/category'
因为规则定义的局限性,恰巧我们的路由规则里面的news和实际的news模块是相同的命名,而:cate并不能自动区分当前URL里面的动态参数是实际的操作名还是路由变量,所以为了避免混淆,我们需要对路由变量cate进行一些排除以帮助我们进行更精确的路由匹配,格式^add|edit|delete表示,匹配除了add edit 和delete之外的所有字符串,建议更好的方式还是改进你的路由规则,避免路由规则和模块同名的情况存在,例如
'new/:cate'=>'News/category'
就可以更简单的定义路由规则了。
完全匹配
规则匹配检测的时候只是对URL从头开始匹配,只要URL地址包含了定义的路由规则就会匹配成功,如果希望完全匹配,可以使用$符号,例如:
'new/:cate$'=> 'News/category',
http://serverName/index.php/new/info
会匹配成功
而
http://serverName/index.php/new/info/2
则不会匹配成功
如果是采用
'new/:cate'=> 'News/category',
方式定义的话,则两种方式的URL访问都可以匹配成功。
路由地址和参数
路由地址和参数表示前面的路由表达式最终需要路由到的地址并且允许隐式传入URL里面没有的一些参数,这里允许使用字符串或者数组方式定义,支持下面6种方式定义:
**定义方式 定义格式**
方式1:路由到内部地址(字符串) '[分组/模块/操作]?参数1=值1&参数2=值2...'
方式2:路由到内部地址(数组)参数采用字符串方式 array('[分组/模块/操作]','参数1=值1&参数2=值2...')
方式3:路由到内部地址(数组)参数采用数组方式 array('[分组/模块/操作]',array('参数1'=>'值1','参数2'=>'值2'...))
方式4:路由到外部地址(字符串)301重定向 '外部地址'
方式5:路由到外部地址(数组)可以指定重定向代码 array('外部地址','重定向代码')
方式6:闭包函数 function($name){ echo 'Hello,'.$name;}
如果路由地址以“/”或者“http”开头则会认为是一个重定向地址或者外部地址,例如:
'blog/:id'=>'/blog/read/id/:1'
和
'blog/:id'=>'blog/read/'
虽然都是路由到同一个地址,但是前者采用的是301重定向的方式路由跳转,这种方式的好处是URL可以比较随意(包括可以在URL里面传入更多的非标准格式的参数),而后者只是支持模块和操作地址。
举个例子,如果我们希望avatar/123重定向到
/member/avatar/id/123_small的话,只能使用:
'avatar/:id'=>'/member/avatar/id/:1_small'
路由地址采用重定向地址的话,如果要引用动态变量,也是采用:1、:2 的方式。
采用重定向到外部地址通常对网站改版后的URL迁移过程非常有用,例如:
'blog/:id'=>'http://blog.thinkphp.cn/read/:1'
表示当前网站(可能是http://thinkphp.cn)的 blog/123地址会直接重定向到 http://blog.thinkphp.cn/read/123。
在路由跳转的时候支持额外传入参数对(额外参数指的是不在URL里面的参数,隐式传入需要的操作中,有时候能够起到一定的安全防护作用,后面我们会提到),支持“参数1=值1&参数2=值2”或者array(‘参数1’=>‘值1’,‘参数2’=>‘值2’…)这样的写法,可以参考不同的定义方式选择。例如:
'blog/:id'=>'blog/read/?status=1&app_id=5',
'blog/:id'=>array('blog/read/?status=1&app_id=5'),
'blog/:id'=>array('blog/read/','status=1&app_id=5'),
'blog/:id'=>array('blog/read/',array('status'=>1,'app_id'=>5)),
上面的路由规则定义中额外参数的传值方式都是等效的。status和app_id参数都是URL里面不存在的,属于隐式传值,当然并不一定需要用到,只是在需要的时候可以使用。
闭包支持
我们可以使用闭包的方式定义一些特殊需求的路由,而不需要执行控制器的操作方法了,例如:
'URL_ROUTE_RULES'=>array(
'test' => function(){ echo 'just test'; },
'hello/:name' => function($name){
echo 'Hello,'.$name;
}
)
参数传递
闭包定义的参数传递在规则路由和正则路由的两种情况下有所区别。
规则路由的参数传递比较简单:
'hello/:name' =>
function($name){
echo 'Hello,'.$name;
}
规则路由中定义的动态变量的名称 就是闭包函数中的参数名称,不分次序。 因此,如果我们访问的URL地址是: http://serverName/Home/hello/thinkphp
则浏览器输出的结果是: Hello,thinkphp
如果多个参数可以使用:
'blog/:year/:month' =>
function($year,$month){
echo 'year='.$year.'&month='.$month;
}
如果是正则路由的话,闭包函数中的参数就以正则中出现的参数次序来传递,例如:
'/^new\/(\d{4})\/(\d{2})$/' =>
function($year,$month){
echo 'year='.$year.'&month='.$month;
}
如果我们访问: http://serverName/Home/new/2013/03 浏览器输出结果是:
year=2013&month=03
A-Za-z ↩︎