yoshiki 2003/10/21 11:10:05 Added: htdocs/manual/mod mod_rewrite.html.html mod_rewrite.html.ja.jis Removed: htdocs/manual/mod mod_rewrite.html Log: New Japanese translation. Finally finished reviewing this document. Sorry for taking so much time to review. Submitted by: HOTTA Michihide Reviewed by: Yoshiki Hayashi, Nobuyuki Morita Revision Changes Path 1.1 httpd-docs-1.3/htdocs/manual/mod/mod_rewrite.html.html Index: mod_rewrite.html.html =================================================================== 1.1 httpd-docs-1.3/htdocs/manual/mod/mod_rewrite.html.ja.jis Index: mod_rewrite.html.ja.jis =================================================================== Apache module mod_rewrite

mod_rewrite モジュール
URL 書き換えエンジン

このモジュールは、要求された URL をリアルタイムで書き換えるための、 ルールベースの書き換えエンジンを提供します。

ステータス: Extension
ソースファイル: mod_rewrite.c
モジュール識別子: rewrite_module
互換性: Apache 1.2 以降で使用可能



概要

`` mod_rewrite のすばらしいところは、 Sendmail のような設定性と柔軟性を与えてくれるところだろう。 また、mod_rewrite のよくないところは、 Sendmail のような設定性と柔軟性を与えてくれるところだろう。''
-- Brian Behlendorf
Apache Group
`` 膨大な設定例やドキュメントがあるにもかかわらず、 mod_rewrite は黒魔術である。かなりイケてるっぽい黒魔術だが、 やっぱり黒魔術である。''
-- Brian Moore
bem@news.cmc.net
URL を操作するためのスイス製のアーミーナイフ、mod_rewrite へようこそ!

このモジュールは、(正規表現パーサに基づく) ルールベースの書き換えエンジンを使い、要求された URL を適宜書き換えます。サポートするルールの数、 および各ルールを適用する際のルール条件の数に制限はなく、 本当に柔軟でかつ強力な URL 操作メカニズムを提供します。この URL 操作に先立ち、次のようにいろいろな評価を行うことができます。 例えばサーバ変数、環境変数、HTTP ヘッダ、タイムスタンプ、 さらに外部データベースの検索結果までを評価の対象として、 各種のフォーマットを使った細粒度の URL マッチングを実現できます。

このモジュールは、サーバ単位のコンテキスト (httpd.conf) およびディレクトリ単位のコンテキスト (.htaccess) において (PATH-INFO 部分を含む) フル URL に対する操作を行いますが、 さらに結果としてクエリー文字列部分を生成することもできます。 出力された結果を内部のサブプロセスや外部リクエストのリダイレクション、 さらには内部のプロキシ処理ルーチンに渡すこともできます。

ただ、これらすべての機能や柔軟性が、 欠点である複雑さの元にもなっています。なので、このモジュール 全体を一日程度で覚えようなどとは思わないほうがいいでしょう。

このモジュールは 1996 年の 4 月に

Ralf S. Engelschall
rse@engelschall.com
www.engelschall.com

らにより考案されてオリジナルが書かれ、
1997 年の 7 月に、The Apache Group に対して独占的に贈呈されました。


目次

内部処理

設定ディレクティブ

その他

内部処理


このモジュールの内部処理はとても複雑ですが、 ありがちなミスを避け、また全機能を活用できるように、 平均的ユーザに対しても一度は説明しておく必要があります。

API フェーズ

まずは、Apache が HTTP リクエストを処理する際に、 このモジュールがこのフェーズで行うことを理解しておかなければなりません。 Apache API では、これらの各フェーズに対するフックが提供されています。 mod_rewrite は以下の二つのフックを使います: HTTP リクエストが読まれた後でかつすべての認証が開始される前に使われる URL-to-filename 変換フック、そして、認証フェーズの後で ディレクトリごとの設定ファイル (.htaccess) が読まれた後、まだ content ハンドラが有効になる前に起動される Fixup フックです。

そして、あるリクエストが入って来て、Apache がこれに対応するサーバ (若しくはバーチャルサーバ) を決定した後に、書き換えエンジンは、 サーバごとの設定を元に、URL-to-filename フェーズですべての mod_rewrite ディレクティブの処理を開始します。 その後多少のステップを経て最後のデータディレクトリが見つかった時、 ディレクトリごとの mod_rewrite 設定ディレクティブが Fixup フェーズで起動されます。 この各々のタイミングの間に特に明らかな違いはないのですが、それでも mod_rewrite はいずれの時にも各 URL を新しい URL またはファイル名に書き換えます。これはこの API がデザインされた時に想定された使い方ではないのですが、Apache 1.x においてはこれが mod_rewrite が動ける唯一の方法でした。 この点をよりはっきりさせるために、以下の 2 点について覚えておいてください:

  1. mod_rewrite は URL を URL へ、URL をファイル名へ、 さらにファイル名をファイル名へと書き換えますが、API では現在のところ URL-to-filename フックのみを提供しています。 Apache 2.0 ではそれまでにはなかった二つのフックが追加され、 処理がより明確になりました。 しかしこの点ではユーザにとっての不利益はなく、 単に覚えておくべき事実としては: Apache は URL-to-filename フックにおいて API が意図する以上のことを行います。
  2. mod_rewrite では、信じられないことに、URL がファイル名に変換されてからずっと後に辿り着くところにある、 ディレクトリごとのコンテキストすなわち .htaccess ファイルの中で URL 操作を行えるようになっていす。.htaccess ファイルはファイルシステム中にあるために 処理の流れはすでにこの段階まで到達しているので、 このようになっているのです。つまりこの時点で API フェーズに従えば、どの URL を操作するにも既に遅きに失しているのです。 この鶏と卵問題を打開するため、mod_rewrite ではちょっとしたトリックを使っています: ディレクトリごとのコンテキストで URL / ファイル名の操作を行う際、 mod_rewrite はまずファイル名を対応する URL に戻し (これは通常不可能ですが、これを可能にするトリックについては RewriteBase を見てください) 、その新しい URL で内部的に新しいサブリクエストを生成しているのです。これで API フェーズ処理が再度起動されます。

    このように、mod_rewrite は複雑なステップを ユーザに対して全般に透過的にしようとがんばっていますが、 とりあえず以下のことは覚えておくべきでしょう: サーバごとのコンテキストにおける URL 操作は非常に高速でかつ効率が良いのに対し、 ディレクトリごとの書き換えは、 この鶏と卵の問題のため遅い上に低効率です。しかしこれは、 mod_rewrite がごく平均的なユーザに提供できる、 (ローカルに制限された) URL 操作のための唯一の方法なのです。

これら二つの点を忘れないでください!

ルールセット処理

これら二つの API フェーズで mod_rewrite が起動されると、 mod_rewrite はまず自分自身の設定用構造体 (これは起動時のサーバごとのコンテキストか、Apache カーネルがディレクトリ間を探索する途中のディレクトリごとの コンテキストか、のいずれかにより生成される) より構成されたルールセットを読み込みます。そしてその中に入っている ルールセット (条件を伴う一つ以上のルールの集まり)とともに URL 書き換えエンジンが開始されます。URL 書き換えエンジン自体は、 双方の設定コンテキストで全く同じように動作します。 最終結果の処理が異なるだけです。

ルールセット中のルールの書き順は重要です。 これは、書き換えエンジンはそれらを特別な (かつ、あまり分かりやすいとは言えない) 順序で処理するからです。 ルールは以下のように処理されます: 書き換えエンジンはルール (RewriteRuleディレクティブ) を一つずつなめながら ルールセット中をループしますが、あるルールがマッチしたら、 それに対応する条件 (RewriteCondディレクティブ) がある間その中をループします。 歴史的な理由によりまず条件が与えられるため、 制御フローがちょっとくどくなっています。詳細は図 1 をご覧ください。

[表示するにはグラフィック機能が必要です]
図 1: 書き換えルールセットにおける制御フロー

もうお分かりのように、まず URL を各ルールの Pattern に対してマッチングします。マッチしない場合、mod_rewrite はすぐにこのルールの処理を中止して次のルールを見に行きます。 Pattern にマッチすると、mod_rewrite はそれに対応する条件を探します。もし何もなければ、単に URL を Substitution 文字列から作られた新しい値に置換し、 ルールのループを続けます。何らかの条件があれば内部ループを開始し、 それらの条件が列挙されている順に処理を繰り返します。 条件文の場合はロジックが異なります: 現在の URL に対してはパターンのマッチングを行いません。その代わり、 まず変数を展開し、後方参照を行い、 検索テーブルをマッピングするなどしてテスト文字列 を生成し、それに対して条件パターンとのマッチングを行います。 パターンにマッチしない場合、条件の組み合わせ全体とそれに対応する ルールは成立しないことになります。パターンにマッチした場合、 次の条件が評価され、それが条件のある限り繰り返されます。 もしすべての条件にマッチすれば、URL は Substitution 文字列に置換され、処理が継続されます。

特殊文字のクウォート

Apache 1.3.20 では、テスト文字列Substitution 文字列の中の特殊文字は、その直前にバックスラッシュ ('\') を置くことでエスケープ (すなわち、それらの持つ特殊な意味を打ち消して、 通常の文字として扱うこと) できるようになっています。 例えば、置換対象文字列の中でも '\$' という文字列を使って本来のドル記号を入れることができるわけです。 これにより、mod_rewrite がそれを後方参照として扱おうとするのを防ぐことができるわけです。

正規表現の後方参照を使う

ここでひとつ覚えておいて欲しいことがあります: Pattern の中や CondPattern のうちのどこかで括弧を使えば、文字列 $N%N で使える後方参照が内部的に生成されます (後述)。これらは Substitution 文字列やテスト文字列を生成するのに使えます。図 2 では、この後方参照が転送されて展開される場所について解説します。
[表示するにはグラフィック機能が必要です]
図 2: ルールを通した後方参照の流れ

これまでは mod_rewrite の内部処理に関する短期集中コースでした。 ここからは使用可能なディレクティブに関することが書かれています。 それらを読むときにここまでの知識が役立つはずです。


設定ディレクティブ


RewriteEngine

書式: RewriteEngine on|off
デフォルト: RewriteEngine off
コンテキスト: サーバ設定ファイル、 バーチャルホスト、ディレクトリ、.htaccess
オーバーライド: FileInfo
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2

RewriteEngine ディレクティブを使うと、 実行時の書き換えエンジンを有効にしたり無効にしたりできます。これが off に設定されていると、このモジュールは実行時の 処理を一切行いません。また SCRIPT_URx 環境変数の更新さえもしなくなります。

RewriteRule を全部コメントアウトしたりしないで、 このディレクティブを使ってくださいね。

デフォルトでは、rewrite の設定は継承されないので注意してください。 つまり、この機能を使いたいと思うバーチャルホストごとに RewriteEngine on ディレクティブを書かなければいけないということです。


RewriteOptions

書式: RewriteOptions オプション
デフォルト: RewriteOptions MaxRedirects=10
コンテキスト: サーバ設定ファイル、 バーチャルホスト、ディレクトリ、.htaccess
オーバーライド: FileInfo
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2。MaxRedirects は Apache 1.3.28 以降で使用可能

RewriteOptions ディレクティブは、 現在のサーバ単位もしくはディレクトリ単位の設定で使用する、 特別なオプションをセットします。 Option 文字列は以下のいずれかです:

inherit
これは、現在の設定値を親の設定値から強制的に継承させます。 これにより、仮想サーバ単位のコンテキストにおいて、 メインサーバのマップ、条件、ルールが継承されることになります。 また、ディレクトリ単位のコンテキストでは、親ディレクトリの .htaccess 設定に記述されている条件やルールが継承されることになります。
MaxRedirects=number
ディレクトリ毎の RewriteOptions による内部リダイレクトの 無限ループを防ぐために、mod_rewrite はリダイレクトの 上限に達するとリクエストを中止し、500 Internal Server Error を応答として 返します。一つのリクエストに対して本当に 10 を越えるリダイレクトが必要な 場合は、望みの値まで増加させることができます。

RewriteLog

書式: RewriteLog file-path
デフォルト: なし
コンテキスト: サーバ設定ファイル、 バーチャルホスト
オーバーライド: 適用不可
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2
 

RewriteLog ディレクティブは、 行なわれたすべての書き換え動作を サーバがログに書き込むための ファイル名を設定します。この名前がスラッシュ ('/') で始まらない場合は Server Root からの相対パスであると見なされます。このディレクティブは サーバ単位の設定の中で一度だけ記述されるべきものです。

注意: 書き換え動作のロギングを抑制するために file-path/dev/null にするのはお勧めできません。これは、 書き換えエンジンは実際にはログファイルへの出力を行わないのに、 未だ内部的にはログファイルへの出力を生成しているからです。 これは管理者に何の利点ももたらさずに サーバのパフォーマンスを低下させるだけです! ロギングを抑止する場合は RewriteLog ディレクティブをコメントアウトするか、 RewriteLogLevel 0 を使うようにしてください!
セキュリティ: ログファイルを格納するディレクトリが、 サーバを起動するユーザ以外にも書き込み可能である場合に、 なぜセキュリティが脅かされるかについての詳しい説明は、 Apache のセキュリティの こつ ドキュメントをご覧ください。

例:

  RewriteLog "/usr/local/var/apache/logs/rewrite.log"
  

RewriteLogLevel

書式: RewriteLogLevel Level
デフォルト: RewriteLogLevel 0
コンテキスト: サーバ設定ファイル、 バーチャルホスト
オーバーライド: 適用不可
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2

RewriteLogLevel ディレクティブでは、 書き換え用のログファイルの冗長レベルを指定します。 デフォルトのレベルは 0 で、これは一切ログを書かないことを意味します。一方 9 もしくはそれ以上を指定すると、 事実上ほとんどすべての動作についてログが収集されます。

書き換えのログを取らないようにするには、単に Level を 0 にします。これで書き換えに関するすべてのログが無効となります。

注意: Level に大きな値を指定すると、Apache サーバの動作速度が劇的に低下します! 書き換え時のログファイルで Level に 2 以上の値を指定するのはデバッグ時のみにしておいてください!

例:

  RewriteLogLevel 3
  

RewriteLock

書式: RewriteLock file-path
デフォルト: なし
コンテキスト: サーバ設定ファイル
オーバーライド: 適用不可
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.3

このディレクティブは、mod_rewrite が RewriteMap プログラムと通信するのに必要な、 同期用ロックファイルの名前をセットします。RewriteMap で プログラムを使いたい場合には、このロックファイルに(NFS マウントされたデバイスではなく)ローカルパスを設定します。 それ以外のタイプの RewriteMap を使う場合には、 設定する必要はありません。


RewriteMap

書式: RewriteMap MapName MapType:MapSource
デフォルト:デフォルトでは使用されない
コンテキスト: サーバ設定ファイル、 バーチャルホスト
オーバーライド: 適用不可
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2 (一部のみ), Apache 1.3

RewriteMap ディレクティブは、 マッピング関数を使ってルール置換文字列の内部で使える 書き換えマップを定義します。これにより、 キーを検索する際に、フィールドを挿入したり置換したりできます。 検索対象にはいろいろなタイプが使えます。

MapName はマップの名前です。以下の書式のどちらかにより、 書き換えルールの置換文字列で使われる マッピング関数を指定するのに使われます。

${ MapName : LookupKey }
${ MapName : LookupKey | DefaultValue }
このような書式が現れると、MapName という名前のマップの中のキー LookupKey が検索されます。 キーが見つかれば、このマップ関数の書式の部分は SubstValue により置換されます。キーが見つからない場合、 DefaultValue があればそれで置換され、DefaultValue が指定されていなければ空文字列に置換されます。

以下のような MapTypeMapSource を使った組み合わせを使用できます:

  • 標準のプレーンテキスト
    MapType: txt, MapSource: Unix ファイルシステムの有効な通常ファイルへのパス

    これは標準の書き換えマップ機能です。 MapSource は空白行やコメント行(行頭が '#' 文字で始まる行)、若しくは以下のような ペアが一行毎に書かれているような普通の ASCII ファイルです。

    MatchingKey SubstValue

    例:

      ##
      ##  map.txt -- rewriting map
      ##
      
      Ralf.S.Engelschall    rse   # Bastard Operator From Hell
      Mr.Joe.Average        joe   # Mr. Average
      
      RewriteMap real-to-user txt:/path/to/file/map.txt
      
  • ランダムなプレーンテキスト
    MapType: rnd, MapSource: Unix ファイルシステムの有効な通常ファイルへのパス

    これは前述の標準プレーンテキストとほぼ同じですが、それに加えて 専用の後処理機能を持っています: 値を検索した後、その値は ``or'' の意味を持つ ``|'' 文字にしたがってパースされます。 つまりこれらは変換候補を羅列しており、 実際に返される値はこれらの中からランダムに選ばれます。 これは一見妙な感じがして意味がなさそうに思えますが、 実際に検索した値がサーバ名になるような リバースプロキシを用いた負荷分散用に 設計されています。 例えば:

      ##
      ##  map.txt -- rewriting map
      ##
      
      static   www1|www2|www3|www4
      dynamic  www5|www6
      
      RewriteMap servers rnd:/path/to/file/map.txt
      
  • ハッシュファイル
    MapType: dbm, MapSource: Unix ファイルシステムの有効な通常ファイルへのパス

    ファイルの内容の意味はプレーンテキストフォーマット と同じですが、 高速な検索を行うために最適化が施された NDBM フォーマットというバイナリファイル をソースとして使うこともできます。このようなファイルは、 NDBM ツールを使ったり、以下のような perl スクリプトを使って作ることができます。

      #!/path/to/bin/perl
      ##
      ##  txt2dbm -- convert txt map to dbm format
      ##
      
      use NDBM_File;
      use Fcntl;
      
      ($txtmap, $dbmmap) = @ARGV;
      
      open(TXT, "<$txtmap") or die "Couldn't open $txtmap!\n";
      tie (%DB, 'NDBM_File', $dbmmap,O_RDWR|O_TRUNC|O_CREAT, 0644) or die "Couldn't create $dbmmap!\n";
      
      while (<TXT>) {
        next if (/^\s*#/ or /^\s*$/);
        $DB{$1} = $2 if (/^\s*(\S+)\s+(\S+)/);
      }
      
      untie %DB;
      close(TXT);
      
      $ txt2dbm map.txt map.db
      
  • 内部関数
    MapType: int, MapSource: 内部 Apache 関数

    ソースとして、内部 Apache 関数を使うこともできます。 現時点ではエンドユーザが自分用に独自のものを作ることはできませんが、 以下のものが用意されています。

    • toupper:
      見つかったキーをすべて大文字に変換する。
    • tolower:
      見つかったキーをすべて小文字に変換する。
    • escape:
      見つかったキーの中の特殊文字を 16 進エンコーディングに変換する。
    • unescape:
      見つかったキーの中の 16 進エンコーディングを特殊文字に戻す。
  • 外部の書き換えプログラム
    MapType: prg, MapSource: Unix ファイルシステムの有効な通常ファイルへのパス

    ソースにはマップファイル以外にプログラムを使うこともできます。 プログラムは好きな言語を選択することができますが、 作成されたものは実行可能ファイル (すなわちオブジェクトコード、若しくは 1 行目に ' #!/path/to/interpreter' のようなマジッククッキートリックの入ったスクリプト) でなければなりません。

    このプログラムは Apache サーバの起動時に一度だけ起動され、 stdin および stdout ファイルハンドルを通して、書き換えエンジンとのやりとりを行います。 このプログラムは、各々のマップ関数の検索のたびに、 検索対象のキーを、改行文字で終端された文字列として stdin から受け取ります。 そして、値が見つかれば改行文字で終端された文字列を返し、 見つからなければ (すなわち、与えられたキーに対応する値がない)、 4 文字の文字列 ``NULL'' を返さなければなりません。 1:1 のマップ(すなわちキー == 値) を実現する単純なプログラム例としては、以下のようになります:

      #!/usr/bin/perl
      $| = 1;
      while (<STDIN>) {
          # ...put here any transformations or lookups...
          print $_;
      }
      

    しかし、十分に気をつけてほしいことがあります:

    1. ``Keep it simple, stupid (単純なままにしておけ、馬鹿野郎!)」'' (KISS) という原則に従ってください。もしこのプログラムがハングしてしまうと、 そのルールが現れた瞬間に Apache サーバ自体がハングしてしまいます。
    2. ありがちな間違いとしては: stdout に対してバッファされた入出力を使ってはなりません! これをやると無限ループにハマってしまいます! だから上のコードでも ``$|=1'' とやってるんです…。
    3. RewriteLock ディレクティブを使ってロックファイルを定義し、mod_rewrite が当該プログラムへの通信に同期を取れるようにしてください。 デフォルトではそのような同期は行われません。
RewriteMap ディレクティブは何度でも書くことができます。 マッピング関数ごとに RewriteMap を使って書き換え用マップファイルを宣言します。 ディレクトリのコンテキスト内部でマップを宣言する ことはできませんが、ディレクトリのコンテキストでこのマップを 使うことはもちろん可能です。
注意: プレーンテキストと DBM フォーマット のファイルに関しては、マップファイルの mtime が変更されるかまたはサーバが再起動されるまで、 検索されたキーはメモリ内にキャッシュされます。 ですから、毎回のリクエストで使われる マップ関数をルール内に書くことができます。 外部検索は一度しか行われないので、これでも大丈夫なのです。

RewriteBase

書式: RewriteBase URL-path
デフォルト: デフォルトは物理 ディレクトリのパス
コンテキスト: ディレクトリ, .htaccess
オーバーライド: FileInfo
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2

RewriteBase ディレクティブは、ディレクトリごとの書き換えにおいてベースとなる URL を明示的に指定するものです。以下で示すように、 RewriteRule はディレクトリごとの設定ファイル (.htaccess) で使えます。 そこでは、これはローカルに振る舞います。すなわち、 この処理段階ではローカルディレクトリの接頭辞が取り除かれ、 その残りの部分に対してのみ書き換えルールが適用されます。 そして書き換え後、取り除かれた部分が再度自動的にパスに付加されます。

新しい URL に対する置換が発生すると、このモジュールは当該 URL をサーバ処理に再投入しなければなりません。これを行うには、対応する URL の接頭辞、若しくは URL のベースが何なのかを知る必要があります。 デフォルトではこの接頭辞はファイルパスそのものに対応しています。 しかしながら、ほとんどの Web サイトでは URL は物理的なファイル名のパスを直接指している *わけではない* ので、一般的にこの仮定は間違っていることになります。 そのため、RewriteBase ディレクティブを使って正しい URL の接頭辞を指定してやらなければならないのです。

注意: もしあなたの Web サーバの URL が物理的なファイルパスを直接指しているのでなければ、 RewriteRule ディレクティブを使おうとしているディレクトリすべてにおいて、各 .htaccess ファイルで RewriteBase ディレクティブを使わなければなりません。

例:

以下は、ディレクトリごとの設定ファイルだと思ってください:
  #
  #  /abc/def/.htaccess -- ディレクトリ /abc/def のためのディレクトリ別設定ファイル
  #  参考:/abc/def は パス /xyz の物理パス名である。すなわちサーバには
  #       'Alias /xyz /abc/def' といったディレクティブの設定がある。
  #
  
  RewriteEngine On
  
  #  物理的なパスの接頭辞である /abc/def でなく、/xyz を通して
  #  アクセスしていることをサーバに知らせる。
  RewriteBase   /xyz
  
  #  これが書き換えルール
  RewriteRule   ^oldstuff\.html$  newstuff.html
  

上記の例では、/xyz/oldstuff.html へのリクエストで物理ファイル /abc/def/newstuff.html への正しい書き換え操作が行われます。

Apache ハッカーのための注釈:
以下のリストで示しているのは、 内部処理ステップに関する詳細情報です:
  リクエスト:
    /xyz/oldstuff.html
  
  内部処理:
    /xyz/oldstuff.html     -> /abc/def/oldstuff.html  (per-server Alias)
    /abc/def/oldstuff.html -> /abc/def/newstuff.html  (per-dir    RewriteRule)
    /abc/def/newstuff.html -> /xyz/newstuff.html      (per-dir    RewriteBase)
    /xyz/newstuff.html     -> /abc/def/newstuff.html  (per-server Alias)
  
  処理結果:
    /abc/def/newstuff.html
  
  
これは非常に複雑に見えるものの、Apache の内部処理に関する正しい動きです。なぜなら、 ディレクトリ単位の書き換え操作は処理の中において 来るのが遅すぎるからです。そのため書き換えが行なわれると、 (書き換えが行われた)リクエストは Apache カーネルの中に再投入されなければなりません! しかし: これは深刻なオーバーヘッドを伴うように見えるものの、 実際には大した事はありません。この再投入は完全に Apache サーバの内部で起こる事であり、Apache の内部におけるその他の多くの動作中にも同様のことが 起こっているからです。なので、 この設計と実装は正しいものなのです。

RewriteCond

書式: RewriteCond TestString CondPatter
デフォルト: なし
コンテキスト: サーバ設定ファイル、 バーチャルホスト、ディレクトリ、.htaccess
オーバーライド: FileInfo
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2 (部分的に), Apache 1.3

RewriteCond ディレクティブはルール条件を定義します。 RewriteRule ディレクティブの前に一つ以上の RewriteCond ディレクティブを置くことができます。 それ以降の書き換えルールは、そのパターンが現在の URI の状態とマッチし、かつこれらの追加条件が 適用される場合にのみ使われます。

TestStringは文字列であり、プレーンテキストに加え、 以下の拡張構造を持つことができます:

  • RewriteRule 後方参照: この書式で、後方参照を表します。
    $N
    (0 <= N <= 9) これは、対応する RewriteRule ディレクティブ(現在のRewriteCond ディレクティブのブロックの次にあるもの)の (括弧で囲んで)グループ化されたパターンへのアクセスを提供します。
  • RewriteCond 後方参照: この書式で、後方参照を表します。
    %N
    (1 <= N <= 9) これは、現在の条件ブロックの中でRewriteCond ディレクティブ に最後にマッチした (括弧で囲んで)グループ化されたパターンへのアクセスを提供します。
  • RewriteMap 拡張: この書式で、拡張を表します。
    ${mapname:key|default}
    詳細は RewriteMap のドキュメントを参照のこと。
  • サーバ変数: 以下は変数を表します。
    %{ 変数名 }
    変数名は以下の一覧にある文字列のいずれかです:
    HTTP ヘッダ:

    HTTP_USER_AGENT
    HTTP_REFERER
    HTTP_COOKIE
    HTTP_FORWARDED
    HTTP_HOST
    HTTP_PROXY_CONNECTION
    HTTP_ACCEPT

    コネクション & リクエスト:

    REMOTE_ADDR
    REMOTE_HOST
    REMOTE_USER
    REMOTE_IDENT
    REQUEST_METHOD
    SCRIPT_FILENAME
    PATH_INFO
    QUERY_STRING
    AUTH_TYPE

    サーバ内部変数:

    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

    注意: これらの変数は、すべて同様の名前を持つ HTTP MIME ヘッダや Apache サーバの C 変数、または Unix システムの struct tm フィールドに対応します。 ほとんどのものは、マニュアルや CGI 仕様のどこかに説明があります。この中で mode_rewrite で特別な意味を持つものに以下のものがあります:

    IS_SUBREQ
    これは、サブリクエストを処理中は "true" に、そうでなければ "false" になります。 与えられたタスクを完了するために追加のファイルや URI を解決する必要があるモジュールは、 サブリクエストを生成する場合があります。
    API_VERSION
    これは現在の httpd のビルドにおける Apache モジュール API(サーバとモジュール間の内部インターフェース) のバージョンであり、include/ap_mmn.h で定義されています。 モジュール API のバージョンは使用している Apache のバージョン(例えば Apche 1.3.14 であれば 19990320:10) に対応しますが、 これは主にモジュールの作者が関心を持つものです。
    THE_REQUEST
    ブラウザからサーバに送られた HTTP リクエストの完全なもの(例えば、 "GET /index.html HTTP/1.1")。 これには、ブラウザから送られた追加ヘッダは一切含みません。
    REQUEST_URI
    HTTP リクエスト行でリクエストされたリソース (上記の例では "/index.html" がそれにあたります)。
    REQUEST_FILENAME
    リクエストにマッチしたファイルまたはスクリプトの、 完全なローカルファイルシステムのパス。

考慮事項:

  1. SCRIPT_FILENAME および REQUEST_FILENAME には同じ名前、 すなわち、Apache サーバの request_rec 内部構造体の中の filename フィールドの値が入っています。前者は単によく知られている CGI 変数名であるのに対し、後者は (request_rec フィールドの uri の値が入っている)REQUEST_URI に対応するものです。
  2. 変数に任意の環境変数を指定できる特別な書式 %{ENV:変数} があります。これは Apache の内部構造体若しくは(そこに存在しなければ)Apache サーバプロセスが発行する getenv() を通して検索されます。
  3. ヘッダに任意の HTTP MIME ヘッダ名を指定できる特別な書式 %{HTTP:ヘッダ}があります。これは HTTP リクエストから検索されます。 例: %{HTTP:Proxy-Connection} は HTTP ヘッダの ``Proxy-Connection:'' の値です。
  4. 前方参照を行なって内部の(URL ベースの) サブリクエストを実行して変数の最終値を決定する特別な書式 %{LA-U:変数} があります。 実際には API フェーズの後のほうでセットされるために、 現時点ではアクセスできないような変数を使って書き換えを 行ないたい場合に使用します。例えば、サーバ単位のコンテキスト (httpd.conf ファイル) で REMOTE_USER 変数にしたがって書き換えを行いたい場合には、 %{LA-U:REMOTE_USER} を使用しなければなりません。なぜなら、この変数は mod_rewrite が動作する URL 変換フェーズのにある認証フェーズで セットされるものだからです。一方、ディレクトリ単位のコンテキスト (.htaccess ファイル) では、mod_rewrite は API の Fixup フェーズを通して実装されており、 認証フェーズはこのフェーズのに行なわれるため、 そこでは単に %{REMOTE_USER} とすることができるます。
  5. 内部の(ファイル名ベースの) サブリクエストを実行して変数の最終値を決定する特別な書式 %{LA-F:変数} があります。 ほとんどの場合これは前述の LA-U と同じです。

CondPattern は、条件パターンで、 現在の TestString の実体に対して適用される正規表現です。 TestString は評価された後に CondPatternに対して マッチングが行なわれます。

備考: CondPatternは、 標準の拡張正規表現にいくつか追加を行ったものです:

  1. '!' 文字(エクスクラメーションマーク) をパターン文字列の前につけることで、 マッチしないパターンを指定できます。
  2. CondPattern のちょっとした変種もあります。 実際の正規表現文字列の代わりに以下のように使うことができます:
    • '<CondPattern' (字句の並び的に、より小さい)
      CondPattern を単なる文字列として扱い、 字句の並びとして TestString と比較します。 TestString が字句の並びとして CondPattern より小さい場合に真になります。
    • '>CondPattern' (字句の並び的に、より大きい)
      CondPattern を単なる文字列として扱い、 字句の並びとして TestString と比較します。 TestString が字句の並びとして CondPattern より大きい場合に真になります。
    • '=CondPattern' (字句の並び的に等しい)
      CondPattern を単なる文字列として扱い、 字句の並びとして TestString と比較します。 TestString が字句の並びとして CondPattern と等しい場合、すなわち、二つの文字列が (1 文字ずつ比較して)正確に等しい場合に真になります。 もし CondPattern が単なる"" (二つの引用符)であれば、 TestString は空文字列と比較されます。
    • '-d' (ディレクトリ (directory))
      TestString をパス名として扱い、それが存在して、 かつディレクトリであれば真。
    • '-f' (通常のファイル (file))
      TestString をパス名として扱い、それが存在して、 かつ通常のファイルであれば真。
    • '-s' (大きさ (size) のある通常のファイル)
      TestString をパス名として扱い、それが存在して、 かつ大きさが 0 より大きい通常ファイルであれば真。
    • '-l' (シンボリックリンク (symbolic link))
      TestString をパス名として扱い、それが存在して、 かつシンボリックリンクであれば真。
    • '-F' (サブリクエストを通した既存ファイル)
      TestString が有効なファイルであること、 そしてこのサーバにおいて、現時点で設定されているすべての アクセス制御を通して、そのパス名でアクセスできるかどうかを チェックします。これは内部のサブリクエストを使って チェックを行うので、注意して使わないとサーバの パフォーマンスを低下させることになりかねません!
    • '-U' (サブリクエストを通した既存 URL)
      TestString が有効な URL であること、 そしてこのサーバにおいて、現時点で設定されているすべての アクセス制御を通して、そのパス名でアクセスできるかどうかを チェックします。これは内部のサブリクエストを使って チェックを行うので、注意して使わないとサーバの パフォーマンスを低下させることになりかねません!
    注意: 以上すべてのテストについて、 エクスクラメーションマーク ('!') を前に置くことにより それらの意味を否定したマッチングを行なうことができます。

さらに、RewriteCond ディレクティブへの第三引数として CondPattern に特別な

[フラグ]
を追加することができます フラグは以下のものをカンマ区切りで並べたものです:
  • 'nocase|NC' (no case)
    これは大文字小文字を区別せずにテストします。すなわち、 展開されたTestStringCondPattern において、 'A-Z' および 'a-z' の間には違いはないものと見なされます。 このフラグはTestStringCondPattern の間の 比較においてのみ有効です。ファイルシステム上およびサブリクエスト のチェックでは意味を持ちません。
  • 'ornext|OR' (or next condition)
    ルール条件を結合するにあたり、暗黙の AND の代わりにローカルの OR を使います。典型的な例として、以下を参照してください:
      RewriteCond %{REMOTE_HOST}  ^host1.*  [OR]
      RewriteCond %{REMOTE_HOST}  ^host2.*  [OR]
      RewriteCond %{REMOTE_HOST}  ^host3.*
      RewriteRule ...これらのホストに関する特別な処理
      
    このフラグを使わない場合は、条件/ルールを 3 回書くことになってしまいます。

使用例:

リクエストの中の ``User-Agent:'' ヘッダに従って サイトのホームページの書き換えを行なうには、以下のようにします:
  RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
  RewriteRule  ^/$                 /homepage.max.html  [L]
  
  RewriteCond  %{HTTP_USER_AGENT}  ^Lynx.*
  RewriteRule  ^/$                 /homepage.min.html  [L]
  
  RewriteRule  ^/$                 /homepage.std.html  [L]
  
解釈: ブラウザとして(自分自身で 'Mozilla' と名乗っている) ネットスケープナビゲータを使う場合、フレームなどを含む max のホームページを見ることになります。(端末ベースの) Lynx ブラウザを使う場合は、画像やテーブルなどを含まない min のホームページが表示されます。それ以外のブラウザの場合は標準 (std) のページが表示されます。

RewriteRule

書式: RewriteRule Pattern Substitution
デフォルト: なし
コンテキスト: サーバ設定ファイル、 バーチャルホスト、ディレクトリ、.htaccess
オーバーライド: FileInfo
ステータス: Extension
モジュール: mod_rewrite.c
互換性: Apache 1.2 (partially), Apache 1.3

RewriteRule ディレクティブは、実際の書き換えを担当してくれる馬車馬です。 このディレクティブは複数回書くことができます。 各ディレクティブは一つの書き換えルールを定義します。 これらルールを定義する順序は重要です。 なぜなら、実行時にルールを適用する際、この順序で行なわれるからです。

Pattern は現在の URL に適用される (Apache 1.1.x では System V8、Apache 1.2.x 以降では POSIX の)正規表現です。 ここで「現在の」と言っているのは、ルールが適用される際の URL の値のことです。これはリクエストされたオリジナルの URL であるとは限りません。既に数多くのルールがマッチして、 それを書き換えた後かもしれないからです。

正規表現の文法に関するヒント:

  テキスト: 
    .           任意の一文字
    [chars]     文字クラス: いずれかの文字
    [^chars]    文字クラス: これら以外の文字
    text1|text2 選択肢: text1 または text2
  
  文字数指定:
    ?           直前の文字の 0 回または 1 回の繰り返し
    *           直前の文字の 0 回以上の繰り返し
    +           直前の文字の 1 回以上の繰り返し
  
  グルーピング:
    (text)      テキストのグルーピング
                (選択肢の境界を明示する、若しくは後方参照を作成するために使う。
                 N番目のグループは、RewriteRule の右側の表現で$Nとして参照することが可能。)
  
  文字位置の指定:
    ^           行頭
    $           行末
  
  エスケープ:
    \char       特殊文字をエスケープ(効果を打ち消す)する
                (例えば ".[]()" など)
  

正規表現に関する情報は、ローカルの regex(3) man ページかまたは Apache 1.3 の配布物に含まれるsrc/regex/regex.3 を参照してください。もし正規表現やその変種 (POSIX 正規表現、 Perl 正規表現 など)に興味があれば、以下の専門書をご覧下さい:

Mastering Regular Expressions
Jeffrey E.F. Friedl
Nutshell Handbook Series
O'Reilly & Associates, Inc. 1997
ISBN 1-56592-257-3

(訳注: 第2版の日本語版)

詳説 正規表現 第2版
Jeffrey E. F. Friedl 著
田和 勝 訳
オライリー・ジャパン 2003
ISBN 4-87311-130-7

さらに、mod_rewrite ではパターンの前に NOT 文字('!') が使えます。これで後続のパターンを否定することができます。 例えていうならば、``もし現在の URL がこのパターンにマッチしなければ'' ということです。これは、反対のパターンを表す方が簡単だったり、 最後のデフォルトルールとするなど、 例外的なケースを表現するのにも使えます。

注意: NOT 文字を使ってパターンを否定する場合はパターン中に グループ化されたワイルドカード部分を入れることはできません。 これは、パターンがマッチ *しない* とき、 グループの中身は空になってしまうからです。その結果、 否定されたパターンを使う場合は、置き換え文字列の中で $N は使えません!

書き換えルールの Substitution は、Patternが マッチした場合にオリジナルの URL から置き換えられる文字列です。 プレーンテキストの他に以下のものが使えます。

  1. RewriteRule パターンへの後方参照 $N
  2. 最後にマッチした RewriteCond パターンへの後方参照 %N
  3. ルール条件のテスト文字列と同様のサーバ変数 (%{変数名})
  4. マッピング関数 の呼び出し (${mapname:key|default})
後方参照は $N(N=0..9) 識別子で表します。これは、マッチした Pattern のグループの中で、 N 番目のものの内容に置き換えられます。サーバ変数は RewriteCond ディレクティブの TestString と同じです。 マッピング関数は RewriteMap ディレクティブから来たもので、 そこで説明しています。これら 3 タイプの変数は、上記の順序で展開されます。

前述のように、すべての書き換えルールが Substitution に対して (設定ファイルに定義してある順に)適用されます。URL は Substitution によって完全に置き換えられ、 書き換え処理は L フラグ -- 後述 -- によって明示的に終端されていない限り、 ルールがなくなるまで続けられます。

'-' と呼ばれる特殊な置き換え文字列があります。 これは、置換禁止! の意味です。変でしょ? いいえ、これは URL のマッチングだけを行ない、 置換を行なわないという機能を提供してくれるものです。 すなわちC (chain) フラグとないっしょに使うことによって、 置換が行なわれる前に複数のパターンを適用することができます。

もうひとつ注意事項: クエリー文字列部分を付加した置換文字列で URL を生成することもできます。 単に、置換文字列の中にクエスチョンマークを入れるだけで、それ以降は QUERY_STRING に入れるべきことを示します。 既存のクエリー文字列を消去したい場合は、 置換文字列をクエスチョンマークだけで終わらせるようにします。

注意: 特殊機能について述べます: 置換フィールドの前に http://thishost[:thisport] を置くと、mod_rewrite は自動的にこれを除去します。この暗黙の外部リダイレクト URL における自動変換機能は、ホスト名部分を生成する マッピング関数と同時に使う場合に便利かつ重要なものです。 これを理解するには、以下のサンプルの章の最初の例を見てください。
備考: この機能の影響で、 http://thishost 接頭辞の付いた 自分自身のサーバへの無条件の外部リダイレクションは、 動作しません。 このような自己リダイレクトを行うには、R フラグを使う必要があります(後述)。

RewriteRule ディレクティブの第三引数として、 Pattern に対して上記以外にも以下のような

[フラグ]
をつけることができます。 フラグは以下のものをカンマで区切って指定します:
  • 'redirect|R [=code]' (強制 redirect)
    Substitution の前に (新しい URL を URI にする) http://thishost[:thisport]/ をつけることにより強制的な外部リダイレクションを行ないます。 code が指定されない場合、HTTP レスポンスの 302 (MOVED TEMPORARILY) が使われます。300 から 400 までの他のレスポンスコードを返したい場合は、 直接その番号を指定するか、シンボル名 temp (デフォルト), permanent, seeother のいずれかを使います。例えば、``/~'' を ``/u/'' に変換したり、常に /u/ user にスラッシュを追加するなどの、クライアントに 正規化 された URL を返すルールに使うことができます。

    注意: このフラグを使う場合は、置換フィールドが有効な URL であることを確認してください。もしそうでない場合、 無効な場所にリダイレクトしていることになってしまいます。 さらに、このフラグは、URL の前に http://thishost[:thisport]/ を付加するだけで、その後も書き換え処理は続くことを 理解しておいてください。 通常はそこで書き換えをやめて即時にリダイレクトすることが望みの動作 でしょう。 書き換えを終了するには、 'L' フラグもいっしょに指定しなければなりません。

  • 'forbidden|F' (URL を強制的に forbidden(禁止)にする)
    これは現在の URL を強制的にアクセス禁止にします。 すなわち、即時に HTTP レスポンスの 403 (FORBIDDEN) を返します。このフラグは適切な RewriteCond といっしょに使って、特定の URL に対する条件ブロックを行なうために 使います。
  • 'gone|G' (URL を強制的に gone(消去済み)にする)
    これは現在の URL を強制的に消去済み(gone)にします。 すなわち、即時に HTTP レスポンスの 410 (GONE) を返します。このフラグはもはや存在しないページを 消去済みとしてマークするために使います。
  • 'proxy|P' (強制 proxy)
    このフラグは、置換対象部を内部的なプロキシリクエスト とみなし、その場で(すなわち、 ここで書き換えルールを停止して)プロキシモジュールを通して出力します。 置換対象文字列は(例えば、普通は http:// hostnameで始まるような)、Apache プロキシモジュールで扱える有効な URI でなければなりません。 そうでなければ、プロキシモジュールからエラーが報告されます。 このフラグを使うことでより強力な ProxyPass ディレクティブの実装を行なうことができ、リモートにあるものを ローカルサーバの名前空間にマップすることができます。

    注意: この機能を使うにあたっては、ご自分の Apache サーバに プロキシモジュールが組み込まれていることを 確認してください。確認方法がわからない場合は、``httpd -l'' の出力の中に mod_proxy.c があるかどうかを調べてみましょう。もしあれば、 mod_rewrite のこの機能を使えます。もしなければ、mod_proxy を有効にして ``httpd'' プログラムを再構築する必要があります。

  • 'last|L' (last(最後の)ルール)
    ここで書き換え処理を中止し、 それ以上の書き換えルールを適用しないようにします。これは Perl の last コマンドや C 言語の break コマンドに対応するものです。このフラグを使うことで、 現在の書き換え後の URL が後続のルールによって それ以上書き換えられることを防止します。 例えば、これを使ってルートパスの URL ('/') を実際のもの、例えば '/e/www/' に書き換えます。
  • 'next|N' (next(次の)一周)
    書き換え処理を(一番最初の書き換えルールから)再実行します。 ただしその際マッチングされる URL は当初の URL ではなく、最後に書き換えられた URL です。これは Perl の next コマンドや C 言語の continue コマンドに対応するものです。 書き換え処理を再起動したいとき すなわち、ループの先頭に戻りたいとき
    に このコマンドを使ってください。 ただし、無限ループを作らないように留意してください!
  • 'chain|C' (次のルールに chained (チェイン))
    このフラグを指定すると、現在のルールは次のルールにチェインされます (なお、次のルールも後続のルールに順番に チェインすることができます)。これには以下の効果があります: ルールがマッチすると、処理は通常どおり行われます。 すなわちフラグは何の影響も与えません。ルールがマッチ しない場合、後続のすべてのルールはスキップされます。 例えば (.www 部分が行なわれるべきでない) 外部リダイレクトを発生させた時に、 ディレクトリごとのルールセットの中から ``.www'' の部分を取り除くために使うことできます。
  • 'type|T=MIME-type' (MIME type の強制指定)
    ターゲットファイルの MIME タイプを強制的に MIME-type にします。例えばこれを使って、mod_alias のディレクティブである ScriptAlias をシミュレートすることができます。これは、 マッピングされたディレクトリの中にあるすべてのファイルの MIME タイプを、内部的に``application/x-httpd-cgi'' に強制セットするものです。
  • 'nosubreq|NS' (no sub-request, 内部の サブリクエストがない ときのみ使われる)
    このフラグを使うと、クエストが内部のサブリクエストである場合に、 書き換えエンジンが書き換えルールをスキップするようにします。 サブリクエストは、例えば、mod_include がディレクトリのデフォルトの候補となるファイルの情報 (index.xxx) を検索しようとする際に、Apache の中で内部的に発生します。 サブリクエストにおいては書き換え操作は常に有用であるとは限らず、 すべてのルールが適用されてしまうと問題を起こしてしまう場合もあります。 そのようなルールはこのフラグを使って除外します。

    以下のルールを使って、このフラグを使うかどうか決めてください: CGI スクリプトの先頭になんらかの URL を付加して、それを CGI スクリプトで処理させようとする場合、サブリクエストの際に問題が 起こったり (オーバーヘッドがかかったり) する可能性が高くなります。 このようなケースでは、このフラグを使ってください。

  • 'nocase|NC' (no case)
    これはパターンについて大文字小文字を区別しないようにします。 すなわちパターンが現在の URL とマッチされる際、 'A-Z' と 'a-z' は区別されません。
  • 'qsappend|QSA' (query string append)
    このフラグは、既存のものを置き換えるのではなく、置換文字列の クエリー文字列部分を追加するようにします。書き換えルールを通してクエリー 文字列に何かデータを追加したい場合にこのフラグを使います。
  • 'noescape|NE' (no URI escaping of output)
    このフラグは、mod_rewrite が書き換え結果に対して通常行なわれる URL エスケープルールを適用しないようにします。通常は ('%', '$', ';' といった) 特殊文字については、それらと等価の 16 進数文字列 (順に '%25', '%24', '%3B') にエスケープされます。 このフラグはこの動作を抑制します。 これにより、出力の中にパーセント文字を使うことができます。 以下に例を挙げます。
          RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]
         
      
    この例では、'/foo/zed' が安全なリクエストである '/bar?arg=P1=zed' に変更されます。
    注意: noescape フラグは Apache 1.3.20 以降でのみ有効です。
  • 'passthrough|PT' (pass through to next handler)
    このフラグは、内部の request_rec 構造体の uri フィールドに filename フィールドの値をセットするように、書き換えエンジンに指示します。 このフラグは単に、RewriteRule ディレクティブの出力に対して、他の URI からファイル名への変換処理を行う Alias, ScriptAlias, Redirect といったディレクティブによる後処理を入れるための小技です。 意味を示すための単純な例: mod_rewrite の書き換えエンジンで /abc から /def への変換を行ない、さらに mod_alias/def から /ghi に書き換えるには、以下のようにします:
          RewriteRule ^/abc(.*)  /def$1 [PT]
          Alias       /def       /ghi
         
      
    もし PT フラグを指定するのを忘れてしまった場合、 mod_rewrite はちゃんとその仕事を行ないます。 すなわち、完全な API に準拠した URI-to-filename 変換ルーチンが行うべき、uri=/abc/...filename=/def/... に書き換え、を行ないます。その後 mod_alias が起動され、URI-to-filename 変換を試みますが、これは動作しません 。

    注意: URL-to-filename 変換を含む異なったモジュールのディレクティブを混用したい場合には、 このフラグを指定する必要があります。典型的な例としては、 mod_aliasmod_rewrite の同時使用です。

    注意 - Apache ハッカーへ:
    現在の Apache API に URI-to-filename フックに加えて filename-to-filename フックがあれば、 このフラグを使う必要はないのです! しかしこのようなフックがない現在、 このフラグが唯一の解決策となります。Apache グループはこの問題について議論しており、Apache バージョン 2.0 にはそのようなフックが追加されることでしょう。
  • 'skip|S=num' (skip next rule(s))
    このフラグは書き換えエンジンに対し、現在のルールがマッチしたら、 次の num 個のルールをスキップするよう指示します。これを 使って、擬似的に if-then-else 構造を作ることができます: then-句 の最終ルールは skip=N となります。ここで N は else-句 に入れるルールの数です。(これは 'chain|C' フラグとは 異なります!)。
  • 'env|E=VAR:VAL' (set environment variable)
    これは VAR という名前の環境変数の値を VAL にするよう指示します。ここで VAL には、正規表現の後方参照として展開される $N%N を書くことができます。 このフラグを複数使って、複数の変数を定義することもできます。 この変数は多くの場合、通常後から XSSI (<!--#echo var="VAR"--> を通して) または CGI (例えば $ENV{'VAR'}) のように、参照されます。さらに、 RewriteCond パターン %{ENV:VAR} を通して参照することもできます。これを使って URL からの情報を切り取って記憶します。
注意: サーバ単位の設定ファイルの中では、Pattern は完全な URL に適用されることを忘れないでください。 しかしながら、ディレクトリ単位の設定ファイルの中では、 パターンマッチングのためにディレクトリ単位の接頭辞 (これは特定のディレクトリでは常に同じものです!) が自動的に 取り除かれ、置換が終わった後に自動的に付加 されます。この機構は、さまざまな種類の書き換え操作に おいて欠くことのできないものです。なぜなら、この接頭辞のスキップ が行なわれないと、常に存在するとは限らない親ディレクトリとの マッチングを行なわなければならなくなるからです。

ひとつ例外があります: 置換文字列が ``http://'' で始まっている場合、ディレクトリ接頭辞は付加されず 、外部リダイレクトまたは (P フラグが 使われていれば!) プロキシ処理が強制的に行なわれます。

注意: ディレクトリ単位の設定ファイル における書き換えエンジンを有効にする場合、これらのファイルに ``RewriteEngine On'' をセットし、かつ ``Options FollowSymLinks'' を有効に しなければなりません。あなたのところの管理者がユーザの ディレクトリの FollowSymLinks のオーバーライド を禁止していた場合、書き換えエンジンを使うことはできません。 この制限が必要なのは、セキュリティ関連の理由によります。

以下に有効な置換の組合せと、それらの意味を示します:

リクエスト ``GET /somepath/pathinfo'' が行なわれた場合の、
サーバ単位の設定 (httpd.conf) の内部:

  与えられたルール                                      置換結果
  ----------------------------------------------  ----------------------------------
  ^/somepath(.*) otherpath$1                      無効なのでサポートしない
  
  ^/somepath(.*) otherpath$1  [R]                 無効なのでサポートしない
  
  ^/somepath(.*) otherpath$1  [P]                 無効なのでサポートしない
  ----------------------------------------------  ----------------------------------
  ^/somepath(.*) /otherpath$1                     /otherpath/pathinfo
  
  ^/somepath(.*) /otherpath$1 [R]                 外部リダイレクション経由で
                                                  http://thishost/otherpath/pathinfo
  
  ^/somepath(.*) /otherpath$1 [P]                 無意味なのでサポートしない
  ----------------------------------------------  ----------------------------------
  ^/somepath(.*) http://thishost/otherpath$1      /otherpath/pathinfo
  
  ^/somepath(.*) http://thishost/otherpath$1 [R]  外部リダイレクション経由で
                                                  http://thishost/otherpath/pathinfo
  
  ^/somepath(.*) http://thishost/otherpath$1 [P]  無意味なのでサポートしない
  ----------------------------------------------  ----------------------------------
  ^/somepath(.*) http://otherhost/otherpath$1     外部リダイレクション経由で
                                                  http://otherhost/otherpath/pathinfo
  
  ^/somepath(.*) http://otherhost/otherpath$1 [R] 外部リダイレクション経由で
                                                  http://otherhost/otherpath/pathinfo
                                                  ([R] フラグは冗長)
  
  ^/somepath(.*) http://otherhost/otherpath$1 [P] 内部プロキシ経由で
                                                  http://otherhost/otherpath/pathinfo
  

リクエスト ``GET /somepath/localpath/pathinfo'' が行なわれた場合の、
/somepath に関するディレクトリ単位の設定の内部:
(例えば/physical/path/to/somepath ディレクトリにあって、
RewriteBase /somepath の記述がある .htaccess ファイル):

  与えられたルール                                      置換結果
  ----------------------------------------------  ----------------------------------
  ^localpath(.*) otherpath$1                      /somepath/otherpath/pathinfo
  
  ^localpath(.*) otherpath$1  [R]                 外部リダイレクション経由で
                                                  http://thishost/somepath/otherpath/pathinfo
  
  ^localpath(.*) otherpath$1  [P]                 無意味なのでサポートしない
  ----------------------------------------------  ----------------------------------
  ^localpath(.*) /otherpath$1                     /otherpath/pathinfo
  
  ^localpath(.*) /otherpath$1 [R]                 外部リダイレクション経由で
                                                  http://thishost/otherpath/pathinfo
  
  ^localpath(.*) /otherpath$1 [P]                 無意味なのでサポートしない
  ----------------------------------------------  ----------------------------------
  ^localpath(.*) http://thishost/otherpath$1      /otherpath/pathinfo
  
  ^localpath(.*) http://thishost/otherpath$1 [R]  外部リダイレクション経由で
                                                  http://thishost/otherpath/pathinfo
  
  ^localpath(.*) http://thishost/otherpath$1 [P]  無意味なのでサポートしない
  ----------------------------------------------  ----------------------------------
  ^localpath(.*) http://otherhost/otherpath$1     外部リダイレクション経由で
                                                  http://otherhost/otherpath/pathinfo
  
  ^localpath(.*) http://otherhost/otherpath$1 [R] 外部リダイレクション経由で
                                                  http://otherhost/otherpath/pathinfo
                                                  ([R] フラグは冗長)
  
  ^localpath(.*) http://otherhost/otherpath$1 [P] 内部プロキシ経由で
                                                  http://otherhost/otherpath/pathinfo
  

例:

ここでは、
/ Language /~ Realname /.../ File
という書式の URL を
/u/ Username /.../ File . Language
に書き換えたいものとします。

前述のマップファイルを /path/to/file/map.txt という名前で保存しておきます。その後、Apache サーバ設定 ファイルに以下の行を追加するだけです:

  RewriteLog   /path/to/file/rewrite.log
  RewriteMap   real-to-user               txt:/path/to/file/map.txt
  RewriteRule  ^/([^/]+)/~([^/]+)/(.*)$   /u/${real-to-user:$2|nobody}/$3.$1
  

その他の情報


環境変数

このモジュールは、SCRIPT_URLSCRIPT_URI という二つの (非標準の) CGI/SSI 環境変数を設定します。これらの中には現在のリソースへの論理的な Web ビューが入っています。一方、標準の CGI/SSI 変数である SCRIPT_NAMESCRIPT_FILENAME には、物理的なシステムビューが入っています。

注意: これらの変数の中には、最初にリクエストを受けた時点 すなわち、書き換えが行われる前の URI/URL が保持されています。URL 書き換え処理は、論理的な URL を物理的なパス名に書き換えるために使われることが多いため、 この点は重要です。

例:

  SCRIPT_NAME=/sw/lib/w3s/tree/global/u/rse/.www/index.html
  SCRIPT_FILENAME=/u/rse/.www/index.html
  SCRIPT_URL=/u/rse/
  SCRIPT_URI=http://en1.engelschall.com/u/rse/
  

実践的な解決法

この文書以外にも、URL Rewriting Guide という文書があります。この中には、URL ベースの問題について、実践的な解決法が集められています。 ここで実際に役立つルールセットや mod_rewrite に関する追加情報を見ることができるでしょう。