#####Yii框架的路由以安全方面的研究
- 基础核心类共有
69
个 - 其中抽象类共有
10
个 - 接口类共有
15
个 - 其余全为动态加载 详情见: 动态加载原理
- 全部类共有
208
个
.
├── base // 底层核心类库
├── caching // 所有的缓冲存放的位置
├── cli // 项目命令行生成脚本
├── collections // PHP语言构造的数据存储单元.队列,栈,哈希等等......
├── console // Yii 框架控制台相关PHP代码.
├── db // 数据库相关操作类库
├── gii // 代码生成器 (脚手架, 可以生成模型, 控制器, 视图等代码)
├── i18n // 国际化(就是让网站实现多语言访问)
├── logging // 日志功能相关类库
├── messages // 存放的是与国际化相关的语言包
├── test // 用于单元测试的文件夹
├── utils // 单元测试相关类库
├── validators // 存放着各种自动验证的相关类库
├── vendors // 第三方文档 / 资料
├── views // 包含了Yii 框架自带的错误页面,日志,配置文件的多语言视图.
├── web // Yii 所有与开发相关的文件
└── zii // 用于前端开发的各种插件
1.1、 加载 YiiBase.php
,安装 autoload
方法;加载用户的配置文件;
1.2、 创建 WebApp
应用,并对 App
进行初始化,加载部分组件,最后执行 WebApp
2.1、 加载 request 组
件,加载 Url 管理组件
,获得路由信息 route=ControllerId/ActionId
2.2、 创建出控制器实例,并运行控制器
3.1、 根据路由创建出 Action
3.2、 根据配置,创建出该 Action
的 Filter
;
3.3、 执行 Filter
和 Action
4.1、 渲染部分视图和渲染布局视图
4.2、 渲染注册的 javascript 和 css
Web开发中不可避免的要使用到URL。用得最多的,就是生成一个指向应用中其他某个页面的URL了。
开发者需要一个简洁的、集中的、统一的方法来完成这一过程。
而开发中最常用的架构就为`MVC`说到`MVC架构`, 就一定离不开`Route`这个概念;
在之前访问一个网站的时候常常会出现以QueryString
方式出现的url
访问方式 ;
比如: "http://www.xxxxx.com/index.php?m=index&c=index&a=login"
;
这种方式是采用QueryString
方式去访问后端的指定模块&控制器&方法,这种方法虽然操作简单但是参数多了就比较臃肿最主要的是不利于SEO
. 为了解决这种访问模式又有童鞋想出了美化URL
的方法, 就是 Path 参数传递
;
这种方法不但美观并且利于SEO优化
(和伪静态异曲同工);
如: "http://www.xxxx.com/index.php/index/index/login"
这种URL
的访问得到的结果和上面是一模一样的.
到这里就有一个问题了原来QueryString
方式访问可以往后台传参数现在的Path
方式如何往后台传参数呢?
其实聪明的同学应该已经明白了, 那是不是能再后面加上QueryString
方式的参数呢?
如: "index.php/index/index/login?admin=admin&xxx=xxx"
这样写其实是可以的,但是如果这么写那么Path
方式的路由也就没有什么意义了.
按照之前的规律, 咱们可以这么写 "index.php/index/index/login/admin/admin/xxx/xxx"
这么写是与上面的QueryString
方式的传参是完全等价的, 至于这里的如果有想深入的同学可以去研究下http协议规范
.
这里附上3个网站
那么上面的那些访问模式是怎么实现的呢? 首先我们知道现在的框架绝大部分都为单入口模式, 这种单入口模式的程序相对于多入口的程序有什么好处呢? 其实就是为了方便管理与控制(单入口模式配合路由那真是天造地设的一对呀! ) .
这里咱们回归到上面提到的3个参数, 把这三个参数代表的意思搞明白, 才能方便咱们继续向下学习.
+ m -> module -> 模块
+ c -> controller -> 控制器
+ a -> action -> 方法
在这里我简单的实现了一个框架传送门
上面的流程图, 简单的展示了框架是如何分配控制器以及方法的.
如果看懂了上面的逻辑图, 那么对咱们下面学习如何处理Path参数的学习,会更加快速.
如上图所示的无论用户传入的是怎么样美化过的URL最终都需要被转化为$_GET的参数.
大家都知道, $_GET这个全局变量里面的参数实际是PHP帮咱们进行QueryString
的拆分.
并且PHP只支持QueryString
的自动处理.
如果大家直接以"http://www.xxxxx.com/index.php/admin/admin/index/id/1231" 这种方式访问.
你去$_GET || $_POST || $_REQUEST 这几个全局变量里面是都无法获取到index.php往后的URI参数的.
那么这里该怎么获取呢?????????
别担心, 世界上最好的语言已经为我们准备好解决方案了.
<?php
var_dump($_SERVER['PATH_INFO']);
// 直接打印这个函数, 将获得以下结果.
string(26) "/admin/admin/index/id/1231"
大家是不是知道应该怎么做了? 下面这个函数就展了如何将Path参数转换为QueryString 存放到GET里面
//PathInfo 路由规则
function PathInfo()
{
$_GET['m'] = empty($_GET['m']) ? 'index' : $_GET['m'];
$_GET['c'] = empty($_GET['c']) ? 'index' : $_GET['c'];
!empty($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] = $_SERVER['PATH_INFO'];
if (!empty($_SERVER['PATH_INFO'])) {
$path = $_SERVER['PATH_INFO'];
$get = explode('/', $path);
unset($get[0]);
foreach ($get as $key => $value) {
if ($key > 0) {
if (count($get) == 1) {
$_GET['c'] = $get[1];
} else if (count($get) == 2) {
$_GET['c'] = $get[1];
$_GET['a'] = $get[2];
} else if (count($get) > 2) {
$_GET['m'] = $get[1];
$_GET['c'] = $get[2];
$_GET['a'] = $get[3];
}
}
if (count($get) > 4) {
$param = array_slice($get, 3);
$param = array_filter($param);
for ($i = 0; $i < count($param); $i += 2) {
if ($param[$i] != 'm' && $param[$i] != 'a' && $param[$i] != 'c' && !empty($param[$i + 1])) {
$_GET[$param[$i]] = $param[$i + 1];
}
}
}
}
}
}
到这里核心原理已经讲解的差不多了, 后面其他的一些功能比如rules的控制, 自定义url美化规则......等等都可以在这个函数的基础上继续添加只需要最后保证参数m与参数c与参数a最终能获得正确的值就可以. 咱们接下来看一下Yii框架为咱们提供了那些Route功能.
'urlManager'=>array(
'urlFormat'=>'path', // 设置路由访问模式
'urlSuffix' => '.html', // 伪静态后缀
'showScriptName' => false, // 去掉 index.php (True | False)
'rules'=>array( // URL 规则定义 非常的强大 可以随心所欲的自定义自己的URL规则
'post/<id:\d+>/<title:.*?>'=>'post/view',
'jun/<id:\d+>/<title:.*?>'=>'post/jun',
'haha/haha' => [
'post/jun',
'urlSuffix' => '.html', // 仅对生成url时有效
'defaultParams' => ['a'=>'v'], // 默认注入参数
'caseSensitive' => false, // 是否区分大小写
'verb' => 'GET' // 设置当前规则适用的场景 如GET POST PUT DELETE等等......
],
'posts/<tag:.*?>'=>'post/index',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
),
index.php?r=/post/jun/jun
index.php/post/jun/jun
可以看到上面存在了很多配置项, 下面咱们就一一探究每个配置项对应的功能是什么.
如果想切换路由模式很简单只需要在配置项 urlFormat
这一项中将对应的 value 更改成 get || path 就可以了.
rules 是 Yii框架中URL管理器中非常强大的一个模块, 它提供了非常强大便捷URL 管理功能 ,下面咱么就一起来看一下它的使用规则. 比如下面的这个配置能实现的效果是什么.
'urlManager'=>array(
...
'rules'=>array(
'post/<id:\d+>/<title:.*?>'=>'post/view',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
...
),
),
),
),
在rules 这个key 中它对应这一个数组, 这个数组也是一个 key => value 的结构. 它可以定义多个规则, 只需要像正常数组一样往下写便可,
key => URL规则
value => 指向的控制器
在key
中可以这么写 'xxx/xxx/xxx' || '<xx:\d>/xxxx/xxxx'
在value
中可以这么 'xxx/xxx/xxx' || '<xx>/xxx/xxx'
上面的两个实例可以组合成下面两个正常规则
'rules' => array(
'index/index/index' =>'admin/index/index', // 将 index/index/index 的用户访问 定向到 admin/index/index
'<model:\w+>/index/index' =>'<model>/post/view', // 这里面的<model> 会被替换成 <model: \w> 里面正则匹配到的内容.
...
),
那么如何生成URL呢?很简单,在Yii框架中生成URL需要注意两点。
- 在控制器中生成URL
- 在layout中生成URL
$url=$this->createUrl($route,$params);
$this指的是控制器实例; $route指定请求的route 的要求;$params 列出了附加在网址中的GET参数。
默认情况下,URL以get格式使用createUrl 创建。例如,提供$route='post/read'和$params=array('test'=>123) ,我们将获得以下网址:
/index.php?r=post/read&test=123
参数以一系列Name=Value通过符号串联起来出现在请求字符串,r参数指的是请求的route 。这种URL格式用户友好性不是很好,因为它需要一些非字字符。
我们可以使上述网址看起来更简洁,更不言自明,通过采用所谓的'path格式,省去查询字符串和把GET参数加到路径信息,作为网址的一部分:
/index.php/post/read/id/100
要更改URL格式,我们应该配置urlManager应用元件,以便createUrl可以自动切换到新格式和应用程序可以正确理解新的网址:
array(
......
'components'=>array(
......
'urlManager'=>array(
'urlFormat'=>'path',
),
),
);
请注意,我们不需要指定的urlManager元件的类,因为它在CWebApplication预声明为CUrlManager。
createurl方法所产生的是一个相对地址。为了得到一个绝对的url ,我们可以用前缀yii"> 提示:此网址通过createurl方法所产生的是一个相对地址。为了得到一个绝对的url ,我们可以用前缀yii: :app()->hostInfo ,或调用createAbsoluteUrl 。 #######2.User-friendly URLs(用户友好的URL) 当用path格式URL,我们可以指定某些URL规则使我们的网址更用户友好性。例如,我们可以产生一个短短的URL/post/100 ,而不是冗长/index.php/post/read/id/100。网址创建和解析都是通过CUrlManager指定网址规则。
要指定的URL规则,我们必须设定urlManager 应用元件的属性rules:
array(
......
'components'=>array(
......
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'pattern1'=>'route1',
'pattern2'=>'route2',
'pattern3'=>'route3',
),
),
),
);
这里大家应该都懂怎么填了吧?