2011年3月8日 星期二

rewrite範例解說-未完成

以下範例取自網路
不是全部都測試過
主要是作為研究語法之用,使用時請多加測試
如果有問題,歡迎一起討論

    速查表
    http://regexlib.com/CheatSheet.aspx


13各範例,來自http://articles.sitepoint.com/article/apache-mod_rewrite-examples/2
1. Forcing www for a domain while preserving subdomains
將不是以www開頭的子網域請求轉成www.子網域
RewriteCond %{HTTP_HOST} ^([a-z.]+)?example\.com$ [NC]  
RewriteCond %{HTTP_HOST} !^www\. [NC]  
RewriteRule .? http://www.%1example.com%{REQUEST_URI} [R=301,L]

This rule captures the optional subdomain using the %1 variable, and, if it doesn't start with www., redirects with www. prepended to the subdomain. The domain and the original {REQUEST_URI} are appended to the result.
當HTTP_HOST開頭非www.時,將example.com之前的字串取成%1
重寫為www.%1example.com開頭,並把查詢字串${REQUEST_URI}接在後面
如果沒有第二條,那www.example.com的查詢也會被處理而成為www.www.example


2. Eliminating www from a domain
與第一條相反,去除網域請求中的www
RewriteCond %{HTTP_HOST} !^example\.com$ [NC]  
RewriteRule .? http://example.com%{REQUEST_URI} [R=301,L]
當HTTP_HOST不是example.com時,重寫為example.com

3. Getting rid of the www but preserving a subdomain
去除子網域的www但保留子網域

RewriteCond %{HTTP_HOST} ^www\.(([a-z0-9_]+\.)?example\.com)$ [NC]  
RewriteRule .? http://%1%{REQUEST_URI} [R=301,L]

Here, the subdomain is captured in %2 (the inner atom) but, since it's optional and already captured in the %1 variable, all you need is the %1 for the subdomain.
這邊的%2是子網域的名稱(使用?讓子網域不存在時也讓規則成立
雖然有代表子網域名稱的%2,不過由於%2未必存在,且包在%1中,所以在重寫規則中使用%1比較方便
簡化版
RewriteCond %{HTTP_HOST} ^www\.([a-z0-9_]+\.)?example\.com$ 
RewriteRule .? http://%1example.com%{REQUEST_URI} [R=301,L]
這邊的重點是判斷子網域時,"."必須要放在規則中
否則比對結果不能使用在重寫規則上

4. Preventing image hotlinking
防止圖片盜連(hotlink: 從網站外部來的請求)
If some unscrupulous webmasters are leeching your bandwidth by linking to images from your site to post on theirs, you can use the following rule to block the requests:

RewriteCond %{HTTP_REFERER} !^$  
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com/ [NC]  
RewriteRule \.(gif|jpg|png)$ - [F]
當HTTP_REFERER非空且非example.com時
對以.gif/.jpg/.png結尾的請求重寫為不可存取
沒第一條時,可以透過直接輸入網址的方式存取
沒第二條的話,連自己網站也不能開圖

If the {HTTP_REFERER} value is not blank, or from your own domain (example.com), this rule will block the viewing of URIs ending in .gif, .jpg, or .png using the forbidden flag, F.

If you are upset enough at these hotlinkers, you could change the image and let visitors to the site know that you know that they're hotlinking:

RewriteCond %{HTTP_REFERER} !^$  
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com/.*$ [NC]  
RewriteRule \.(gif|jpg|png)$ http://www.example.com/hotlinked.gif [R=301,L]

Instead of blocking the URI, the above rule rewrites it to a specific image in our domain. What appears in this image is completely up to your imagination!
進階版:轉向到指定圖片,告知這是盜連

You can block specific domains using:

RewriteCond %{HTTP_REFERER} !^http://(www\.)?leech_site\.com/ [NC]  
RewriteRule \.(gif|jpg|png)$ - [F,L]

This rule blocks all requests where the {HTTP_REFERER} field is set to the bad domain.
如果只是想阻止從某網站來的連結就用這條規則


Of course, the above rules rely on the {HTTP_REFERER} value being set correctly. It usually is, but if you'd rather rely on the IP Address, use {REMOTE_ADDR} instead.
上面規則都是建立在http_refer沒有被造假的情況下
另外也可以用remote_addr做判斷依據

5. Redirecting to a 404 page if the directory and file do not exist
當檔案或目錄不存在時,提供404錯誤頁面
If your host doesn't provide for a "file not found" redirection, create it yourself!

RewriteCond %{REQUEST_FILENAME} !-f  
RewriteCond %{REQUEST_FILENAME} !-d  
RewriteRule .? /404.php [L]

Here, -f matches an existing filename and -d matches an existing directory name. This script checks to see that the requested filename is not an existing filename or directory name before it redirects to the 404.php script. You can extend this script: include the URI in a query string by adding ?url=$1 immediately after the URI:
-f會檢查檔案是否存在,-d則是檢查目錄
當要使用a.com/a/b->a.com/a.php?q=b的方法的話,這條要放後面一點


RewriteRule ^/?(.*)$ /404.php?url=$1 [L]

This way, your 404.php script can do something with the requested URL: display it in a message, send it in an email alert, perform a search, and so on.
用這條重寫規則的話,可以用404.php根據所請求的名稱自訂處理方法

6. Renaming your directories
重寫目錄名稱(目錄改名時,把連到舊目錄的請求轉向到新目錄)
If you've shifted files around on your site, changing directory names, try this:

RewriteRule ^/?old_directory/([a-z/.]+)$ new_directory/$1 [R=301,L]

I've included the literal dot character (not the "any character" metacharacter) inside the set to allow file extensions.
這裡的一各小重點是字元集合中的"."代表的是小數點而非"任意字元"
如果沒有".",有檔名的請求如/old/123.gif會因為不符合樣式而不被重寫


7. Converting old .html links to new .php links
將old.html轉向到new.php
Updating your web site but need to be sure that bookmarked links will still work?
用於網站更新後依然要保持舊連結可用的情況下
RewriteRule ^/?([a-z/]+)\.html$ $1.php [L]
這規格會將/123/456.html 改寫為 123/456.PHP

This is not a redirection, so it will be invisible to your visitors. To make it permanent (and visible), change the flag to [R=301,L].

8. Creating extensionless links

If your site uses PHP files, and you want to make your links easier to remember -- or you just want to hide the file extension, try this:

RewriteRule ^/?([a-z]+)$ $1.php [L]
這會將/123/345 重寫為 123/345.php
If you have a mixture of both .html and .php files, you can use RewriteCond statements to check whether the filename with either extension exists as a file:

RewriteCond %{REQUEST_FILENAME}.php -f  
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.php [L]  
RewriteCond %{REQUEST_FILENAME}.html -f  
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.html [L]

If the file name exists with the .php extension, that rule will be chosen.
當網站同時存在.html和.php檔案(網站更新到一半或有部分檔案改變)
例如123/345.html已經被改成123/345.php, 但123/234.html還沒更新成123/234.php時
就可以用以上方法:透過-f檢查同名新檔案是否存在,存在時才重寫
並且用[L]終止繼續往下判斷
如果繼續往下,123/345.html改寫成123/345.php後,會再次被改為123/345.PHP


9. Checking for a key in a query string
檢查查詢參數中是否有key
If you need to have a specific key's value in your query string, you can check for its existence with a RewriteCond statement:

RewriteCond %{QUERY_STRING} !uniquekey=  
RewriteRule ^/?script_that_requires_uniquekey\.php$ other_script.php [QSA,L]

The above code will check the {QUERY_STRING} variable for a lack of the key uniquekey and, if the {REQUEST_URI} is the script_that_requires_uniquekey, it will redirect to an alternative URI.
當QUERY_STRING中沒有uniquekey這參數,就重寫請求
將/script_that_requires_uniquekey.php重寫為 other_script.php
使用^$包起來應該是因為request_uri並不包括query string? 
還是因為考慮到post的情況,所以用這方式處理?
[QSA]表示追加querystring




10. Deleting the query string
刪除查詢字串

Apache's mod_rewrite automatically passes through a query string unless you do either of the following:
mod_reqrite會自動跳過query string不做處理
除非發生以下任一情況(意思應該是有以下狀況時,會將原本的查詢字串刪除)

Assign a new query string (you can keep the original query string by adding a QSA flag, e.g., [QSA,L]).
Add a ? after a filename (for example, index.php?). The ? will not be shown in the browser's location field.
1. 設定新的query string,透過[QSA]可以將原本的query string附加上去
2. 在檔案後面加"?"


11. Redirecting a working URI to a new format
將一各現在還在用的uri轉成新的格式
Here's a curly one. Let's say, for example, that we've got a set of working URLs that look like this: /index.php?id=nnnn. However, we'd really like to change them to /nnnn and make sure search engines update their indexes to the new URI format. First, we'd have to redirect the old URIs to the new ones so that search engines update their indexes, but we'd still have to rewrite the new URI back to the old one so that the index.php script would run. Have I got your head spinning?
ok,這有點複雜 XD
有些時候,我們需要做一些奇怪的事情,例如我們有site/index.php?id=nnn這連結
我們不想改變檔案,但是想讓搜尋引擎上以site/nnn呈現
因此,首先要把舊的連結轉成新的連結,這樣搜尋引擎會更新成新的連結
但是使用者用新的連結連到網站時,又需要把它轉成舊的連結格式...你看懂了嘛?


The trick here is to place into the query string a marker code that will not be seen by visitors. We redirect from the old link to the new format only if the "marker" is not present in the query string. Then we rewrite the new format link back to the old format, and add a marker to the query string, using the QSA flag to ensure we're not eliminating an existing query string. Here's how it's done:
處理重點是如何在query string中尋找一各使用者看不到的marker code出來(標示碼?)
當marker code不在query string中,就把指向舊連結(index.php?id=nnn)的請求轉向到新的連結格式(/nnn)
然後我們就可以把使用新格式的請求轉向到舊連結去,同時附加一各標示碼
而使用QSA旗標可以把原本的query string附加回去(沒使用的話,原本的query string會被刪除)


RewriteCond %{QUERY_STRING} !marker  
RewriteCond %{QUERY_STRING} id=([-a-zA-Z0-9_+]+)  
RewriteRule ^/?index\.php$ %1? [R=301,L]  
以上是針對舊格式(index.php?id=nnnn)的存取處理
如果query string中沒有marker存在,且id匹配([-a-zA-Z0-9_+]+) 
就重寫請求為 /nnn?
 
RewriteRule ^/?([-a-zA-Z0-9_+]+)$ index.php?marker&id=$1 [L]




Here, the original URI, http://www.example.com/index.php?id=nnnn, does not contain the marker, so it's redirected by the first rule to http://www.example.com/nnnn with a HTTP 301 response. The second rule rewrites http://www.example.com/nnnn back to http://www.example.com/index.php?marker&id=nnnn, adding marker and id=nnnn in a new query string; then, the mod_rewrite process is started over.

In the second iteration, the marker is matched so the first rule is ignored and, since there's a dot character in index.php?marker&id=nnnn, the second rule is also ignored ... and we're finished!

Note that, while useful, this solution does require additional processing by Apache, so be careful if you're using it on shared servers with a lot of traffic.

12. Ensuring that a secure server is used

Apache can determine whether you're using a secure server in two ways: using the {HTTPS}, or {SERVER_PORT}, variables:

RewriteCond %{REQUEST_URI} ^secure_page\.php$  
RewriteCond %{HTTPS} !on   
RewriteRule ^/?(secure_page\.php)$ https://www.example.com/$1 [R=301,L]

The above example tests that the {REQUEST_URI} value is equal to our secure page script, and that the {HTTPS} value is not equal to on. If both these conditions re met, the request is redirected to the secure server URI. Alternatively, you could do the same thing by testing the {server_port} value, where 443 is typically the secure server port:

RewriteCond %{REQUEST_URI} ^secure_page\.php$  
RewriteCond %{SERVER_PORT} !^443$  
RewriteRule ^/?(secure_page\.php)$ https://www.example.com/$1 [R=301,L]

13. Enforcing secure server only on selected pages

In situations where secure and unsecured domains share the web server's DocumentRoot directory, you'll need a RewriteCond statement to check that the secure server port isn't being used, and then only redirect the request if the requested script is one in the list of those that require a secure server:

RewriteCond %{SERVER_PORT} !^443$  
RewriteRule ^/?(page1|page2|page3|page4|page5)$  https://www.example.com/%1 [R=301,L]

Here's how you'd redirect requests for pages not requiring a secure server back to port 80:

RewriteCond %{ SERVER_PORT } ^443$   
RewriteRule !^/?(page6|page7|page8|page9)$ http://www.example.com%{REQUEST_URI} [R=301,L]

#以下是网址指向重写(ISAPI_Rewrite 3.x 版本)即二级域名绑定子目录:
RewriteCond Host: disk\.dayunet\.com 
RewriteRule ^(.*)$ /disk/$1 [NC]

#以下是防盗链系统:

RewriteCond Host: (.+) 
RewriteCond Referer: (?!http://(?:www.dayunet\.com|(.*)\.dayunet\.com|baidu\.com|(.*)\.baidu\.com|google\.com|(.*).\google.com|google\.cn|(.*).\google.cn|dayunet\.com|(.*)\.dayunet\.com|(.*)\.dayunet\.com.cn|(.*)\.dayunet\.cn)).*
RewriteRule .*\.(?:jpg|jpeg|gif|png|bmp|rar|zip|exe|mp3) /door.png [NC,O,N]

#door.png为网站根目录下原来显示盗链的图片

------配置结束------


一各避免重複的作法
pattern: th[^s]*.
test:
I want to match the words that start
with 'th' and end with 's'.
result
this
thus
thistle
this line matches too much



常見的用法:
(A) 重新導向到正確的網址:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^ohaha.ks.edu.tw$ [NC] 
RewriteRule ^(.*)$ http://ohaha.ks.edu.tw/$1 [R,L]
說明: 
若使用者瀏覽頁是www.ohaha.ks.edu.tw/ooo.php 重導向至 http://ohaha.ks.edu.tw/ooo.php 

(B) 禁止盜連檔案,並且顯示相關訊息給盜連者.
RewriteEngine on
SetEnvIf referer "^$" local_ref=1
RewriteCond %{HTTP_REFERER} !^http://ohaha.ks.edu.tw/.*$ [NC]
RewriteRule .*\.(jpg|gif|png|iso|rar|zip|tar.gz)$ /nohotlink.png [R,NC]

說明:
若使用者參照頁面不是空的, (第一行)
也不包含 http://ohaha.ks.edu.tw/  (第二行)
且瀏覽 jpg gif ...等圖檔, 則以 /nohotlink.png 圖檔替代顯示這些遭盜連檔案. (第三行)

補充:
此時若有盜連者,可以在http-access log檔案可以發現類似如下紀錄:
使用者的IP位址 - - [30/Jun/2008:16:57:41 +0800] "GET /nohotlink.png HTTP/1.1" 304 - "盜連的頁面來源" "Mozilla/4.0 (compatible; MSIE 7.0; W indows NT 5.1)"

沒有留言: