Apache HTTP サーバ バージョン 2.5

このドキュメントは mod_rewrite
リファレンスドキュメントを補足するものです。
mod_rewrite の使用に必要な基本概念を説明します。
他のドキュメントではさらに詳しく説明しますが、このドキュメントは
初心者が最初の一歩を踏み出すのに役立つはずです。
Apache モジュール mod_rewrite は、URL 操作を行う方法を
提供する非常に強力で洗練されたモジュールです。これを使用すると、
必要なほぼすべての種類の URL 書き換えを行うことができます。
ただし、やや複雑で、初心者には敷居が高く感じられるかもしれません。
また、書き換えルールを実際に何をしているか理解せずに、魔法の呪文として
扱う傾向もあります。
このドキュメントは、以下の内容が単にコピーされるのではなく、 理解されるための十分な背景を提供することを目指しています。
多くの一般的な URL 操作タスクは mod_rewrite の
フルパワーと複雑さを必要としないことを忘れないでください。シンプルな
タスクについては、mod_alias と
URL からファイルシステムへの
マッピングに関するドキュメントを参照してください。
最後に、先に進む前に、LogLevel
ディレクティブを使用して mod_rewrite のログレベルを
trace レベルのいずれかに設定してください。これにより圧倒的な量の情報が
得られますが、mod_rewrite 設定の問題をデバッグするのに
不可欠です。各ルールがどのように処理されるかを正確に教えてくれます。
mod_rewrite は Perl 互換
正規表現の語彙を使用します。このドキュメントでは、正規表現の
詳細なリファレンスを提供しようとはしていません。そのためには、
PCRE man ページ、
Perl 正規表現
man ページ、および
Jeffrey Friedl 著
『詳説 正規表現』 (第 3 版は 2006 年のものですが、正規表現の
構文は本質的に変わっておらず、このテーマの決定的なリファレンスです)
を推奨します。
このドキュメントでは、圧倒されることなく始められるように、
十分な正規表現の語彙を提供しようとしています。
RewriteRule が魔法の呪文ではなく、
科学的な公式であるようになることを願っています。
以下は、正規表現と RewriteRule を書くために必要な
最小限の構成要素です。これらは完全な正規表現の語彙を表すものでは
ありませんが、良い出発点であり、基本的な正規表現を読むだけでなく、
自分で書くのにも役立つはずです。
| 文字 | 意味 | 例 |
|---|---|---|
. |
任意の 1 文字にマッチ | c.t は cat、cot、
cut 等にマッチ |
+ |
直前のマッチを 1 回以上繰り返す | a+ は a、aa、
aaa 等にマッチ |
* |
直前のマッチを 0 回以上繰り返す | a* は a+ がマッチするすべてにマッチするが、
空文字列にもマッチする |
? |
マッチをオプションにする | colou?r は color と
colour にマッチ |
\ |
次の文字をエスケープ | \. は上記で説明した任意の 1 文字ではなく、
. (ドット) にマッチ |
^ |
アンカーと呼ばれ、文字列の先頭にマッチ | ^a は a で始まる文字列にマッチ |
$ |
もう一つのアンカーで、文字列の末尾にマッチ | a$ は a で終わる文字列にマッチ |
( ) |
複数の文字を 1 つの単位にグループ化し、バックリファレンスで 使用するためのマッチをキャプチャ | (ab)+ は ababab にマッチ - つまり、
+ がグループに適用される。バックリファレンスの
詳細は以下を参照 |
[ ] |
文字クラス - いずれかの文字にマッチ | c[uoa]t は cut、cot、
cat にマッチ |
[^ ] |
否定文字クラス - 指定されていない任意の文字にマッチ | c[^/]t は cat や c=t に
マッチするが、c/t にはマッチしない |
mod_rewrite では、正規表現の前に ! 文字を
使用して否定できます。つまり、式の残りの部分にマッチしない場合にのみ、
文字列がマッチしたとみなされます。
ここで覚えておくべき重要なことがあります: Pattern 内または
CondPattern 内で括弧を使用するたびに、内部的にバックリファレンスが
作成され、$N および %N という文字列で使用
できます (以下を参照)。これらは
RewriteRule の
Substitution パラメータまたは
RewriteCond の
TestString パラメータの作成に使用できます。
RewriteRule パターン内の
キャプチャは、(直感に反して) すべての先行する
RewriteCond ディレクティブで
利用可能です。これは、RewriteRule
式が個々の条件よりも先に評価されるためです。
図 1 は、バックリファレンスが展開のためにどの場所に 転送されるかを示すとともに、RewriteRule と RewriteCond の マッチングのフローを図示しています。次の章では、これらの バックリファレンスの使用方法を探りますので、最初は少し 馴染みがないように感じても心配しないでください。

図 1: ルールを通るバックリファレンスのフロー。
この例では、/test/1234 へのリクエストは /admin.foo?page=test&id=1234&host=admin.example.com に変換されます。
RewriteRule は、
スペースで区切られた 3 つの引数で構成されます。引数は以下の通りです
Pattern は正規表現です。 最初 (最初の書き換えルールまたは置換が発生するまで) は、受信リクエストの URL パス (ホスト名の後、クエリ文字列の開始を示す疑問符の前の部分) に対して マッチされます。ディレクトリ単位のコンテキストでは、ルールが定義された ディレクトリに対するリクエストの相対パスに対してマッチされます。 置換が発生すると、後続のルールは置換された値に対してマッチされます。

図 2: RewriteRule ディレクティブの構文
Substitution 自体は以下の 3 つのいずれかです:
RewriteRule "^/games" "/usr/local/games/web/puzzles.html"
これは、Alias ディレクティブと
同様に、リクエストをファイルシステム上の任意の場所にマッピングします。
RewriteRule "^/games$" "/puzzles.html"
DocumentRoot が
/usr/local/apache2/htdocs に設定されている場合、
このディレクティブは http://example.com/games への
リクエストをパス /usr/local/apache2/htdocs/puzzles.html
にマッピングします。
RewriteRule "^/product/view$" "http://site2.example.com/seeproduct.html" [R]
これは、指定された URL に対する新しいリクエストを行うよう クライアントに指示します。
/usr/) がファイルシステム上に存在するのに対し、2 の場合は存在しない (つまり、ファイルシステムのルートレベルディレクトリとして /bar/ が存在しない) ことです。Substitution には、Pattern でマッチした 受信 URL パスの部分へのバックリファレンスも含めることができます。 以下を考えてみてください:
RewriteRule "^/product/(.*)/view$" "/var/web/productdb/$1"
変数 $1 は、Pattern 内の括弧内の
式でマッチしたテキストに置き換えられます。例えば、
http://example.com/product/r14df/view へのリクエストは
パス /var/web/productdb/r14df にマッピングされます。
括弧内の式が複数ある場合、変数 $1、$2、
$3 等の順序で利用できます。
RewriteRule の動作は、
ルールの末尾に 1 つ以上のフラグを適用することで変更できます。例えば、
ルールのマッチング動作は [NC] フラグの適用で
大文字小文字を区別しないようにできます:
RewriteRule "^puppy.html" "smalldog.html" [NC]
利用可能なフラグ、その意味、および例の詳細については、 書き換えフラグドキュメントを参照してください。
1 つ以上の RewriteCond
ディレクティブを使用して、後続の
RewriteRule の対象となる
リクエストの種類を制限できます。最初の引数はリクエストの特性を
記述する変数、2 番目の引数は変数にマッチする必要がある
正規表現、3 番目のオプション引数はマッチの
評価方法を変更するフラグのリストです。

図 3: RewriteCond ディレクティブの構文
例えば、特定の IP 範囲からのすべてのリクエストを別のサーバに 送信するには、以下を使用できます:
RewriteCond "%{REMOTE_ADDR}" "^10\.2\."
RewriteRule "(.*)" "http://intranet.example.com$1"
複数の RewriteCond が
指定された場合、RewriteRule
が適用されるには、すべてがマッチする必要があります。例えば、
クエリ文字列に "hack" という単語を含むリクエストを拒否するが、
"go" という単語を含む cookie がある場合は除外するには、以下を使用
できます:
RewriteCond "%{QUERY_STRING}" "hack"
RewriteCond "%{HTTP_COOKIE}" !go
RewriteRule "." "-" [F]
感嘆符は否定マッチを指定しており、cookie に "go" が含まれていない 場合にのみルールが適用されます。
RewriteCond 内の正規表現の
マッチは、RewriteRule の
Substitution で変数 %1、%2 等を
使用して使用できます。例えば、以下はサイトへのアクセスに使用された
ホスト名に応じて、リクエストを異なるディレクトリに振り分けます:
RewriteCond "%{HTTP_HOST}" "(.*)"
RewriteRule "^/(.*)" "/sites/%1/$1"
http://example.com/foo/bar へのリクエストの場合、
%1 は example.com を含み、
$1 は foo/bar を含みます。
RewriteMap ディレクティブは、
書き換えを行うための外部関数を呼び出す方法を提供します。これについては
RewriteMap 補足ドキュメントでより詳細に
説明されています。
書き換えは通常、メインサーバ設定
(<Directory>
セクション外) または
<VirtualHost>
コンテナ内で設定されます。これが書き換えの最も簡単な方法であり、
推奨されます。ただし、追加の複雑さを伴いますが、
<Directory>
セクションや .htaccess
ファイル内で書き換えを行うことも可能です。このテクニックは
ディレクトリ単位の書き換えと呼ばれます。
サーバ単位の書き換えとの主な違いは、.htaccess
ファイルを含むディレクトリのパスプレフィックスが
RewriteRule でのマッチング前に
削除されることです。さらに、リクエストが適切にマッピングされるように
RewriteBase を使用する
必要があります。