Apache HTTP サーバ バージョン 2.5

このドキュメントは mod_rewrite
リファレンスドキュメントを補足するものです。
mod_rewrite を使用してリクエストをリダイレクトおよびリマッピング
する方法を説明します。mod_rewrite の一般的な使用例を多数含んでおり、
それぞれの動作についての詳細な説明も含まれています。
旧 URL から新 URL へ (内部)
旧 URL から新 URL への書き換え (外部)
リソースの別サーバへの移動
静的から動的へ
ファイル拡張子変更の後方互換性
正規ホスト名
複数のディレクトリでのページ検索
地理的に分散されたサーバへのリダイレクト
正規 URL
DocumentRoot の移動
フォールバックリソース
クエリ文字列の書き換え最近ページ foo.html を bar.html に
リネームし、後方互換性のために旧 URL も提供したいとします。
ただし、旧 URL のユーザにはページがリネームされたことを
気づかせたくありません - つまり、ブラウザのアドレスが
変更されないようにします。
以下のルールで旧 URL を内部的に新しいものに書き換えます:
RewriteEngine on RewriteRule "^/foo\.html$" "/bar.html" [PT]
再び、最近ページ foo.html を bar.html
にリネームし、後方互換性のために旧 URL を提供したいとします。
しかし今回は、旧 URL のユーザに新しい URL を知らせたい、
つまりブラウザの Location フィールドも変更されるようにしたいとします。
新しい URL への HTTP リダイレクトを強制し、ブラウザと ユーザの表示を変更します:
RewriteEngine on RewriteRule "^/foo\.html$" "bar.html" [R]
この例では、上記の内部の例と
対比して、単純に Redirect ディレクティブを使用できます。
mod_rewrite は、前の例でクライアントからリダイレクトを
隠すために使用されました:
Redirect "/foo.html" "/bar.html"
リソースが別のサーバに移動した場合、人々がブックマークを 更新する間、旧サーバでも URL がしばらく機能し続けるように したいとします。
mod_rewrite を使用してこれらの URL を新しいサーバに
リダイレクトできますが、Redirect や RedirectMatch ディレクティブの
使用も検討してください。
#With mod_rewrite RewriteEngine on RewriteRule "^/docs/(.+)" "http://new.example.com/docs/$1" [R,L]
#With RedirectMatch RedirectMatch "^/docs/(.*)" "http://new.example.com/docs/$1"
#With Redirect Redirect "/docs/" "http://new.example.com/docs/"
静的ページ foo.html を動的バリアント
foo.cgi にシームレスに、つまりブラウザ/ユーザに
気づかれずに変換するにはどうすればよいでしょうか。
URL を CGI スクリプトに書き換え、ハンドラを
cgi-script に強制して、CGI プログラムとして
実行されるようにします。
これにより、/~quux/foo.html へのリクエストは
内部的に /~quux/foo.cgi の呼び出しに
つながります。
RewriteEngine on RewriteBase "/~quux/" RewriteRule "^foo\.html$" "foo.cgi" [H=cgi-script]
document.YYYY から document.XXXX への
移行後、例えば .html ファイル群を .php に
変換した後に、URL の後方互換性 (仮想的にまだ存在する状態) を
どのように保つことができるでしょうか?
URL は旧拡張子から新拡張子に書き換えられますが、新拡張子の ターゲットファイルが存在し、かつ旧拡張子の元のファイルが 存在しない場合のみです。それ以外の場合、URL はそのまま 変更されません。
# backward compatibility ruleset for
# rewriting document.html to document.php
# when and only when document.php exists
<Directory "/var/www/htdocs">
RewriteEngine on
RewriteBase "/var/www/htdocs"
RewriteCond "$1.php" -f
RewriteCond "$1.html" !-f
RewriteRule "^(.*).html$" "$1.php"
</Directory>
この例では、mod_rewrite のあまり知られていない
機能を利用しています。ルールセットの実行順序を活用しています。
具体的には、mod_rewrite は RewriteCond ディレクティブを
評価する前に RewriteRule の左辺を評価します。
そのため、RewriteCond ディレクティブが評価される時点で
$1 はすでに定義されています。これにより、同じベースファイル名を使用して
元のファイル (document.html) とターゲットファイル
(document.php) の存在を確認できます。
このルールセットはディレクトリ単位のコンテキスト
(<Directory> ブロックまたは .htaccess ファイル内) で
使用するよう設計されているため、-f チェックは
正しいディレクトリパスを参照します。作業しているディレクトリベースを
指定するために RewriteBase
ディレクティブを設定する必要があるかもしれません。
最善の方法は mod_rewrite をまったく使わず、
非正規のホスト名用のバーチャルホストに配置した Redirect ディレクティブを使用する
ことです。
<VirtualHost *:80> ServerName undesired.example.com ServerAlias example.com notthis.example.com Redirect "/" "http://www.example.com/" </VirtualHost> <VirtualHost *:80> ServerName www.example.com </VirtualHost>
あるいは、<If>
ディレクティブを使用して実現することもできます:
(2.4 以降)
<If "%{HTTP_HOST} != 'www.example.com'">
Redirect "/" "http://www.example.com/"
</If>
あるいは、例えばサイトの一部を HTTPS にリダイレクトするには、 以下のようにします:
<If "%{SERVER_PROTOCOL} != 'HTTPS'">
Redirect "/admin/" "https://www.example.com/admin/"
</If>
何らかの理由でまだ mod_rewrite を使用したい場合 -
例えば、より大きな RewriteRule のセットと組み合わせる必要がある場合 -
以下のレシピのいずれかを使用できます。
ポート 80 以外で実行されているサイトの場合:
RewriteCond "%{HTTP_HOST}" "!^www\.example\.com" [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteCond "%{SERVER_PORT}" "!^80$"
RewriteRule "^/?(.*)" "http://www.example.com:%{SERVER_PORT}/$1" [L,R,NE]
ポート 80 で実行されているサイトの場合:
RewriteCond "%{HTTP_HOST}" "!^www\.example\.com" [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteRule "^/?(.*)" "http://www.example.com/$1" [L,R,NE]
すべてのドメイン名に対してこれを汎用的に行いたい場合 - つまり、example.com のすべての可能な値に対して example.com を www.example.com にリダイレクトしたい場合 - 以下のレシピを使用できます:
RewriteCond "%{HTTP_HOST}" "!^www\." [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteRule "^/?(.*)" "http://www.%{HTTP_HOST}/$1" [L,R,NE]
これらのルールセットは、メインサーバ設定ファイルまたはサーバの
DocumentRoot に配置した
.htaccess ファイルのいずれでも動作します。
特定のリソースが複数の場所に存在する可能性があり、 リクエスト時にそれらの場所でリソースを検索したいとします。 おそらく最近ディレクトリ構造を再編成し、コンテンツを 複数の場所に分割したためです。
以下のルールセットは 2 つのディレクトリでリソースを検索し、 どちらにも見つからない場合は、リクエストされた場所からそのまま 提供しようとします。
RewriteEngine on
# first try to find it in dir1/...
# ...and if found stop and be happy:
RewriteCond "%{DOCUMENT_ROOT}/dir1/%{REQUEST_URI}" -f
RewriteRule "^(.+)" "%{DOCUMENT_ROOT}/dir1/$1" [L]
# second try to find it in dir2/...
# ...and if found stop and be happy:
RewriteCond "%{DOCUMENT_ROOT}/dir2/%{REQUEST_URI}" -f
RewriteRule "^(.+)" "%{DOCUMENT_ROOT}/dir2/$1" [L]
# else go on for other Alias or ScriptAlias directives,
# etc.
RewriteRule "^" "-" [PT]
ウェブサイトの多数のミラーがあり、アクセス元の国に最も近い ミラーにリダイレクトしたいとします。
リクエスト元のクライアントのホスト名を参照して、どの国から アクセスしているかを判定します。IP アドレスの検索ができない場合は、 デフォルトサーバにフォールバックします。
使用したいサーバのリストを構築するために RewriteMap ディレクティブを
使用します。
HostnameLookups on
RewriteEngine on
RewriteMap multiplex "txt:/path/to/map.mirrors"
RewriteCond "%{REMOTE_HOST}" "([a-z]+)$" [NC]
RewriteRule "^/(.*)$" "${multiplex:%1|http://www.example.com/}$1" [R,L]
## map.mirrors -- マルチプレクシングマップ
de http://www.example.de/
uk http://www.example.uk/
com http://www.example.com/
##EOF##
HostNameLookups が
on に設定されていることに依存しており、
パフォーマンスに大きな影響を与える可能性があります。RewriteCond
ディレクティブは、リクエスト元のクライアントのホスト名の最後の
部分 (国コード) をキャプチャし、後続の RewriteRule はその値を
使用してマップファイルから適切なミラーホストを検索します。
一部のウェブサーバでは、リソースに対して複数の URL が存在します。 通常、正規の URL (実際に使用および配布される URL) と、単なる ショートカット、内部用の URL 等があります。ユーザがリクエストで どの URL を提供したかに関係なく、最終的にブラウザのアドレスバーに 正規の URL が表示されるようにしたいとします。
すべての非正規 URL に対して外部 HTTP リダイレクトを行い、
ブラウザの表示を修正し、以降のすべてのリクエストに反映させます。
以下のルールセット例では、/puppies と
/canines を正規の /dogs に
置き換えます。
RewriteRule "^/(puppies|canines)/(.*)" "/dogs/$2" [R]
RedirectMatch "^/(puppies|canines)/(.*)" "/dogs/$2"
DocumentRoot の移動 ¶通常、ウェブサーバの DocumentRoot
は URL "/" に直接対応します。
しかし、このデータが最優先ではない場合も多くあります。例えば、
訪問者がサイトに最初にアクセスしたときに特定のサブディレクトリ
/about/ に移動させたい場合があります。これは以下の
ルールセットで実現できます:
URL / を /about/ にリダイレクトします:
RewriteEngine on RewriteRule "^/$" "/about/" [R]
これは RedirectMatch
ディレクティブでも処理できることに注意してください:
RedirectMatch "^/$" "http://example.com/about/"
この例はルート URL のみを書き換えることに注意してください。つまり、
http://example.com/ へのリクエストは書き換えますが、
http://example.com/page.html へのリクエストは書き換えません。
実際にドキュメントルートを変更した場合 - つまり、コンテンツの
すべてが実際にそのサブディレクトリにある場合 - URL を
書き換えるよりも、単に DocumentRoot
ディレクティブを変更するか、すべてのコンテンツを 1 つ上のディレクトリに
移動する方がはるかに望ましいです。
バージョン 2.2.16 以降では、このために FallbackResource ディレクティブを
使用してください:
<Directory "/var/www/my_blog"> FallbackResource index.php </Directory>
ただし、以前のバージョンの Apache や、これよりも複雑なニーズがある 場合は、以下の書き換えセットのバリエーションを使用して同じことを 実現できます:
<Directory "/var/www/my_blog">
RewriteBase "/my_blog"
RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-f
RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-d
RewriteRule "^" "index.php" [PT]
</Directory>
一方、リクエストされた URI をクエリ文字列引数として index.php に 渡したい場合は、その RewriteRule を以下に置き換えることができます:
RewriteRule "(.*)" "index.php?$1" [PT,QSA]
これらのルールセットは .htaccess ファイルでも
<Directory> ブロックでも使用できることに注意してください。
このセクションの多くの解決方法は同じ条件を使用し、マッチした値を %2 バックリファレンスに残します。%1 はクエリ文字列の先頭 (対象キーまで)、 %3 は残りの部分です。この条件は、柔軟性のため、また置換で二重の '&&' を避けるためにやや複雑です。
# Remove mykey=???
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
RewriteRule "(.*)" "$1?%1%3"
# Copy from query string to PATH_INFO
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
RewriteRule "(.*)" "$1/products/%2/?" [PT]
# Capture the value of mykey in the query string
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
RewriteCond "%2" !=not-so-secret-value
RewriteRule "(.*)" "-" [F]
# The desired URL might be /products/kitchen-sink, and the script expects # /path?products=kitchen-sink. RewriteRule "^/?path/([^/]+)/([^/]+)" "/path?$1=$2" [PT]