mod_rewrite の書き方についてまとめ2
前回のおさらい
- RewiteRule はリクエストURIに対して正規表現置換
- RewiteRule は複数書くと、全部処理され最後にマッチしたものが採用
- RewiteCond はRewriteRuleとAnd条件で追加される。
RewriteRule を1つ、RewriteCondを複数
1つのRewriteRuleに対して、RewriteCondを複数書くとどうなるのか。
RewriteCond %{REQUEST_FILENAME} \.jpg
RewriteCond %{REQUEST_FILENAME} hoge
RewriteRule ^ ../get.php?from=ex1-rule1
hoge.gif は 書換処理されない。
hoge でマッチするが、jpg にマッチしないのでAND条件で、最終的にFalse
その結果、通常リクエストが行われ、hoge.gif が存在しないので404 file not found になる。
takuya@~/Sites/rewrites/ex1$ curl -I http://localhost/~takuya/rewrites/ex1/hoge.gif HTTP/1.1 404 Not Found # 書換処理されない。
hogehoge.jpg や hoge.jpg へのリクエスト
ファイルは存在しないが、リクエストURIにRewriteが行われるので、get.php に転送される。
takuya@~/Sites/rewrites/ex1$ curl http://localhost/~takuya/rewrites/ex1/hoge.jpg
array(1) {
["from"]=>
string(9) "ex1-rule1"
}
takuya@~/Sites/rewrites/ex1$ curl http://localhost/~takuya/rewrites/ex1/hogehoge.jpg
array(1) {
["from"]=>
string(9) "ex1-rule1"
}
RewriteCond は複数書くとAND条件
RewriteRule AND RewriteCond
複数書けば
RewriteRule AND RewriteCond AND RewriteCond
さらに、Rewriteruleが複数なら
if ( RewriteRuleMatch AND RewriteCond ) { }
if ( RewriteRuleMatch AND RewriteCond AND RewriteCond ) {}
のようになっている。
後半で言及するけど、 [OR]を使えば
if ( RewriteRuleMatch AND (RewriteCond OR RewriteCond ) ) {}
のような処理も可能ですね。
RewriteRule のGET文字列の取扱い
RewriteRule の書換えでGETを指定した場合。
RewriteRule ^ ../get.php?from=ex1
リクエストURLにつけたGET文字列は無視される
リクエスト結果
takuya@~/Sites/rewrites$ curl http://localhost/~takuya/rewrites/ex1/hoge.jpg?test=1 # GET文字列つけた array(1) { ["from"]=> string(3) "ex1" # 書換の結果に出てこない。 }
RewriteRule の書換えにGET指定しない場合
何もか書かずにURLだけを指定した場合、GET文字列の書換は起こらない。
RewriteRule ^ ../get.php
リクエスト結果
takuya@~/Sites/rewrites$ curl http://localhost/~takuya/rewrites/ex1/hoge.jpg?test=1 # GET文字列つけた array(1) { ["test"]=> string(1) "1" }
これはQueryString環境変数が書換指定が無いため、環境変数の書換が行われないと理解しています。
RewriteRule の書換えにGET指定し、QSA(クエリ文字列追記)フラグを書いた場合
QSA : Query String Append フラグをつけた場合は、GET文字列の書換が行われる。
GET引数が追加される例
RewriteRule ^ ../get.php?from=ex1 [QSA]
リクエスト結果
都合よく、QueryStringが追記が行われるので便利そう。
takuya@~/Sites/rewrites$ curl http://localhost/~takuya/rewrites/ex1/hoge.jpg?test=1
array(2) {
["from"]=>
string(3) "ex1"
["test"]=>
string(1) "1" # 書換先でGET文字列は追加された。
}
同名で上書きの例
RewriteRuleと同じGET引数を指定した場合も考えておく。
リクエストとRewriteRuleで同名の変数が指定されたら、同名の from=ex1 がリクエストで上書きされる。
takuya@~/Sites/rewrites$ curl 'http://localhost/~takuya/rewrites/ex1/hoge.jpg?test=1&from=curl'
array(2) {
["from"]=>
string(4) "curl" # リクエストで上書き
["test"]=>
string(1) "1"
}
リクエストの引数が強くて、RewriteRuleのGET引数は上書きされ消される。
このことから、GET文字列の書換は環境変数QueryStringに依存していると理解している。
リクエストのURLは、QueryStringとPathINFO でそれぞれ別に処理されているようだ。
RewriteRuleで使えるオプション
[QSA] の他にも、RewriteRuleで使えるオプションはたくさんある。ありすぎて、組合せが用意に想像つかないくらい。たくさん。
ApacheのDocumentationによると次表の通り。
| Flag and syntax | Function |
|---|---|
| B | Escape non-alphanumeric characters before applying the transformation. |
| chain|C | Rule is chained to the following rule. If the rule fails, the rule(s) chained to it will be skipped. |
| cookie|CO=NAME:VAL | Sets a cookie in the client browser. Full syntax is: CO=NAME:VAL:domain[:lifetime[:path[:secure[:httponly]]]] |
| discardpath|DPI | Causes the PATH_INFO portion of the rewritten URI to be discarded. |
| env|E=[!]VAR[:VAL] | Causes an environment variable VAR to be set (to the value VAL if provided). The form !VAR causes the environment variable VAR to be unset. |
| forbidden|F | Returns a 403 FORBIDDEN response to the client browser. |
| gone|G | Returns a 410 GONE response to the client browser. |
| Handler|H=Content-handler | Causes the resulting URI to be sent to the specified Content-handler for processing. |
| last|L | Stop the rewriting process immediately and don't apply any more rules. Especially note caveats for per-directory and .htaccess context (see also the END flag). |
| next|N | Re-run the rewriting process, starting again with the first rule, using the result of the ruleset so far as a starting point. |
| nocase|NC | Makes the pattern comparison case-insensitive. |
| noescape|NE | Prevent mod_rewrite from applying hexcode escaping of special characters in the result of the rewrite. |
| nosubreq|NS | Causes a rule to be skipped if the current request is an internal sub-request. |
| proxy|P | Force the substitution URL to be internally sent as a proxy request. |
| passthrough|PT | Forces the resulting URI to be passed back to the URL
mapping engine for processing of other URI-to-filename
translators, such as Alias or
Redirect. |
| qsappend|QSA | Appends any query string from the original request URL to any query string created in the rewrite target. |
| redirect|R[=code] | Forces an external redirect, optionally with the specified HTTP status code. |
| skip|S=num | Tells the rewriting engine to skip the next num rules if the current rule matches. |
| type|T=MIME-type | Force the MIME-type of the target file to be the specified type. |
使い方例は、別章にまとめて書きます。
RewriteCond を複数ORで組み合わせる
RewriteRuleはほどほどにして、RewriteCondに戻ります。RewriteCondを複数書いた時にORで結合する話です。
例:UserAgentがcurlまたはtakuyaの時だけ処理をする
RewriteCond %{HTTP_USER_AGENT} curl [NC,OR]
RewriteCond %{HTTP_USER_AGENT} takuya [NC]
RewriteRule ^ ../get.php?from=ex1
リクエストすると、書換が動作する。
takuya@~/Sites/rewrites$ curl http://localhost/~takuya/rewrites/ex1/index.php
array(1) {
["from"]=>
string(3) "ex1"
}
takuya@~/Sites/rewrites$ curl \
-H "User-Agent: takuya" \
http://localhost/~takuya/rewrites/ex1/index.php
array(1) {
["from"]=>
string(3) "ex1"
}
UserAgent を指定してリクエストを送信してみる。
マッチしないUserAgentだと書き換えられず、本来の結果が表示される。
takuya@~/Sites/rewrites$ curl \ -H "User-Agent: webkit" \ http://localhost/~takuya/rewrites/ex1/index.php Hello from 'index'
もっとも、正規表現のマッチでORを使う理由はあまり無い。(正規表現で複数条件をかけるため)
RewriteCond で 複数条件
ORを使って柔軟な条件を考えてみようと思います。
Cookie に login=true が含まれる OR UserAgentがcurl の時に書換
RewriteCond %{HTTP_USER_AGENT} curl [NC,OR]
RewriteCond %{HTTP_COOKIE} login=true
RewriteRule ^ ../get.php?from=ex1
login=true を満たす
条件のCookie 側にマッチした場合。書換が起こる。
takuya@~/Sites/rewrites$ curl \
--cookie "login=true" \
-H "User-Agent: takuya" \
http://localhost/~takuya/rewrites/ex1/index.php
array(1) {
["from"]=>
string(3) "ex1"
}
UserAgent = curl を満たす。
条件のUserAgent = /curl/ 側を満たす場合。書換が起こる
takuya@~/Sites/rewrites$ curl \
--cookie "login=false" \
-H "User-Agent: curl " \
http://localhost/~takuya/rewrites/ex1/index.php
array(1) {
["from"]=>
string(3) "ex1"
}
どちらにもマッチしない場合。
どちらにもマッチしない場合、書換は処理されない。
takuya@~/Sites/rewrites$ curl \ --cookie "login=false" \ -H "User-Agent: takuya" \ http://localhost/~takuya/rewrites/ex1/index.php Hello from 'index'
ただし、この場合でもRewriteRuleが動作している。RewriteRuleにマッチするURLなので、RewriteCondルール処理判定されている。
RewriteCond で使えるオプション
| オプション | 意味 |
|---|---|
| OR | 直後に続くCondとOR |
| NC | 大文字小文字を否区別 |
NC と OR を同時に指定するときは、[ NC, OR ] とカンマ区切りで指定する。
# 正しい例
RewriteCond %{HTTP_USER_AGENT} curl [NC,OR]
# 間違い ー [ OR ] は処理されない
RewriteCond %{HTTP_USER_AGENT} curl [NC] [OR]
RewriteCond で使える環境変数。
ApacheのDocumentation を閲覧すると、利用できる環境変数は次のものが挙げられている。 またRewriteCondで環境変数の書換や作成が可能なので、柔軟に対応ができる。
| HTTP headers: | connection & request: | |
|---|---|---|
|
HTTP_USER_AGENT HTTP_REFERER HTTP_COOKIE HTTP_FORWARDED HTTP_HOST HTTP_PROXY_CONNECTION HTTP_ACCEPT |
REMOTE_ADDR REMOTE_HOST REMOTE_PORT REMOTE_USER REMOTE_IDENT REQUEST_METHOD SCRIPT_FILENAME PATH_INFO QUERY_STRING AUTH_TYPE |
|
| server internals: | date and time: | specials: |
|
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 |
API_VERSION THE_REQUEST REQUEST_URI REQUEST_FILENAME IS_SUBREQ HTTPS |
上記に記載されてないヘッダへのマッチ。
RewriteCond %{HTTP:X-MY-HEADER} curl [NC]
RewriteRule ^ ../get.php?from=ex1
HTTPのカスタムヘッダで、独自定義のヘッダにマッチさせるには %{HTTP:X-SAMPLE}のようにする。
$HTTP 変数がハッシュになっていて キーで取得しているイメージ
%{HTTP:X-SAMPLE} は $HTTP["X-SAMPLE"] に相当
これを実際に記述して実行してみた結果、ヘッダ追加したばあいに書換が実行される。
takuya@~/Sites/rewrites$ curl -H "X-MY-HEADER: curl " http://localhost/~takuya/rewrites/ex1/index.php
array(1) {
["from"]=>
string(3) "ex1"
}
独自ヘッダでもRewriteCond+RewriteRuleの書換ルールセットは処理される。
RewriteCond で使える、マッチ演算
マッチ演算にはいくつかのパターンがあり、ApacheのDocumentから拾い出すと次表の通りでした。
| 比較演算子 | 内容 |
|---|---|
| '<CondPattern' | (lexicographically precedes) |
| '>CondPattern' | (lexicographically follows) |
| '=CondPattern' | (lexicographically equal) |
| '-d' | (is directory) |
| '-f' | (is regular file) |
| '-s' | (is regular file, with size) |
| '-l' | (is symbolic link) |
| '-x' | (has executable permissions) |
| '-F' | (is existing file, via subrequest) |
| '-U' | (is existing URL, via subrequest) |
よく使いそうなものは、! 否定 や -f ファイルが存在スル だと思います。
RewriteRuleと RewriteCond で紹介しなかったもの
書き換え後のURLに、さらにマッチさせる、サブリクエストにマッチ
書き換え後のURLを、さらに1からマッチをやり直すリクエストなど
サブリクエスト関連については、省略した。
また、プロキシリクエストに関しても省略した。
理由は、RewriteRuleの基本の流れと実験方法がわかれば、理解が容易になるため。
次章
次は、RewriteCondとRewriteMapで独自のプログラムを使う話を書こうと思います。