Tag Archives: mvc

PHP Routing Part 2:Router

上次讲完Request之后,一直在研究Router(路由器)部分的东东。看过PHP、Python等其他框架内实现的路由器。

路由一共分为两个功能:
1、标准路由器, 这里会把链接上的uri根据配置文件分析后,得到Controller和Action。
2、跳转路由和代理路由, 也就是redirect和proxy。同样和1一样,需要写入uri的配置规则,只不过是会根据配置跳转链接,并且赋予301或者302状态码。

在PHP5.4开始的版本,基本上都是使用PHP-FPM模式,当用户访问一个页面,webserver(比如Nginx),会将请求传给php,此时PHP会进行初始化,这时候会将一些变量常量写入到了$_SERVER中。就如上面所说,每次请求都是一个完整的链接,我们分割为3个部分:基本地址,路径,请求参数。

  1. 基本地址: 也就是你的基础路径,可以是一个域名也可以是一个带有path的地址链接。这些将会忽略不计。
  2. 路径: 这里的路径就是你所需的有效路径,比如 /users/show, /video/categories, /news/content/2014-03-02/1313.html
  3. 请求参数: 这里包含了_COOKIE,_GET,_POST以及php://input

一般情况下,我们需要的是路径这一部分,一般可以通过REQUEST_URI获得。这些都是在Request类中的,还没开始进入的Router类中哦,接下来,是路径解析。首先来说说一说标准路由,首先你要对你的期望制定一些路由规则。在路由器中以:开头的,紧跟着的就是变量名称,例如 /:controller/:action 。那么所有在:controller位置的变量都会当作controller名来处理。一般来说我们链接有以下几种需求:
1. 根目录形式 / 需要定义controller和action,指定首页所显示的内容
2. /:controller/:action/* 最常见的链接模型
3. /api/:contoller/:action 链接是有一个prefix的。
4. /news/content/:date/:id.html 一种伪静态的链接。 像这种:date :id是一种自定参数,我们可以在路由配置后面加上 date 的匹配规则, [0-9]{4}-[0-9]{2}-[0-9]{2}。

上面4个例子都是我们常看到的,这些配置有了,还不能正常使用。我们需要通过将这些配置转换成程序可读的正则表达式。首先我们将:controller分割出来,controller将会用于匹配后的key名。这时候正则表达式需要利用标签格式(?exp),这个模式在匹配成功后,返回的结果中,将会以你定的name来做为key,就不需要通过数据索引来一一访问。在匹配成功之后,有了controller和action,这时候Dispatcher就会正式调用。

至此,路由解析已经完成,所有的处理已经全部交给了Controller。Controller处理完结果之后,将会输出给Response,显示给用户的面前。

PHP Routing Part 1:Request


php开发中,如果不是mvc模式,在规划路径的时候通常使用目录结构,或者在根目录下建立有意义的php文件。
例如:

http://www.example.com/user/login.php
http://www.example.com/user.php?actinon=login

但使用MVC模式写站点的的时候,由于php的特性,必须要一个router管理及派发。在谈router之前,首先从request开始谈起.

Request, 请求。用户输入网址按回车,php收到的客户端数据就是Request。我们通过分析request,知道当前用户需要访问哪个页面,哪个动作,哪些数据等等信息。通常情况下request只包含header,但在put状态同时还会包含body部分。

一、 header

在求请求头中,会包含用户浏览器传递到服务端的各种信息,如果用户ip地址、正在访问的url、userAgent、cookie等等参数。可以通过firefox的firebug或者Chrome的调试工具, 点击network。可以查看到当前页的Request信息。如下图所示:
php_request_header_info

header在php中如果访问到?可以从$_SERVER数组中读取HTTP_{$key}的信息。

二、 body

body只有在两种请求状态下会出现:put、delete。并且不是表单提交状态。这一点非常重要,如果是表单提交,那么可以从$_POST中读取。下面会具体讲到。
如何读取?非常简单,直接通过php://input就能读取到数据流。

$fh = fopen("php://input", "r");
$content = stream_get_contents($fh);
fclose($fh);

这种主要出现在resetFul服务中,客户端直接向服务端put/delete json或者xml格式的数据。

三. $_GET

在这里插入一个题外话,在php中一个特殊的数据$_REQUEST,它同时包含了$_GET和_$POST中的数据,如果直接通过$_REQUEST数据是不安全的,此时你没法分清用户传来的数据是post还是get,极大的降低了服务端的安全性。所以不推荐使用$_REQUEST代替$_GET和$_POST读取用户传递的数据信息。
在php.ini中开启magic_quotes_gpc,需要在分析前stripslash。$_GET数据来自于链接?后面的一串字符。以xxx[=yy]形式出现,中间使用‘&’符号相连接。xxx为key,yy为value。在php中就展现成一个数据形式。

array(
'xxx' => 'yy',//xxx=yy
'aaa' => '',//aa
);

在MVC中特别需要注意。一般情况下,一个站点会将域名‘/’后面的字符串全部传给index.php。那么$_GET中就只包含了这个信息。这里要注意一点,这时候链接中带有?后面的字符串,紧紧是字符串,它不会被php自动转化成$_GET中的项。我们只需要从字符串中提取‘?’后面的数据 /user/login?returnurl=http://www.example.com。然后通过parse_str函数分析,然后与$_GET进行合并,

if (ini_get('magic_quotes_gpc') === '1') {
	$query = stripslashes_deep($_GET);
} else {
	$query = $_GET;
}
if (strpos($url, '?') !== false) {
	list(, $querystr) = explode('?', $url);
	parse_str($querystr, $queryArgs);
	$query += $queryArgs;
}

四. $_POST

$_POST只用通过表单,并且表单属性中的method设为post。

五. $_FILES

文件上传处理。文件上传通过页面上表单,并且form属性需要设置encrypt=multipart/form-data,同时form中需要包含一个input type="file",php $_FILES中才会有数据。上传后的数据存储在/tmp(linux)或者/APPDATA/temp(windows)目录下,这个文件在15分钟后会被系统自动回收。

在下一篇会讲到Router,分析url地址,根据设定的规则,自动加载controller文件,控制response,在通过view渲染网页向客户端输出网页。