ThinkPHP采用单一入口模式访问应用,对应用的所有请求都定向到应用的入口文件,系统会从URL参数中解析当前请求的模块、控制器和操作,下面是一个标准的URL访问格式:
http://domainName/index.php/模块/控制器/操作
其中index.php就称之为应用的入口文件(注意入口文件可以被隐藏,后面会提到),模块在ThinkPHP中的概念其实就是应用目录下面的子目录,而官方的规范是目录名小写,因此模块全部采用小写命名,无论URL是否开启大小写转换,模块名都会强制小写。
若访问Index控制器下的index方法的话,可以直接访问localhost/index.php,活着localhost/index.php/index/index/index
若访问Index控制器下的hello方法的话,需要完整的URL地址,localhost/index.php/index/index/hello
若方法有参数的话,看参数是否有默认值,有默认值为可选是否添加,添加可以直接添加在方法名后,
localhost/index.php/index/index/hello
localhost/index.php/index/index/hello/name/thinkphp
默认情况下,URL地址中的控制器和操作名是不区分大小写的,上下两者相同
localhost/index.php/index/Index/Index
localhost/index.php/index/INDEX/INDEX
如果你的控制器是驼峰的,例如定义一个HelloWorld控制器(application/index/controller/HelloWorld.php)注意文件名和控制器名要相同才行,正确的URL访问地址(该地址可以使用url方法生成)应该是:
localhost/index.php/index/hello_world/index
如果直接使用HelloWorld在URL中描述控制器的话,将会提示该控制器不存在,可以在配置文件中进行修改 ‘url_convert’ => false,false表示关闭URL自动转换,支持驼峰直接访问控制器,关闭之后必须严格使用控制器的名称访问
对于下面的方法分别为index和hello操作中,分别有不同的参数,
正常访问hello的URL为lcoalhost/index.php/index/index/hello,因为没有参数,则选择参数重的默认值,如果传入参数的话,则采用参数值,localhost/index.php/index/index/hello/name/thinkphp,输出结果为Hello,thinkphp!
对hello的方法增加参数情况下
public function hello($name = 'World', $city = '')
{
return 'Hello,' . $name . '! You come from ' . $city . '.';
}
则该情况下的访问地址为lcoalhost/index.php/index/index/hello/name/thinkphp/city/shanghai,页面输出为 Hello,thinkphp! You come from shanghai.
对于3中的两个参数,可以根据传入的顺序不同的情况下来输出结果,并不影响最后结果,即:
localhost/index.php/index/index/hello/city/shanghai/name/thinkphp
localhost/index.php/index/index/hello?city=shanghai&name=thinkphp
还可以进一步简化URL,前提是必须明确参数的顺序代表的变量,首先调整配置文件中的url_param_type
变量,改为按照参数的顺序获取,‘url_param_type’ => 1
localhost/index.php/index/index/hello/thinkphp/shanghai,则页面的输出结果为:Hello,thinkphp! You come from shanghai.
一旦使用了url_param_type
顺序获取,就不可以使用get或post。
主要目的是隐藏index.php,这个主要看你使用的是apache还是nginx,我这里使用的是mac下的自带的apache,很坎坷
其中mac自带的apache的文件的http.conf文件在/etc/apache2中,首先需要将mod_rewrite模块前面的#注释去除掉,然后文件中里面有三个AllowOverride All,我 都打开了。
在public下的index.php同级的目录下,会存在一个.htaccess文件,这个文件中需要配置内容,目的是隐藏index.php
Options +FollowSymlinks -Multiviews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
还有关于apache的phpstudy配置和nginx的配置方法等,请参考: 隐藏index.php
可以在文件中的return数组中直接添加路由规则,该规则可以表示所有hello开头的并且带参数的访问都会直接到index控制器中的hello方法中。
return [
// 添加路由规则 路由到 index控制器的hello操作方法
'hello/:name' => 'index/index/hello',
];
添加路由之后的访问地址变更为:
localhost/hello/thinkphp,原地址的URL访问会失效变,localhost/index/index/hello/name/thinkphp
非法请求。
此时在访问localhost/hello/thinkphp
的时候可以任意访问,但是无论index控制器下的hello操作方法是否含有参数的情况下,直接访问localhost/hello
都是不可以的,会产生模块不存在的错误。此时因为路由定义的为'hello/:name'
,表示hello中必须添加一个参数为name在hello的URL后面。
若是路由定义为'hello' => 'index/index/hello',
,表示可以直接访问URL为localhost\hello
即可,此时无法传入任何参数。
对3中的情况是因为路由没有正确匹配,注意此时添加的路由是需要参数的,修改路由规则即可,即将规则中的参数部分用[]
将变量包起来,表示该变量可选,就可以正常的访问localhost/hello
return [
// 路由参数 name 可选
'hello/[:name]' => 'index/hello',
];
Route::rule('hello/:name', index/index/hello);
上文定义的只要是localhost/hello
就可以访问,但是如果需要完整匹配的话,就需要在路由规则后面添加$
结尾,表示当前的路由为完整匹配,要不的话,可以在路由后面添加多少东西都可以正常访问前面的hello操作方法
return[
// 路由参数 name 可选
'hello/[:name]$' => 'index/index/hello',
]
在配置完整匹配后,表示只可以按照完整的路由进行访问,其他形式都不回匹配localhost/hello
: 正确匹配localhost/hello/thinkphp
: 正确匹配localhost/hello/thinkphp/val/value
: 不会匹配
暂时没太理解这个功能是什么用的,但是这个可以直接返回,就不用在控制器中定义了,可以直接在路由中定义操作方法。使用方法可以使用return或者直接定义。
use think/Route
// 直接定义
Route::rule('hello/[:name]', function($name) {
return 'Hello, ' . $name . '!';
});
// 使用return定义
return [
// 定义闭包
'hello/[:name]' => function ($name) {
return 'Hello, ' . $name . '!';
},
];
可以通过访问localhost/hello/thinkphp
地址,会输出Hello, thinkphp!
/
可以修改为其他的符号,但是需要修改配置文件,配置文件在config/app.php
中的pathinfo_depr
,将该变量设置为想要的符号即可'pathinfo_depr' => '-'
,这样访问地址的就变为了localhost/hello-thinkphp
路由可以根据路由参数来限制路由访问的请求类型或者URL后缀之类的条件,例如
return [
// 定义理由的请求类型和后缀
'hello/[:name]' => ['index/index/hello', ['method' => 'get', 'ext' => 'html']],
];
上面定义的路由限制了必需是get
请求,而且后缀必需是html
的,所以访问的时候
localhost/hello : 无效
localhost/hello.html : 有效
localhost/hello/thinkphp : 无效
localhost/hello/thinkphp.html : 有效
具体的路由参数还需要参考完全开发手册中的路由参数一节ThinkPHP完全开发手册-路由-路由参数。
可以定义复杂的路由规则来满足不同的路由变量,增加下面的控制器和操作方法
常规的思路是在return中添加路由规则,并可以通过下面的URL进行访问
localhost/blog/5 // 访问id为5的内容
localhost/blog/thinkphp // 访问name为thinkphp的内容
localhost/blog/2015/05 // 访问2015年5月的归档内容
普通情况下在return[]中添加的形式
return [
'blog/:year/:month' => ['index/blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
'blog/:id' => ['index/blog/read', ['method' => 'get'], ['id' => '\d+']],
'blog/:name' => ['index/blog/get', ['method' => 'get'], ['name' => '\w+']],
];
也可以对上面的路由进行简化,因为都是blog开头的路由,这种定义可以一定程度上提高路由的检测的效率。
return [
'[blog]' => [
':year/:month' => ['index/blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
':id' => ['index/blog/read', ['method' => 'get'], ['id' => '\d+']],
':name' => ['index/blog/get', ['method' => 'get'], ['name' => '\w+']],
],
];
有时候需要对URL做一些特殊的定制,例如如果同时支持下面的访问地址
localhost/blog/thinkphp
localhost/blog-2015-05
可以根据上面的访问形式来修改路由的定义的规则,对于blog-
这样的非正常规范,需要使用<变量名>
这样的变量定义方式,而不是:变量名
方式。
return [
'blog/:id' => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
'blog/:name' => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
'blog--' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
];
还可以将参数的定义规则提取出来,存放到全局,用来直接使用
return [
// 全局变量规则定义
'__pattern__' => [
'name' => '\w+',
'id' => '\d+',
'year' => '\d{4}',
'month' => '\d{2}',
],
// 路由规则定义
'blog/:id' => 'blog/get',
'blog/:name' => 'blog/read',
'blog--' => 'blog/archive',
];
在__pattern__
中定义的变量规则可以称为全局变量规则,在单个路由里面定义的称为局部变量规则,若同时定义了全局规则和局部规则,当前的局部规则会覆盖全局规则。
return [
// 全局变量规则
'__pattern__' => [
'name' => '\w+',
'id' => '\d+',
'year' => '\d{4}',
'month' => '\d{2}',
],
'blog/:id' => 'blog/get',
// 定义了局部变量规则
'blog/:name' => ['blog/read', ['method' => 'get'], ['name' => '\w{5,}']], // 这里表示字母长度必需大于等于5个
'blog--' => 'blog/archive',
];
在5.1中路由配置文件为单独的route/route.php
,并且支持随意明明,都会自动加载,尽量建议使用注册路由的方式替代数组配置的方式
use think\facade\Route;
Route::get('blog/:id','blog/get');
Route::get('blog/:name','blog/read');
URL生成的目的,目前的理解为:
1.controller下的php文件生成路由如:
$url= Url::build('blog/read', 'name='.$param);
然后其他地方就可以直接调用$url
2.view下的html文件跳转指定地址如超链接里面内容为:{:url('blog/read', 'name='.$param)}
定义路由规则之后,我们可以通过Url类来方便的生成实际的URL地址(路由地址),针对上面的路由规则,我们可以用下面的方式生成URL地址。build方法的第一个参数使用路由定义中的完整路由地址。
// 输出 blog/thinkphp
Url::build('blog/read', 'name=thinkphp');
Url::build('blog/read', ['name' => 'thinkphp']);
// 输出 blog/5
Url::build('blog/get', 'id=5');
Url::build('blog/get', ['id' => 5]);
// 输出 blog/2015/05
Url::build('blog/archive', 'year=2015&month=05');
Url::build('blog/archive', ['year' => '2015', 'month' => '05']);
可以使用系统提供的助手函数URL简化,url('blog/read', 'name=thinkphp');
等效于 Url::build('blog/read', 'name=thinkphp');
**?**若在模版文件中进行输出的话,可以使用助手函数,{:url('blog/read', 'name=thinkphp')}
在config/app.php
中进行配置url_html_suffix
参数的话,生成的URL地址会带上后缀'url_html_suffix' => 'html',
生成的URL地址类似blog/thinkphp.html
和blog/2015/05.html
如果你的URL地址全部采用路由方式定义,也可以直接使用路由规则来定义URL生成
url(’/blog/thinkphp’);
Url::build(’/blog/8’);
Url::build(’/blog/archive/2015/05’);
生成方法的第一个参数一定要和路由定义的路由地址保持一致,如果你的路由地址比较特殊,例如使用闭包定义的话,则需要手动给路由指定标识
// 添加hello路由标识
Route::rule(['hello','hello/:name'], function($name){
return 'Hello,'.$name;
});
// 根据路由标识快速生成URL
Url::build('hello', 'name=thinkphp');
// 或者使用
Url::build('hello', ['name' => 'thinkphp']);
5.1版本,你需要引入think\facade\Url才能使用静态方法调用,其它用法不变。高阶方法具体可参考ThinkPHP5路由完全指南