2012年1月6日 星期五

Web Server - Apache RewriteRule 重寫規則

重寫相關的指令,可以寫在 httpd.conf 的 <Directory /></Directory>,或是 .htaccess 檔。

方式一,Directory 標籤

    <Directory />
        Options All
        AllowOverride All
        Order Deny,Allow
        Allow from all
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ index.php?arg=$1 [QSA,L]

    </Directory>

方式二,.htaccess 檔

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?arg=$1 [QSA,L]

注意:如果使用虛擬站台,設定檔是 httpd-vhosts.conf ,記得要去 httpd.conf <Directory /> 開啟 AllowOverride All ,不然 .htaccess 會沒發生作用。

RewriteCond

假設使用者請求的網址是:
http://www.example.local:8080/index.php?arg1=123 &arg2=456

RewriteCond %{HTTP_HOST}
符合字串:www.example.local:8080

RewriteCond %{SERVER_NAME}
符合字串:www.example.local

RewriteCond %{REMOTE_HOST}
符合字串:myXpPcName (客戶端的電腦名稱)

RewriteCond %{REMOTE_ADDR}
符合字串:123.123.123.123 (客戶端的IP位址)

RewriteCond %{REQUEST_URI}
符合字串:index.php

RewriteCond %{QUERY_STRING}
符合字串:arg1=123&arg2=456

RewriteCond %{REQUEST_FILENAME} ......
符合字串:/var/www/html/index.php (系統的檔案完整路徑 )


Flag 旗標
C (chain) 如果一個規則被匹配,則繼續處理其後繼規則;如果該規則不被匹配,則其後繼規則將被跳過。
L (last) 使用這個FLAG以阻止當前被重寫的URI被後面的規則再次重寫。換句話說,返回指定的網址內容,但網址不變。
N (next) 重新執行重寫操作(從第一個規則重新開始)。此時再次進行處理的URL已經不是原始的URL了,而是經最後一個重寫規則處理過的URL。但是要小心,不要製造死循環。
QSA (Query String Append) 追加查詢字串
NC (nocase) 忽略大小寫
R (redirect) 轉址到指定的網址,網址會變。

注意: 使用多個旗標時要用逗號隔開。例如 [N,C,NC] 所以 [NC] 跟 [N,C] 不一樣喔

範例
 --------------------------------------------------------------------------------
請求:http://example.local/index.php
返回:http://www.example.local/index.php
語法:
#方法一
RewriteCond %{HTTP_HOST} ^example.local [NC]
RewriteRule ^(.*)$ http://www.example.local/$1 [R=301,L]

#方法二
RewriteCond %{HTTP_HOST} !^www [NC]
RewriteRule ^(.*)$ http://www.example.local/$1 [R=301,L]

#方法三
RewriteCond %{HTTP_HOST} !^www [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
--------------------------------------------------------------------------------
請求:http://www.example.local/USA/California/San_Diego
返回:http://www.example.local/index.php?country=USA&state=California&city=San_Diego
語法:
#轉址
RewriteRule ^([a-zA-Z_]+)/([a-zA-Z_]+)/([a-zA-Z_]+)$ index.php?country=$1&state=$2&city=$3 [NE,R]

#不轉址,但使用後面的形式返回,一樣可以得到 url 參數
RewriteRule ^/?([a-zA-Z_]+)/([a-zA-Z_]+)/([a-zA-Z_]+)$ index.php?country=$1&state=$2&city=$3 [L]
 --------------------------------------------------------------------------------
請求:http://example.local/users/?view=registration
返回:http://example.local/users/registration.php
RewriteBase "/"
RewriteCond %{QUERY_STRING} ^view=(.*)$
RewriteRule ^users/$ users/%1.php [R=301,L]
--------------------------------------------------------------------------------
請求:http://example.local/product/ProductName
返回:http://example.local/product/product.php?pname=ProductName
語法:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ product.php?pname=$1 [L,QSA]
#這個要寫在 /product/.htaccess


2014-03-09 補充:
2.4版以後的apache,取消 RewriteLog 相關指令。
官網說明
Those familiar with earlier versions of mod_rewrite will no doubt be looking for the RewriteLog and RewriteLogLevel directives. This functionality has been completely replaced by the new per-module logging configuration mentioned above.

要改用這樣的指令: LogLevel warn mod_rewrite.c:trace3
trace後面的數字是要記錄的詳細程度,可以是1到8。
LogLevel 跟 ServerName 的指令在同一層。

另外,有些舊文章說要加 AddModule mod_rewrite.c。但是不知道從哪個版本開始,也已經拿掉了 AddModule 這個指令。

延申閱讀:
Apache模块 mod_rewrite (金步國)
Module mod_rewrite (Apache官網)
RewriteRule Flags(Apache官網)
PHP, 正規表式法 (by myself)
URL Rewrite(網址重寫)語法教學

mod_rewrite Quick Reference and Cheat Sheet (有實際範例)
使用 apache 的 rewrite 重導網頁
Apache 重寫規則的常見應用 (rewriterule)
Apache中RewriteCond规则参数介绍(转)
在httpd.conf中设置%{REQUEST_FILENAME} !-f无效解决方法

沒有留言:

張貼留言