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で独自のプログラムを使う話を書こうと思います。