介绍和配置:
以数据库后台驱动的动态内容的网站,经常会遇到这些的问题:
- 当在浏览器的地址栏输入一个无效的参数时,会出现数据库的错误提示,这是一个安全的隐患
- 搜索引擎无法收录你的所有网页
- 网页的链接地址是一系列的参数,对浏览用户和搜索引擎都不易理解
这 些问题都可以通过Apache服务器的一个基本的模块mod_rewrite来解决,默认的安装的Apache就会装有这个模块。要启用这个模 块,打开 httpd.conf文件,察看下面的两行是否被屏蔽,第一行是载入mod_rewrite模块,第二行是启用这个模块。
LoadModule rewrite_module modules/mod_rewrite.so
AddModule mod_rewrite.cmod_rewrite这个模块是如何工作的呢?
mod_rewrite截获符合特定条件的URL,并按照设定的规则将它们改写成需要的URL。
比如,可以将 http://www.mysite.com/product.php?pid=123312 这样的URL改写成
http://www.mysite.com/product-123312.html 这样的静态URL,或者是更具体的 http://www.mysite.com/product/thinkpad-t42.html
重写的规则重写的规则的表达式:
RewriteRule 模式 替换 [选项]
RewriteRule 是一个简单的命令告诉mod_rewrite这个模块如何去重写,关键的地方在于可以在模式和替换中使用正则表达式来匹配相应的字符,正则表达式的广泛的灵活性能将动态的URL转换成各式各样的符合要求的静态URL。看看这个重写规则:
RewriteRule /products/([0-9]+)
/fancy/products.php?id=$1当你在浏览器地址栏输入 http://www.mysite.com/product/123 时,这个地址被重写为 http://www.mysite.com/fancy/product.php?id=123
这样,访问者就无法知道你的程序真正放在那个目录,程序的真正名字是什么,这也提高了网站的安全系数;这样的URL也去掉了?=这些字符,易于搜索引擎的机器人爬行你的网站。
通过正则表达式,可以写出更复杂的重写规则:
RewriteRule ^/products$ /content.php
RewriteRule ^/products/([0-9]+)$ /content.php?id=$1
RewriteRule ^/products/([0-9]+),([ad]*),([0-9]{0,3}),([0-9]*),([0-9]*$)重写规则的选项有
- ‘forbidden’ 或 ‘f’ - 403 禁止
- ‘gone’ 或 ‘g’ - 410 gone
- ‘nocase’ 或 ‘NC’ - 大小写敏感
- ‘next’/N’ - 回到第一条规则
- ’skip=N’ 或 ‘S=N’ - 跳过下面的N条规则
流程控制
mod_rewrite是按照从上到下的顺序执行重写的规则,如果URL匹配了第一条规则,则按照第一条规则进行重写,如果不匹配,就执行第二条规则,直到最后。通过流程控制,可以定义在不同情况下采用不同的重写规则。格式是:
RewriteCond 测试条件 Condition
这些测试条件有:
- HTTP变量: HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_FORWARDED, HTTP_HOST, HTTP_PROXY_CONNECTION, HTTP_ACCEPT
- 连 结和请求的变量: REMOTE_ADDR, REMOTE_HOST, REMOTE_USER, REMOTE_IDENT, REQUEST_METHOD, SCRIPT_FILENAME, PATH_INFO, QUERY_STRING, AUTH_TYPE
- 服务器内部变量: DOCUMENT_ROOT, SERVER_ADMIN, SERVER_NAME, SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL, SERVER_SOFTWARE
- 系统变量: TIME_YEAR, TIME_MON, TIME_DAY, TIME_HOUR, TIME_MIN, TIME_SEC, TIME_WDAY, TIME
- mod_rewrite特殊值: API_VERSION, THE_REQUEST, REQUEST_URI,
例如,利用mod_rewrite可以禁止从其他的网站链接到你的图片:
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://localhost/.*$ [OR,NC]
RewriteCond %{HTTP_REFERER} !^http://mysite.com/.*$ [OR,NC]
RewriteCond %{HTTP_REFERER} !^http://www.mysite.com/.*$ [OR,NC]
RewriteRule .*\.(gif|GIF|jpg|JPG)$ http://mysite/images/bad.gif [L,R]
配置apache mod_rewrite最简单的方法:
在网上找了很多篇关于配置apache mod_rewrite的文章,发觉这篇最有用,大家需要的可参考一下。
1,通过php提供的phpinfo()函数查看环境配置,通过Ctrl+F查找到“Loaded Modules”,其中列出了所有apache2handler已经开启的模块,如果里面包括“mod_rewrite”,则已经支持,不再需要继续设置。
如 果没有开启“mod_rewrite”,则打开目录 您的apache安装目录“/apache/conf/” 下的 httpd.conf 文件,通过Ctrl+F查找到“LoadModule rewrite_module”,将前面的”#”号删除即可。如果没有查找到,则到“LoadModule” 区域,在最后一行加入“LoadModule rewrite_module modules/mod_rewrite.so”(必选独占一行),然后重启apache服务器即可。
2, 让apache服务器支持”.htaccess”
如 何让自己的本地APACHE服务器支持”.htaccess”呢?其实只要简单修 改一下apache的httpd.conf设置就可以让APACHE支 持.htaccess了。打开httpd.conf文件(在那里? APACHE目录的CONF目录里面),用文本编辑器打开后,查找
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
改为
<Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
就可以了
3,建立 “.htaccess” 文件
如果是在windows平台下,刚开始还真不知道怎么建立”.htaccess”文件,因为这个文件实际上没有文件名,仅仅只有扩展名,通过普通方式是无法建立这个文件的,别着急,马上告诉你三种方法:
三 种方法都是先建立一个htaccess.txt的文本文件(当然,这个文本文件的名字你可以随便取),然后有三种方式给这个文件重命名:(1)用记事本 打开,点击文件–另存为,在文件名窗口输入”.htaccess”,注意是整个绿色部分,也就是包含英文引号,然后点击保存就行了。(2)进入cmd命令 窗口,通过cd切换当刚建立htaccess.txt文件的文件夹,然后输入命令:rename htaccess.txt .htaccess ,然后点击键盘Enter键即可。(3)通过ftp连接htaccess.txt所在文件夹,通过ftp软件重命名。
那么我们须要建立几个 “.htaccess” 文件,里面又输入什么内容呢?基本的原则是这样,根目录必须有一个,用于重定向(URl重写)所有的请求都会转到到index.php(交给前端控制 器);”./application”文件夹下须要一个,用于拒绝所有针对该文件夹内容的直接访问(比如 http://localhost/application/models/User.php),这样做是因为所有访问请求必选通过前端控制器来分配访 问,其次为了安全;“./library”文件夹下的“.htaccess”同前;”./public”文件夹下必选建一个,因为这个文件夹的文件全部是 供前端直接访问的,因此须要撤销URl重写。以下是4个“./htaccess”文件的内容:
./.htaccess
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
./application/.htaccess
deny from all
./library/.htaccess
deny from all
./public
RewriteEngine off
实际上,apache的url重写功能也可以直接在httpd.conf文件中进行设置,这里就不具体讲了,网上相关的教程也很多。
Apache的RewriteRule规则详细介绍:
RewriteRule适用的标志符
一条RewriteRule指令,定义一条重写规则,规则间的顺序非常重要。对Apache1.2及以后的版本,模板(pattern)是一个POSIX正则式,用以匹配当前的URL。当前的URL不一定是用记最初提交的URL,
因为可能用一些规则在此规则前已经对URL进行了处理。
对mod_rewrite来说,!是个合法的模板前缀,表示“非”的意思,这对描述“不满足某种匹配条件”的情况非常方便,或用作最后一条默认规则。当使用!时,不能在模板中有分组的通配符,也不
能做后向引用。
当匹配成功后,Substitution会被用来替换相应的匹配,它除了可以是普通的字符串以外,还可以包括:
$N,引用RewriteRule模板中匹配的相关字串,N表示序号,N=0..9
%N,引用最后一个RewriteCond模板中匹配的数据,N表示序号
%,服务器变量
${mapname:key|default},映射函数调用
这些特殊内容的扩展,按上述顺序进行。
一个URL的全部相关部分都会被Substitution替换,而且这个替换过程会一直持续到所有的规则都被执行完,除非明确地用L标志中断处理过程。
当susbstitution有”-”前缀时,表示不进行替换,只做匹配检查。
利用RewriteRule,可定义含有请求串(Query String)的URL,此时只需在Sustitution中加入一个?,表示此后的内容放入QUERY_STRING变量中。如果要清空一个QUERY_STRING变量,只需要以?结束
Substitution串即可。
如果给一个Substitution增加一个http://thishost[:port]的前缀,则mod_rewrite会自动将此前缀去掉。因此,利用http://thisthost做一个无条件的重定向到自己,将难以奏效。要实现这种效果
,必须使用R标志。
Flags是可选参数,当有多个标志同时出现时,彼此间以逗号分隔。
\'redirect|R [=code]\' (强制重定向)
给当前的URI增加前缀http://thishost[:thisport]/, 从而生成一个新的URL,强制生成一个外部重定向(external redirection,指生的URL发送到客户端,由客户端再次以新的URL发出请求,虽然
新URL仍指向当前的服务器). 如果没有指定的code值,则HTTP应答以状态值302 (MOVED TEMPORARILY),如果想使用300-400(不含400)间的其它值可以通过在code的位置以相应的数字指定,也可以用标
志名指定: temp (默认值), permanent, seeother.
注意,当使用这个标志时,要确实substitution是个合法的URL,这个标志只是在URL前增加http://thishost[:thisport]/前缀而已,重写操作会继续进行。如果要立即将新URL重定向,用L标志来中
重写流程。
\'forbidden|F\' (强制禁止访问URL所指的资源)
立即返回状态值403 (FORBIDDEN)的应答包。将这个标志与合适的RewriteConds 联合使用,可以阻断访问某些URL。
\'gone|G\' (强制返回URL所指资源为不存在(gone))
立即返回状态值410 (GONE)的应答包。用这个标志来标记URL所指的资源永久消失了.
# \'proxy|P\' (强制将当前URL送往代理模块(proxy module))
这个标志,强制将substitution当作一个发向代理模块的请求,并立即将共送往代理模块。因此,必须确保substitution串是一个合法的URI (如, 典型的情况是以http://hostname开头),否则会从
代理模块得到一个错误. 这个标志,是ProxyPass指令的一个更强劲的实现,将远程请求(remote stuff)映射到本地服务器的名字空间(namespace)中来。
注意,使用这个功能必须确保代理模块已经编译到Apache 服务器程序中了. 可以用“httpd -l ”命令,来检查输出中是否含有mod_proxy.c来确认一下。如果没有,而又需要使用这个功能,则需要
重新编译``httpd\'\'程序并使用mod_proxy有效。
\'last|L\' (最后一条规则)
中止重写流程,不再对当前URL施加更多的重写规则。这相当于perl的last命令或C的break命令。
\'next|N\' (下一轮)
重新从第一条重写规则开始执行重写过程,新开的过程中的URL不应当与最初的URL相同。 这相当于Perl的next命令或C的continue命令. 千万小心不要产生死循环。
# \'chain|C\' (将当前的规则与其后续规则綑绑(chained))
当规则匹配时,处理过程与没有綑绑一样;如果规则不匹配,则綑绑在一起的后续规则也不在检查和执行。
\'type|T=MIME-type\' (强制MIME类型)
强制将目标文件的MIME-type为某MIME类型。例如,这可用来模仿mod_alias模块对某目录的 script Alias指定,通过强制将该目录下的所有文件的类型改为 “application/x-httpd-cgi”.
\'nosubreq|NS\' (used only if no internal sub-request )
这个标志强制重写引擎跳过为内部sub-request的重写规则.例如,当mod_include试图找到某一目录下的默认文件时 (index.xxx),sub-requests 会在Apache内部发生. Sub-requests并非总是有用
的,在某些情况下如果整个规则集施加到它上面,会产生错误。利用这个标志可排除执行一些规则。
\'nocase|NC\' (模板不区分大小写)
这个标志会使得模板匹配当前URL时忽略大小写的差别。
\'qsappend|QSA\' (追加请求串(query string))
这个标志,强制重写引擎为Substitution的请求串追加一部分串,则不是替换掉原来的。借助这个标志,可以使用一个重写规则给请求串增加更多的数据。
\'noescape|NE\' (不对输出结果中的特殊字符进行转义处理)
通常情况下,mod_write的输出结果中,特殊字符(如\'%\', \'$\', \';\', 等)会转义为它们的16进制形式(如分别为\'%25\', \'%24\', and \'%3B\')。这个标志会禁止mod_rewrite对输出结果
进行此类操作。 这个标志只能在 Apache 1.3.20及以后的版本中使用。
\'passthrough|PT\' (通过下一个处理器)
这个标志强制重写引擎用filename字段的值来替换内部request_rec数据结构中uri字段的值。. 使用这个标志,可以使后续的其它URI-to-filename转换器的Alias、 script Alias、Redirect等指
令,也能正常处理RewriteRule指令的输出结果。用一个小例子来说明它的语义:如果要用mod_rewrite的重写引擎将/abc转换为/def,然后用mod_alas将/def重写为ghi,则要:
RewriteRule ^/abc(.*) /def$1 [PT]
Alias /def /ghi
如果PT标志被忽略,则mod_rewrite也能很好完成工作,如果., 将 uri=/abc/... 转换为filename=/def/... ,完全符合一个URI-to-filename转换器的动作。接下来 mod_alias 试图做 URI-to-filename
转换时就会出问题。
注意:如果要混合都含有URL-to-filename转换器的不同的模块的指令,必须用这个标志。最典型的例子是mod_alias和mod_rewrite的使用。
\'skip|S=num\' (跳过后面的num个规则)
当前规则匹配时,强制重写引擎跳过后续的num个规则。用这个可以来模仿if-then-else结构:then子句的最后一条rule的标志是skip=N,而N是else子句的规则条数。
\'env|E=VAR:VAL\' (设置环境变量)
设置名为VAR的环境变量的值为VAL,其中VAL中可以含有正则式的后向引用($N或%N)。这个标志可以使用多次,以设置多个环境变量。这儿设置的变量,可以在多种情况下被引用,如在XSSI或CGI中。
另外,也可以在RewriteCond模板中以%{ENV:VAR}的形式被引用。
rewrite时服务器变量:
HTTP headers:HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_HOST, HTTP_ACCEPT
connection & request: REMOTE_ADDR, QUERY_STRING
server internals: DOCUMENT_ROOT, SERVER_PORT, SERVER_PROTOCOL
system stuff: TIME_YEAR, TIME_MON, TIME_DAY
Rewrite规则表达式的说明:
. 匹配任何单字符
[chars] 匹配字符串:chars
[^chars] 不匹配字符串:chars
text1|text2 可选择的字符串:text1或text2
? 匹配0到1个字符
* 匹配0到多个字符
+ 匹配1到多个字符
^ 字符串开始标志
$ 字符串结束标志
\n 转义符标志
反向引用 $N 用于 RewriteRule 中匹配的变量调用(0 <= N <= 9)
反向引用 %N 用于 RewriteCond 中最后一个匹配的变量调用(1 <= N <= 9)
RewriteCond标志符
RewriteCond 语法中的 TestStrng 为要被检查的内容, CondPattern 是进行匹配的规则, 它是一个兼容Perl风格的正则表达式和一些其他的特有字符属性. 这里介绍一下.
第一个: ! (感叹号) 表示否的意思. 比如一个条件: 判断访问此页面的上一页URL是否包含 sex 字符的话可以用这样: RewriteCond %{HTTP_REFERER} !(sex)
第二个: < 就是小于的意思, TestString < CondPattern.
第三个: > 就是大于于的意思, TestString < CondPattern.
第四个: = 相等的意思. <, >, = 三个和通常程序语言使用的 <, >, = 功能类似.
第五个: -d 是否是一个目录. 判断TestString是否不是一个目录可以这样: !-d
第六个: -f 是否是一个文件. 判断TestString是否不是一个文件可以这样: !-f
第七个: -s 是否是一个正常的有大小的文件. 判断TestString是否不是一个正常的有大小的文件可以这样: !-s
第八个: -l 是否是一个快捷方式文件. 判断TestString是否不是一个快捷方式文件可以这样: !-l
第九个: -x 是否是一个文件并且又执行权限. 判断TestString是否不是一个文件并且又执行权限可以这样: !-x
第十个: -F 检查TestString是否是一个合法的文件,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的性
能。
第十一个: -U 检查TestString是否是一个合法的URL,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的
性能.
另外: RewriteCond 指令后面可带 Flag, 现在只要2个可用, 一个是 NC|nocase, 不区分大小写的意思. 一个是 OR|ornext 表示连接下一个条件的意思.
RewriteCond 实际需要使用情况比如要判断一个条件成真的时候才执行相关的重写操作. 紧接着它下面的 RewriteRule 总是在RewriteCond 条件判断为真的时候才被执行.
看下面的一个例子:
#开启服务器重写模式
RewriteEngine on
#来自 www.test.cn 的连接访问本站时都只能访问 test.php 这页.
RewriteCond %{HTTP_REFERER} (www.test.cn)
RewriteRule (.*)$ test.php
#来自 www.test.com 的连接访问本站时都只能访问 newTest.php 这页.
RewriteCond %{HTTP_REFERER} (www.test.com)
RewriteRule (.*)$ newTest.php
OK, RewriteCond 就介绍到这里了. 其实很简单. 就想程序里的 if() 这样的效果. 下篇聊一下 RewriteRule
实际操作
例子:
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ^MSIE [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^Opera [NC]
RewriteRule ^.* - [F,L] 这里”-”表示没有替换,浏览器为IE和Opera的访客将被禁止访问。
例子:
RewriteEngine On
RewriteBase /test
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ([^/]+)$ /test/$1.php
#for example: /test/admin => /test/admin.php
RewriteRule ([^/]+)\.html$ /test/$1.php [L]
#for example: /test/admin.html => /test/admin.php
限制目录只能显示图片
< IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !^.*\.(gif|jpg|jpeg|png|swf)$
RewriteRule .*$ - [F,L]
< /IfModule>
//参数传递
ServerAdmin test@test.com
DocumentRoot "D:/wwwroot/a"
ServerName uni.sina.com.cn
ErrorLog "logs/dummy-host2.localhost-error.log"
CustomLog "logs/dummy-host2.localhost-access.log" combined
RewriteEngine on
RewriteRule ^/$ http://search.sina.com.cn [R=301.L]
RewriteCond %{QUERY_STRING} ^k=([^&]*) [OR]
RewriteCond %{QUERY_STRING} &k=([^&]*)
RewriteRule ^/c\.php$ http://search.sina.com.cn/?c=blog&q=%1&by=tag [R=301,L]
</VirtualHost>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^www.xxxx.com$
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^admin.xxxx.com$
RewriteRule ^(.*)$ manager.php/$1 [QSA,PT,L]
</IfModule>