一、Why Url Rewrite?
简单说2个肤浅的原因: 1、好看,2、有利于SEO
[1]. http://6zou.net/index.php?articleid=1024&mode=view&cate=tech&name=article_title
[2]. http://6zou.net/tech/title.html
这2个url用户更喜欢哪个我想不用我多说,幸运的是url的喜好跟用户一样
最终的第三点: 基于Url Rewrite 来实现 Url Router 进一步优化和简化MVC流程控制
我正是因为这一点需要
二、Apache Url Rewrite Rules
官方文档: http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_rewrite.html
下面说下我的理解
(1)、.htaccess实现url rewrite
首先我们来看一个 apache vhost 的配置
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | <VirtualHost *:80> ServerName abc.6zou.net ServerAdmin admin@6zou.net DocumentRoot "D:/www/abc.6zou.net/" <Directory "D:/www/abc.6zou.net/"> Options -Indexes FollowSymLinks AllowOverride All Order allow,deny Allow from all </Directory> ErrorLog "D:/www/abc.6zou.net/error.log" CustomLog "D:/www/abc.6zou.net/access.log" combined</VirtualHost> |
通常我们利用 Apache 的 mod_rewrite 进行 url rewrite 时,rewrite rules 写在 .htaccess 文件里
AllowOverride 的值就控制着是否加载对应的 .htaccess 文件内的配置
AllowOverride 指令仅在段有效的
AllowOverride = None 时, 该目录下的 .htaccess 文件中所有配置都被忽略。
AllowOverride = All 时, 该目录下的 .htaccess 文件中所有配置都将生效。
现在不管是虚拟主机提供商 还是 有多个网站的站长 最流行的使用方法是
在配置apache的 vhost 文件时默认 AllowOverride = All,然后在各个网站的根目录中根据各自需求配置各自的 .htaccess
(2)、最简单有效的一组重写规则
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #开启重写引擎RewriteEngine on#如果请求的 -f (文件) ! (不存在) 则跳过本条规则#否则就返回该文件RewriteCond %{REQUEST_FILENAME} !-f#如果请求的 -d (目录) ! (不存在) 则跳过本条规则#否则就返回该目录RewriteCond %{REQUEST_FILENAME} !-d#[L] 声明这是最后一条匹配规则#[QSA] url rewrite时原uri所在的query string也被传递过去#例: 1.php?a=0&b=1&c=1 重写为index.php 那么在index.php 里面 $_GET['a'] 是可以取到值的#^(.*)$ => 所有请求 # 例: 1.php?a=0 重写为 index.php 并携带query stringRewriteRule ^(.*)$ index.php [L,QSA] |
三、Url Router的实现
(1)原理
url rewrite 的本质就是一个 钩子接口 满足规则的请求 都被传递给相应的钩子函数
| 1 2 3 4 5 6 7 8 9 10 11 | |----------|| 用户请求 | 用户请求 http://xxx/login|----------| | |-> UrlRewrite把请求定向给index.php: /login -> index.php ||----------|| index.php|-> 分析: $_SERVER['REQUEST_URI'] -> "/login"|----------| | |-->login模块存在 --> 加载模块 --> 执行并返回给用户 |
(2) PHP实现简单的url router
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | //获取用户请求的uri 并按 / 切割$uri = explode( '/', $_SERVER['REQUEST_URI'] );//uri都是 / 开头的 所以 $uri[0] 为空,直接抛弃array_shift( $uri );//把uri的第一段定义为 classname$class = strtolower( array_shift( $uri ) );//把uri的第二段定义为 class的mothod$method = strtolower( array_shift( $uri ) );//把uri的第三段定义为 class的mothod$var = strtolower( array_shift( $uri ) );//当然你还可以接着取第N段,但应做基本的安全过滤//..../** 这里是我自己的规则,我个人认为最简单有效* 所有类、方法、文件名全小写* class 对应的文件为 class.php* class::method 对应 class.php 里面的 public function method(){}* 此段代码只适合PHP 5.3+版本*///如果这个class对应的文件存在则开始加载,否则返回404错误 if ( file_exists( $class . '.php' ) ){ require_once $class . '.php'; //模块的名字既类的名字, 你可以定义为其他的,我这里是为了简化 if ( class_exists( $class ) ) { //如果class存在则初始化 $clsHandler = new $class(); //如果class的方法是否存在则调用,否则返回404错误 if ( method_exists( $class, $method ) ) { //调用该方法 $clsHandler::$method(); } else if( $method!='' ) { header( 'HTTP/1.0 404 Not Found' ); exit; } }} else{ header( 'HTTP/1.0 404 Not Found' ); exit;} |
(3) 实例
.htaccess
| 1 2 3 4 | RewriteEngine onRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(.*)$ index.php [L,QSA] |
index.php
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | $uri = explode( '/', $_SERVER['REQUEST_URI'] );array_shift( $uri );$class = strtolower( array_shift( $uri ) );$method = strtolower( array_shift( $uri ) );$var = strtolower( array_shift( $uri ) );if ( file_exists( $class . '.php' ) ){ require_once $class . '.php'; if ( class_exists( $class ) ) { $clsHandler = new $class(); if ( method_exists( $class, $method ) ) { $clsHandler::$method($var); } else if( $method!='' ) { exit( "<h1>$class.php: $class::$method Not Found</h1>"); } } else { exit( "<h1>$class.php: $class Not Found</h1>" ); }}else{ switch($class) { case '': echo "<h1>this is default page!</h1>"; break; default: exit( "<h1>$class.php Not Found</h1>"); }} |
test.php
| 1 2 3 4 5 6 7 8 9 10 11 12 | class test{ public function test() { echo "<h1>class inited</h1>"; } public function hello($name='tester') { echo strlen($name)>0 ? "<h1>hello, $name !</h1>" : "<h1>hello, world !</h1>"; }} |
测试url:
http://xxx/ 提示 默认页
http://xxx/asdasd 提示 asdasd.php 文件不存在
http://xxx/test 提示 test类 初始化成功
http://xxx/test/hello 调用test类 hello方法 传递参数为空 显示 hello,world
http://xxx/test/hello/jason 调用test类 hello方法 传递参数为jason 显示 hello,jason
没有评论:
发表评论