热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ThinkPHP3.1快速入门(6)路由

ThinkPHP框架对URL有一定的规范,所以如果你希望定制你的URL格式的话,就需要好好了解下内置的路由功能了,它能让你的URL变得更简洁和有文化。
ThinkPHP框架对URL有一定的规范,所以如果你希望定制你的URL格式的话,就需要好好了解下内置的路由功能了,它能让你的URL变得更简洁和有文化。

启用路由

要使用路由功能,前提是你的URL支持PATH_INFO,并且在项目配置文件中开启路由:
  1. 'URL_ROUTER_ON'   => true//开启路由
然后就是配置路由规则了,使用URL_ROUTE_RULES参数进行配置,配置格式是一个数组,每个元素都代表一个路由规则,例如:
  1. 'URL_ROUTE_RULES'=>array(
  2.     'news/:year/:month/:day' => array('News/archive''status=1'),
  3.     'news/:id'               => 'News/read',
  4.     'news/read/:id'          => '/news/:1',
  5. ),
系统会按定义的顺序依次匹配路由规则,一旦匹配到的话,就会定位到路由定义中的模块(支持分组)和操作方法去执行,并且后面的规则不会继续匹配。

路由定义

路由规则的定义方式如下:
  1. '路由表达式'=>'路由地址和额外参数'

路由表达式

路由表达式包括规则路由和正则路由的定义表达式,只能使用字符串。
表达式 示例
正则表达式 /^blog\/(\d+)$/
规则表达式 blog/:id
正则表达式
路由表达式支持的正则定义必须以“/”开头,否则就视为规则表达式。也就是说如果采用
  1. '#^blog\/(\d+)$#'
方式定义的正则表达式不会被支持,而会被认为是规则表达式进行解析,从而无法正确匹配。
  1. '/^new\/(\d{4})\/(\d{2})$/' => 'News/achive?year=:1&mOnth=:2',
对于正则表达式中的每个变量(即正则规则中的子模式)部分,如果需要在后面的路由地址中引用,可以采用:1、:2这样的方式,序号就是子模式的序号。
更多的关于如何定义正则表达式就不在本文的描述范畴了。

规则表达式
3.0的规则路由是从2.1的简单路由进化而来,虽然无法完美实现正则路由的功能,但是相比简单路由确实增强了不少,而且比正则路由更方便定义和容易理解。
规则表达式通常包含静态地址和动态地址,或者两种地址的结合,例如下面都属于有效的规则表达式:
  1. 'my'=>'Member/myinfo'// 静态地址路由 类似于之前版本的简单路由
  2. 'blog/:id'=>'Blog/read'// 静态地址和动态地址结合
  3. 'new/:year/:month/:day'=>'News/read'// 静态地址和动态地址结合
  4. ':user/:blog_id'=>'Blog/read',// 全动态地址
规则表达式的定义以“/”为参数分割符(无论你的URL_PATHINFO_DEPR设置是什么,请确保在定义规则表达式的时候统一使用“/”进行URL参数分割)。
每个参数中以“:”开头的参数都表示动态参数,并且会自动对应一个GET参数,例如:id表示该处匹配到的参数可以使用$_GET['id']方式获取,:year :month :day 则分别对应$_GET['year'] $_GET['month'] $_GET['day']。

数字约束
支持对变量的类型检测,但仅仅支持数字类型的约束定义,例如
  1. 'blog/:id\d'=>'Blog/read',
表示只会匹配数字参数,如果你需要更加多的变量类型检测,请使用正则表达式定义来解决。

规则排除
非数字变量支持简单的排除功能,主要是起到避免解析混淆的作用,例如:
  1. 'news/:cate^add|edit|delete'=>'News/category'
因为规则定义的局限性,恰巧我们的路由规则里面的news和实际的news模块是相同的命名,而:cate并不能自动区分当前URL里面的动态参数是实际的操作名还是路由变量,所以为了避免混淆,我们需要对路由变量cate进行一些排除以帮助我们进行更精确的路由匹配,格式^add|edit|delete表示,匹配除了add edit 和delete之外的所有字符串,我们建议更好的方式还是改进你的路由规则,避免路由规则和模块同名的情况存在,例如
  1. 'new/:cate'=>'News/category'
就可以更简单的定义路由规则了。

完全匹配
规则匹配检测的时候只是对URL从头开始匹配,只要URL地址包含了定义的路由规则就会匹配成功,如果希望完全匹配,可以使用$符号,例如:
  1. 'new/:cate$'=> 'News/category',
  1. http://serverName/index.php/new/info
会匹配成功
  1. http://serverName/index.php/new/info/2 
则不会匹配成功
如果是采用
  1. 'new/:cate'=> 'News/category',
方式定义的话,则两种方式的URL访问都可以匹配成功。

路由地址和额外参数

路由地址和额外参数表示前面的路由表达式最终需要路由到的地址并且允许隐式传入URL里面没有的一些参数,这里允许使用字符串或者数组方式定义,支持下面5种方式定义:
定义方式 定义格式
方式1:路由到内部地址(字符串) '[分组/模块/操作]?额外参数1=值1&额外参数2=值2...'
方式2:路由到内部地址(数组)参数采用字符串方式 array('[分组/模块/操作]','额外参数1=值1&额外参数2=值2...')
方式3:路由到内部地址(数组)参数采用数组方式 array('[分组/模块/操作]',array('额外参数1'=>'值1','额外参数2'=>'值2'...))
方式4:路由到外部地址(字符串)301重定向 '外部地址'
方式5:路由到外部地址(数组)可以指定重定向代码 array('外部地址','重定向代码')
如果路由地址以“/”或者“http”开头则会认为是一个重定向地址或者外部地址,例如:
  1. 'blog/:id'=>'/blog/read/id/:1'
  1. 'blog/:id'=>'blog/read/'
虽然都是路由到同一个地址,但是前者采用的是301重定向的方式路由跳转,这种方式的好处是URL可以比较随意(包括可以在URL里面传入更多的非标准格式的参数),而后者只是支持模块和操作地址。举个例子,如果我们希望avatar/123重定向到
/member/avatar/id/123_small的话,只能使用:
  1. 'avatar/:id'=>'/member/avatar/id/:1_small'
路由地址采用重定向地址的话,如果要引用动态变量,也是采用:1、:2 的方式。

采用重定向到外部地址通常对网站改版后的URL迁移过程非常有用,例如:
  1. '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'...)这样的写法,可以参考不同的定义方式选择。例如:
  1. 'blog/:id'=>'blog/read/?status=1&app_id=5',
  2. 'blog/:id'=>array('blog/read/?status=1&app_id=5'),
  3. 'blog/:id'=>array('blog/read/','status=1&app_id=5'),
  4. 'blog/:id'=>array('blog/read/',array('status'=>1,'app_id'=>5)),
上面的路由规则定义中额外参数的传值方式都是等效的。status和app_id参数都是URL里面不存在的,属于隐式传值,当然并不一定需要用到,只是在需要的时候可以使用。

实例说明

通过上面的讲解,我们了解了如何定义路由规则,下面我们来举个例子加深印象。
假设我们定义了News控制器如下(代码实现仅供参考):
  1. class NewsAction extends Action{
  2.     public function read(){
  3.         $New = M('New');
  4.         if(isset($_GET['id'])) {
  5.             // 根据id查询结果
  6.             $data = $New->find($_GET['id']);
  7.         }elseif(isset($_GET['name'])){
  8.             // 根据name查询结果
  9.             $data = $New->getByName($_GET['name']);
  10.         }
  11.         $this->data = $data;
  12.         $this->display();
  13.     }
  14.  
  15.     public function archive(){
  16.         $New = M('New');
  17.         $year   =   $_GET['year'];
  18.         $month  =   $_GET['month'];
  19.         $begin_time = strtotime($year $month "01");
  20.         $end_time = strtotime("+1 month"$begin_time);
  21.         $map['create_time'] =  array(array('gt',$begin_time),array('lt',$end_time));
  22.         $map['status']  =   1;
  23.         $list = $New->where($map)->select();
  24.         $this->list =   $list;
  25.         $this->display();
  26.     }
  27. }
定义路由规则如下:
  1. 'URL_ROUTE_RULES' => array//定义路由规则 
  2.     'new/:id\d'    => 'News/read',
  3.     'new/:name'    => 'News/read',
  4.     'new/:year\d/:month\d'  => 'News/archive',
  5. ),
然后,我们访问:
  1. http://serverName/index.php/new/8
会匹配到第一个路由规则,实际执行的效果等效于访问:
  1. http://serverName/index.php/News/read/id/8
当访问:
  1. http://serverName/index.php/new/hello
会匹配到第二个路由规则,实际执行的效果等效于访问:
  1. http://serverName/index.php/News/read/name/hello
那么如果访问:
  1. http://serverName/index.php/new/2012/03
是否会匹配第三个路由规则呢?我们期望的实际执行的效果能够等效于访问:
  1. http://serverName/index.php/News/archive/year/2012/month/03
事实上却没有,因为http://serverName/index.php/new/2012/这个URL在进行路由匹配过程中已经优先匹配到了第一个路由规则了,把2012当成id的值传入了,这种情况属于路由规则的冲突,解决办法有两个:
1、调整定义顺序
路由定义改成:
  1. 'URL_ROUTE_RULES' => array//定义路由规则
  2.     'new/:year\d/:month\d'  => 'News/archive',
  3.     'new/:id\d'                    => 'News/read',
  4.     'new/:name'    => 'News/read',
  5. ),
接下来,当我们再次访问:
  1. http://serverName/index.php/new/2012/03
的时候,达到了预期的访问效果。所以如果存在可能规则冲突的情况,尽量把规则复杂的规则定义放到前面,确保最复杂的规则可以优先匹配到。但是如果路由规则定义多了之后,仍然很容易混淆,所以需要寻找更好的解决办法。
2、利用完全匹配功能
现在我们来利用路由的完全匹配定义功能,把路由定义改成:
  1. 'URL_ROUTE_RULES' => array//定义路由规则
  2.     'new/:id\d$'                    => 'News/read',
  3.     'new/:name$'    => 'News/read',
  4.     'new/:year\d/:month\d$'  => 'News/archive',
  5. ),
在规则最后加上$符号之后,表示完整匹配当前的路由规则,就可以避免规则定义的冲突了。对于规则路由来说,简单的理解就是URL里面的参数数量或者类型约束要完全一致。
所以,如果我们访问
  1. http://serverName/index.php/new/2012/03/01
的话,是不会匹配成功任何一条路由的。
3、利用正则路由
当然,解决问题的办法总是不止一种,对于复杂的情况,我们不要忘了使用正则路由规则定义,在你找不到解决方案的时候,正则路由总能帮到你。
要实现上面的同样路由功能的话,还可以用下面的规则定义:
  1. 'URL_ROUTE_RULES' => array//定义路由规则
  2.     '/^new\/(\d+)$/'        => 'News/read?id=:1',
  3.     '/^new\/(\w+)$/'        => 'News/read?name=:1',
  4.     '/^new\/(\d{4})\/(\d{2})$/' => 'News/achive?year=:1&mOnth=:2',
  5. ),

推荐阅读
  • 致信息安全爱好者的成长指南
    本文旨在为信息安全爱好者提供一份详尽的成长指南,涵盖从学习心态调整到具体技能提升的各个方面。 ... [详细]
  • 本文详细介绍了在PHP中如何创建新文件以及如何使自定义函数在整个项目中全局可用的方法,包括最新的实践技巧。 ... [详细]
  • 本文介绍了在一卡通项目中设计加密管理方案时,证书服务器的配置步骤及其在用户权限控制中的应用。首先概述了证书服务器的基本设置,包括操作系统的选择和证书服务的安装,随后详细描述了服务器证书及客户端证书的创建过程。 ... [详细]
  • 本文详细介绍了C++中常见的容器(如列表、向量、双端队列等)及其迭代器的实现方式,通过具体代码示例展示了如何使用这些容器和迭代器。 ... [详细]
  • 探讨在数据库中存储URL时,删除尾部斜杠的安全性和潜在影响,以及如何确保URL的一致性。 ... [详细]
  • CGroups: 资源管理和控制
    CGroups(Control Groups)是Linux内核提供的一个功能,旨在限制、记录和隔离进程组使用的物理资源,如CPU、内存和I/O等。它通过精细的资源管理,支持现代容器技术如Docker的资源限制需求。 ... [详细]
  • Kafka 示例项目中 Log4j 的配置与调试
    本文详细介绍了如何在 Kafka 源码中的示例项目配置 Log4j,以确保能够正确记录日志信息,帮助开发者更好地理解和调试代码。 ... [详细]
  • Django框架的使用教程mysql数据库[三]
    Django的数据库1.在Django_test下的view.py里面model定义模型fromdjango.dbimportmodels#Createyourmodelshere ... [详细]
  • Linux 文件系统结构详解
    本文详细介绍了Linux操作系统的文件系统结构,包括其独特的树状目录体系、根目录的作用、目录与磁盘分区的关系等,并对各主要目录的功能进行了深入解析。 ... [详细]
  • 本文详细介绍了在Oracle Data Guard中配置Standby Redo Log的方法,包括其重要性和具体的配置步骤。通过本文的学习,您将能够掌握如何有效地设置Standby Redo Log以提高数据保护和系统可用性。 ... [详细]
  • 本文详细记录了《PHP与MySQL Web开发》第一章的学习心得,特别关注了PHP的基本构成元素、标记风格、编程注意事项及表单处理技巧等内容。 ... [详细]
  • mysql 分库分表策略_【数据库】分库分表策略
    关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维度较多, ... [详细]
  • 每位开发者都应该拥有一个展示自我技能与分享知识的空间——个人技术博客。本文将指导你如何使用静态网站生成器Hexo结合GitHub Pages搭建这样一个平台。 ... [详细]
  • APP数据包捕获挑战
    本文探讨了在使用Burp Suite捕获移动应用数据包时遇到的两大难题,尤其是SSL Pinning安全机制的影响,并提供了一种解决方案。 ... [详细]
  • 本文介绍了如何从给定的JSON响应中正确地提取产品标题等信息。 ... [详细]
author-avatar
挚爱—fruit
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有