Skip to content

dsphper/YiiStudy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

82 Commits
 
 
 
 
 
 

Repository files navigation

YiiStudy

#####Yii框架的路由以安全方面的研究

  • 基础核心类共有69
  • 其中抽象类共有10
  • 接口类共有15
  • 其余全为动态加载 详情见: 动态加载原理
  • 全部类共有 208

Yii框架目录结构

.
├── base // 底层核心类库
├── caching // 所有的缓冲存放的位置
├── cli // 项目命令行生成脚本
├── collections // PHP语言构造的数据存储单元.队列,栈,哈希等等......
├── console // Yii 框架控制台相关PHP代码.
├── db // 数据库相关操作类库
├── gii // 代码生成器 (脚手架, 可以生成模型, 控制器, 视图等代码)
├── i18n // 国际化(就是让网站实现多语言访问)
├── logging // 日志功能相关类库
├── messages // 存放的是与国际化相关的语言包
├── test // 用于单元测试的文件夹
├── utils // 单元测试相关类库
├── validators // 存放着各种自动验证的相关类库
├── vendors // 第三方文档 / 资料
├── views // 包含了Yii 框架自带的错误页面,日志,配置文件的多语言视图.
├── web // Yii 所有与开发相关的文件
└── zii // 用于前端开发的各种插件 

框架加载与运行流程

Step1:WebApp 初始化与运行

1.1、 加载 YiiBase.php,安装 autoload 方法;加载用户的配置文件;
1.2、 创建 WebApp 应用,并对 App 进行初始化,加载部分组件,最后执行 WebApp

Step2:控制器初始化与运行

2.1、 加载 request 组件,加载 Url 管理组件,获得路由信息 route=ControllerId/ActionId
2.2、 创建出控制器实例,并运行控制器

Step3:控制器初始化与运行

3.1、 根据路由创建出 Action
3.2、 根据配置,创建出该 ActionFilter;
3.3、 执行 FilterAction

Step4:渲染阶段

4.1、 渲染部分视图和渲染布局视图
4.2、 渲染注册的 javascript 和 css

Yii原理详解

路由原理

概念讲述
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功能.

Yii框架Url 配置项
'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>',
	),
),
GET 方式
index.php?r=/post/jun/jun
Path 方式
index.php/post/jun/jun

可以看到上面存在了很多配置项, 下面咱们就一一探究每个配置项对应的功能是什么. 如果想切换路由模式很简单只需要在配置项 urlFormat 这一项中将对应的 value 更改成 get || path 就可以了.

rules 详解

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

那么如何生成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',
            ),
        ),
    ),
);

这里大家应该都懂怎么填了吧?

动态按需加载

About

📚 Yii框架研究心得

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages