ThinkPHP实战
上QQ阅读APP看书,第一时间看更新

3.2 ThinkPHP的路由

3.2.1 路由模式

ThinkPHP的路由支持以下四种模式:

● 普通模式

● pathinfo模式

● rewrite模式

● 兼容模式

接下来通过一个具体的场景来分析这四种路由模式,假设用户访问Home模块的Index控制器的index方法,这四种模式下的URL如下:

● 普通模式:http://www.example.com/index.php? m=home&c=index&a=index

● pathinfo模式:http://www.example.com/index.php/home/index/index

● rewrite模式:http://www.example.com/home/index/index

● 兼容模式:http://www.example.com/index.php? s=home/index/index

可以看到普通模式和兼容模式可以归类到动态URL中,pathinfo和rewrite模式可以归类到伪静态模式中。rewrite模式和pathinfo模式的区别在于前者没有index.php,有HTTP基础的读者可能有些不理解,如果按照静态页面的处理方式,rewrite模式下Web服务器会前往Web目录下的home/index/index查找默认首页,如果存在则发送给浏览器,否则发送404错误页面。

接下来可以进行测试,观察这四种URL在浏览器中的实际情况,请将www.example.com替换为相应的Web目录(笔者的为http://localhost/thinkphp-inaction)。

在Web目录下新建文件夹chapter-3,按照第2章的方法新建入口文件,并且在浏览器访问使ThinkPHP初始化。

编辑Application/Home/Controller/IndexController.class.php,内容如下:

        <? php
        namespace Home\Controller;
        use Think\Controller;
        class IndexController extends Controller
        {
            public function index()
            {
                echo 1;
            }
        }

文件内容很简单,只要浏览器输出“1”证明访问home/index/index成功。打开浏览器分别测试普通模式(见图3-1)、pathinfo模式(见图3-2)和rewrite模式(见图3-3)。

图3-1

图3-2

图3-3

可以看到,rewrite模式下,已经访问不到home/index/index了,观察URL发现,Web服务器在home/index/index目录下查找默认文件了。这时候就需要对Web服务器进行URL重写设置。

在chapter-3下级目录新建文件“.htaccess”,文件无名称,扩展名为“htaccess”,该文件为Apache服务器的分布式配置文件(通俗点说,就是每个站点可以单独设置,互不影响),文件结构如图3-4所示。

图3-4

文件内容如下:

        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} ! -d
        RewriteCond %{REQUEST_FILENAME} ! -f
        RewriteRule ^(.*)$ index.php/$1 [L]

文件第1行:打开重写引擎。

文件第2行和第3行:如果请求文件不是目录而且不是文件(证明服务器上没有该请求文件或请求目录)。

文件第4行:将所有请求重定向到当前目录下的index.php文件,“L”代表如果该规则成功处理,则不继续处理下一条规则。

http://localhost/thinkphp-inaction/chapter-3/home/index/index为例,由于服务器上并不存在home/index/index目录,故Apache将请求参数“/home/index/index”全部传给chapter-3/index.php文件处理。

打开浏览器刷新,可以看到如图3-5所示界面。

图3-5

最后则是兼容模式的测试,结果如图3-6所示。

图3-6

3.2.2 路由配置

要使用ThinkPHP的路由功能,只要Web服务器支持除普通模式外的任何一种模式即可,前提是在公共(或模块)配置文件中启用路由功能。

编辑Application/Common/Conf/config.php,内容如下:

        <? php
        /**
         * config.php
         */
        return array(
            'URL_ROUTER_ON' => true
        );

接下来就是配置路由规则了,在模块的配置文件中使用URL_ROUTE_RULES参数进行配置,配置格式为数组,一个元素就是一个路由规则,编辑Application/Home/Conf/config.php,内容如下:

        <? php
        /**
         * config.php
         */
        return array(
            'URL_ROUTE_RULES' => array(
              'posts/:year/:month/:day' => 'Index/index',
              'posts/:id' => 'Index/index',
              'posts/read/:id' => '/posts/:1',
            ),
        );

打开浏览器访问http://localhost/thinkphp-inaction/chapter-3/home/posts/2015/01/01,结果如图3-7所示。

图3-7

ThinkPHP已经将请求地址路由到Application/Home/Controller/IndexController.class.php的index方法中去了。

为了测试一下路由图3-7的结果是否是ThinkPHP路由导致的,编辑Application/Common/Conf/config.php文件,内容如下:

        <? php
        /**
         * config.php
         */
        return array(
            'URL_ROUTER_ON' => false
        );

刷新浏览器,可以看到如图3-8所示结果。

图3-8

路由定义的一般规则是:“路由表达式”=>“路由地址和参数”或者array(“路由表达式”,“路由地址”,“传入参数”)。

“路由表达式”指“以何种规则”匹配浏览器中的地址,如果匹配成功,系统将在处理请求的同时把“传入参数”(如果有配置)传给指定的动作。

ThinkPHP的路由规则采用顺序遍历方式进行,只要成功匹配一条匹配的路由,则终止继续匹配。

路由表达式支持规则路由、正则路由、静态路由。

1.规则路由

'posts/:year/:month/:day' => 'Index/index',是一个典型的规则路由,通过“:”进行参数匹配,如果匹配成功,则将该位置的参数传给指定的动作。

编辑Application/Common/Conf/config.php文件,将“false”更改为“true”,编辑Application/Home/Controller/IndexController.class.php,内容如下:

        <? php
        namespace Home\Controller;
        use Think\Controller;
        class IndexController extends Controller
        {
        public function index()
        {
            echo "year:".$_GET['year'].", month:".$_GET['month'].",day:".$_GET['day'];
        }
        }

刷新浏览器,可以看到如图3-9所示结果。

图3-9

ThinkPHP已经将URL地址中的各项参数传给相应的动作,如果是未启用路由的状态,需要获取year、month、day参数就必须访问形如http://localhost/thinkphp-inaction/chapter-3/index.php? year=2015&month=01&day=01这样的URL才可以。

2.正则路由

顾名思义,正则路由就是利用正则表达式进行“路由表达式”配置,至于正则表达式相关知识,读者可以在网上参考相关资料。

编辑Application/Home/Conf/config.php,内容如下:

        <? php
        /**
         * config.php
        */
       return array(
          'URL_ROUTE_RULES' => array(
              '/^posts\/(\d{4})\/(\d{2})\/(\d{2})$/' =>'Index/index? year=:1&month=:2&day=1',
              'posts/:year/:month/:day' => 'Index/index',
              'posts/:id' => 'Index/index',
              'posts/read/:id' => '/posts/:1',
          ),
       );

请注意:正则路由的最后一个“1”前面没有“:”,固只要URL匹配成功,day参数永远为1。

刷新浏览器,可以看到如图3-10所示的结果。

图3-10

正则路由匹配成功,所以day为1;如果正则路由匹配失败,浏览器将输出12。

接下来将浏览器地址栏URL改为http://localhost/thinkphp-inaction/chapter-3/home/posts/2015/01/010,刷新浏览器,可以看到如图3-11所示的结果。

图3-11

可以看到输出的day为“121”,证明ThinkPHP匹配到了第二条路由,这就是正则路由的优势,最严格的匹配模式,路由配置中正则表达式的最后一个子模式为“(\d{2})”,该正则只匹配两位数字,而请求的URL地址中最后一个参数为3位数字,固正则路由匹配失败,系统使用规则路由。

3.静态路由

静态路由定义中不包含任何动态参数,也不需要遍历路由规则,所以路由效果比前两者高,为了区分前两种路由规则,静态路由采用URL_MAP_RULES进行定义。

编辑Application/Home/Conf/config.php,内容如下:

        <? php
        /**
         * config.php
         */
        return array(
            'URL_ROUTE_RULES' => array(
              '/^posts\/(\d{4})\/(\d{2})\/(\d{2})$/' =>
    'Index/index? year=:1&month=:2&day=1',
              'posts/:year/:month/:day' => 'Index/index',
              'posts/:id' => 'Index/index',
              'posts/read/:id' => '/posts/:1',
            ),
            'URL_MAP_RULES' => array(
              'site/welcome' => 'Index/index? from=seo'
            )
        );

编辑Application/Home/Controller/IndexController.class.php,内容如下:

        <? php
        namespace Home\Controller;
        use Think\Controller;
        class IndexController extends Controller
        {
        public function index()
        {
            echo $_GET['from'];
        }
        }

在浏览器中访问http://localhost/thinkphp-inaction/chapter-3/home/site/welcome,可以看到如图3-12所示结果。

图3-12