Rewrite (URL書き換え)

RewriteEngine (Rewriteの有効化)

書き換えを有効にするには、最初にRewriteEngineディレクティブの設定で[on]を指定する必要があります。

RewriteEngine on|off
RewriteEngine Directive - mod_rewrite - Apache HTTP Server

RewriteCond (書き換えを実行する条件の指定)

RewriteRuleの実行に条件を付けられます。

RewriteCond TestString CondPattern [flags]
RewriteCond Directive - mod_rewrite - Apache HTTP Server

TestStringの文字列がCondPatternの条件に一致する場合のみ、書き換えが実行されます。

TestString

TestStringには%{HTTP_HOST}のような、サーバー変数 (Server-Variables) などを指定できます。

HTTP headers
変数 内容
HTTP_USER_AGENT  
HTTP_REFERER  
HTTP_COOKIE  
HTTP_FORWARDED  
HTTP_HOST  
HTTP_PROXY_CONNECTION  
HTTP_ACCEPT  
connection & request
変数 内容
 
server internals
変数 内容
 
date and time
変数 内容
 
specials
変数 内容
THE_REQUEST ブラウザからサーバへ送られたHTTPリクエストであり、"GET /index.html HTTP/1.1"のような内容
REQUEST_URI リクエストURIのパスの部分であり、"/index.html"のような内容
REQUEST_FILENAME リクエストに一致する、ファイルまたはスクリプトへのローカル ファイルシステムへのフルパス (full local filesystem path)
HTTPS SSL/TLSで接続されているならば"on"、さもなくば"off"
 
その他の変数
  内容
%{ENV:variable} 環境変数の値
%{SSL:variable} SSL環境変数の値
%{HTTP:header} HTTPヘッダの値
%{LA-U:variable}  
%{LA-F:variable}  

CondPattern

CondPatternPerl互換の正規表現で記述します。この条件の先頭を「!」から始めると、条件の意味が反転します。また正規表現で指定する以外に、下表のような特別な記述法が用意されています。

CondPatternの代替値
指定方法 一致する条件
<CondPattern  
>CondPattern  
=CondPattern  
-d ディレクトリ
-f 通常のファイル
-s ファイルサイズが0より大きい、通常のファイル
-l シンボリック リンク
-x 実行可能ファイル
-F  
-U  

たとえばファイルやディレクトリが存在するときに適用するCondPatternに「!」を付加することで、それらが存在しないときにのみ書き換えを実行できます。

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

flags

flagsでは特別な機能を追加できます。このflagsは、必ず[]の中に記述します。

flags引数
キーワード 意味
NC (nocase) 大文字と小文字を区別しない
OR (ornext) 続く条件をORで判定する
NV (novary)  
※キーワードは、かっこ内のものでも可

複数の条件を組み合わせる場合

RewriteCondを複数記述すると、それらが一致した場合のみ書き換えが実行されます。

RewriteCond testString1 condPattern1
RewriteCond testString2 condPattern2

これをいずれかの条件が一致した場合のみとするには、flagsにORを指定します。

RewriteCond testString1 condPattern1 [OR]
RewriteCond testString2 condPattern2

ORの指定は、それを指定しない場合よりも優先して判定され、

RewriteCond A [OR]
RewriteCond B
RewriteCond C [OR]
RewriteCond D

は、「(A OR B) AND (C OR D)」の条件となります。mod rewrite - how to use "AND", "OR" for RewriteCond on Apache? - Stack Overflow

複数のRewriteRuleに適用する場合

RewriteCondは、直後に記述された1つのRewriteRuleにしか作用しません。よって、

RewriteBase /
RewriteCond %{REQUEST_URI} bb
RewriteRule aa zz [R]
RewriteRule cc yy [R]

とした場合、「http://example.com/aacc」のURLでも、2番目のRewriteRuleが適用されてしまいます。これは正しくは、

RewriteBase /
RewriteCond %{REQUEST_URI} bb
RewriteRule aa zz [R]

RewriteCond %{REQUEST_URI} bb
RewriteRule cc yy [R]

とします。

記述例

RewriteBase /
RewriteCond %{REQUEST_URI} bb
RewriteRule aa zz [R]

このとき「http://example.com/aacc」のURLでは、RewriteRuleのパターンは一致するものの、RewriteCondの条件が不一致のため、書き換えは起こりません。一方で次のURLならば、書き換えられます。

http://example.com/aabbcc
 ↓
http://example.com/zz

サブドメインの統一

サブドメインを統一するには修正するホスト名をRewriteCondでマッチさせ、そのサブドメイン部を書き換えます。

RewriteBase /
RewriteCond %{HTTP_HOST} ^example\.com [NC,OR]
RewriteCond %{HTTP_HOST} ^www2\.example\.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]

参考

  • useful examples - Apache HTTP Server
  • more useful examples - Apache HTTP Server

RewriteRule (書き換えパターン)

RewriteRule Pattern Substitution [flags]
RewriteRule Directive - mod_rewrite - Apache HTTP Server

PatternはPerl互換の正規表現で、たとえばURLが「http://www.example.com/path/to/file.html」ならば、この太字部分と比較されます。

flags引数
キーワード※1 説明
NC (nocase) 大文字と小文字を区別しない
NE (noescape) URLエスケープを行わない
R[=code] (redirect) ※2 リダイレクトを強制する。オプションでHTTPのステータスコードを明示できる
F (forbidden) 403 (Forbidden) ステータスコードを返す。Denyディレクティブより柔軟に条件を適用できる。Lが暗黙的に指定され、他の規則は評価されない
G (gone) 410 (Gone) ステータスコードを返す。Lが暗黙的に指定され、他の規則は評価されない
L (last) ※3 書き換えを終了し、これ以上書き換えルールが適用されないようにする
 
RewriteRule Flags - Apache HTTP Server
※1 キーワードは、かっこ内のものでも可
※2 設定を誤ると、リダイレクトがループします
※3 apache - RewriteRule Last [L] flag not working? - Stack Overflow

複数のフラグを指定する場合は、カンマで区切ります。

FやGフラグを指定するときはSubstitutionを"-"とします。これはURLを書き換えないことを意味します。要求を拒否するときには、書き換える理由はありません。F|forbidden - RewriteRule Flags - Apache HTTP Server Version 2.2

NEフラグ

RewriteRuleは書き換え時にURLエンコード (パーセントエンコード) を行います。そのためクエリ文字列に特殊文字を含むとき、URLが書き換えられた場合とそうではない場合でクエリが異なってしまいます。

http://example.com/index.html?q=%E3%81%82

 ↓ (クエリの「%E3%81%82」をURLエンコード。「%」の部分が「%25」になる)

http://example.com/index.html?q=%25E3%2581%2582

この問題はNE (noescape) フラグを指定して、エスケープを抑制することで解決できます。Pukiwiki移転の際に便利なmod_rewriteの設定メモ

RewriteRule ^(.*)$ http://example.com/$1 [NE]
NE|noescape - RewriteRule Flags - Apache HTTP Server

Rフラグ

PatternがURLのパスに一致した場合、ドキュメントルート以下のすべてのURLがSubstitutionに書き換えられます。よってルールが、

RewriteRule bb zz [R]

の場合、URLに「bb」が含まれているならば、ドキュメントルート以下のURLが「zz」となります。

http://example.com/aabbcc
 ↓
http://example.com/home/aaa/www/zz

このときPatternによって書き換えられる範囲は、RewriteBaseディレクティブで設定できます。RewriteBase Directive - mod_rewrite - Apache HTTP Server

RewriteBase /
RewriteRule bb zz [R]

この場合は、次のようになります。

http://example.com/aabbcc
 ↓
http://example.com/zz

Pattern正規表現として評価されるため、

RewriteBase /
RewriteRule ^[0-9]+ z$0 [R]

とすると、次のように書き換えられます。

http://example.com/123A
 ↓
http://example.com/z123

Fフラグ

RewriteRule \.exe - [F]

拡張子が.exeであるファイルへのアクセスを禁止し、403を返します。

Gフラグ

RewriteRule oldproduct - [G]

パスにoldproductが含まれるならば、410を返します。

利用例

静的URL (static URLs)

URLのクエリ ストリングを、パス名の一部であるかのように偽装します。このようにして作成されたURLを、静的URLと呼称します。

この方法を用いると、たとえば

http://example.com/?a=1&b=2
(動的URL)

のようなクエリを含むURLを

http://example.com/a=1/b=2/
(静的URL)

のように表せます。

これを実現するにはアクセスされたときに本来のURLに書き換えるように、RewriteRuleで次のように指定します。この例ではクエリの数が変化することも考慮して、2パターンの書き換え規則を定義しています。

RewriteRule ^([^/]+)/ ?$1 [L]
RewriteRule ^([^/]+)/([^/]+)/ ?$1&$2 [L]

なおこのようにしてURLを書き換えた場合、静的URLが相対パスの基準となります。そのため画像や他ページへのリンクが相対パスで記述されている場合には、パスがずれます。

連続したスラッシュの除去

example.com/a//b/のようなURLを、example.com/a/b/に書き換える方法を考えます。

RewriteCond %{THE_REQUEST} //+
RewriteRule ^(.*)$ /$1 [R=301,L]

%{THE_REQUEST}はHTTPリクエストの"GET /a//b/ HTTP/1.1"のような内容であり、そこに正規表現の"//+"が一致したならば、パス全体を書き換えます。そしてRewriteRuleで書き換えるときに、複数のスラッシュは1つに切り詰められます。

書き換えず、削除したものとして通知するならば次のようにします。

RewriteCond %{THE_REQUEST} //+
RewriteRule .? - [G]

連続するスラッシュへの対応は、サイトによって異なります。

URL レスポンス
https://www.w3.org/policies/privacy/
https://www.w3.org/policies//privacy/
404
https://policies.google.com/privacy/key-terms
https://policies.google.com/privacy//key-terms
404
https://privacy.microsoft.com/ja-jp//privacystatement 200