RewriteRule条件の「.(ドット)」扱いの再検証
mod_rewriteのRewriteRuleに対して指定する一致条件の指定においては、
紹介されているコードによって様々です。
特にすべてのURLを一律転送を行うような場合には、
「.*」などを置換前のパス条件に指定されています。
この「.」に関してアスタリスクなしでもいいという記述を見かけたので、
実際にどうなのかを再検証しました。
mod_rewrite x RewriteRule条件の「.(ドット)」扱い
少しmod_rewriteについて調べていて、
とても分かりやすいサイトを見つけました。
考え方の指南としてなるほどねって思ったのです。
そのサイトには以下のように書かれていました。
mod_rewriteの考え方。 – こせきの技術日記 (引用)
12 # 1文字マッチしたらリライト実行。空文字列でなければ実行する。RewriteRule . index.php [L]
12 # 先頭にマッチしたらリライト実行。常に実行する。RewriteRule ^ - [L]よく見かけるのは .* だが、$0で後方参照するのでなければ全体にマッチする必要はないと思う。先頭にマッチ^でも十分なはず。理由があるなら知りたい。
上段のサンプルコードにあるような、
「# 1文字マッチしたらリライト実行。空文字列でなければ実行する。」という例ですが、
2014/12/17追記・訂正
私の読み方が間違っていました。
私の読み方が間違っていなければ、
要求URLが空文字でなければ(要はすべて)実行する(転送される)という、
意味かなと思います。
そんなことできるの?と言うわけで、このパターン検証を行ってみました。
.htaccessによるRewriteRuleのディレクトリ判定を行われる際には、
.htaccessを設置したディレクトリへのURL要求時には、
「空文字」としての要求が行われます。
その為「.」は、
「.htaccessを設置したディレクトリ以外への要求である場合」として解釈が行えます。
逆に「.htaccessを設置したディレクトリへの要求である場合」の判定は、
「^$」にて判定が行えます。
検証作業は以下で行いました。
ディレクトリ内からの.htaccessによる転送
最初はディレクトリ内での転送例で確認しましたが、
「.」は「/rule/dot/」の要求パスには一致しませんでした。
ルートパスの「(空文字)」要求パスとは一致しません。
ルートディレクトリの場合「空文字」になる為、
「.(任意の1文字)」にはマッチしません、当然です。
ドメインルートからの.htaccessによる転送
ならばドメインルートからの転送例でも確認しました。
ですが「.」は「/」の要求パスには一致しませんでした。
ルートパスの「(空文字)」要求パスとは一致しません。
この場合もルートディレクトリの場合「空文字」になる為、
「.(任意の1文字)」にはマッチしません、当然です。
ここで疑問に感じるのは「*」の「直前のサブ式と 0 回以上一致」です。
「*」以外に代用できる記述方法とドメインルートにアクセスした際の挙動を確認します。
* 以外を指定した繰り返し指定例
正規表現では様々なパーターンを表現することができます。
正規表現の構文
こうしたパターンを利用して「.」とのマッチングを確認します。
正規表現の構文|MSDN (引用)
文字 説明 \ 次に続く文字が特殊文字、リテラル、後方参照、または 8 進エスケープであることを示します。たとえば、”n” は文字 “n” と一致します。’\n’ は改行文字と一致します。”\\” は “\” と、”\(” は “(” と一致します。 ^ 入力文字列の先頭と一致します。RegExp オブジェクトの Multiline プロパティが設定されている場合、^ は ‘\n’ または ‘\r’ の直後にも一致します。 $ 入力文字列の末尾と一致します。RegExp オブジェクトの Multiline プロパティが設定されている場合、$ は ‘\n’ または ‘\r’ の直前にも一致します。 * 直前のサブ式と 0 回以上一致します。たとえば、”zo*” は “z” とも “zoo” とも一致します。* は {0,} と同じ意味になります。 + 直前のサブ式と 1 回以上一致します。たとえば、”zo+” は “zo” や “zoo” とは一致しますが、”z” とは一致しません。+ は {1,} と同じ意味になります。 ? 直前のサブ式と 0 回または 1 回一致します。たとえば、”do(es)?” は “do” または “does” の”do” と一致します。? は {0,1} と同じ意味になります。 {n} n には 0 以上の整数を指定します。正確に n 回一致します。たとえば、’o{2}’ は “Bob” の ‘o’ とは一致しませんが、”food” の 2 つの o とは一致します。 {n,} n には 0 以上の整数を指定します。少なくとも n 回一致します。たとえば、’o{2}’ は “Bob” の “o” とは一致しませんが、”foooood” のすべての o とは一致します。’o{1,}’ は ‘o+’ と同じ意味になります。’o{0,}’ は ‘o*’ と同じ意味になります。 {n,m} m および n には 0 以上の整数を指定します。n は m 以下です。n ~ m 回一致します。たとえば、”o{1,3}” は “fooooood” の最初の 3 つの o と一致します。’o{0,1}’ は ‘o?’ と同じ意味になります。カンマと数の間には、スペースを入れないでください。 ? ほかの修飾子 (*, +, ?, {n}, {n,}, {n,m}) の直後に指定すると、一致パターンを制限することができます。既定のパターンでは、できるだけ多数の文字列と一致するのに比べて、制限されたパターンでは、できるだけ少ない文字列と一致します。たとえば、文字列 “oooo” に対して、’o+?’ を指定すると 1 つの “o” と一致し、’o+’ を指定するとすべての ‘o’ と一致します。 . “\n” を除く任意の 1 文字に一致します。‘\n’ など、任意の文字と一致するには、'[.\n]’ などのパターンを指定します。
各パターン例と検証結果
ここでは以下の転送パターンで試します。
条件記述 | 要求パスと転送結果 | 確認先ドメイン | ||||
---|---|---|---|---|---|---|
/ | /1 | /11 | /2(DIR無) | /22(DIR無) | ||
.{0} | ● | ● | ● | ● | ● | http://root-dot0.trce.info/ |
^.{0}$ | ● | × | × | ×404 | ×404 | http://root-dot0cd.trce.info/ |
.{0,} | ● | ● | ● | ● | ● | http://root-dot0over.trce.info/ |
^.{0,}$ | ● | ● | ● | ● | ● | http://root-dot0overcd.trce.info/ |
.{1} | × | ● | ● | ● | ● | http://root-dot1.trce.info/ |
^.{1}$ | × | ● | × | ● | ×404 | http://root-dot1cd.trce.info/ |
.{1,} | × | ● | ● | ● | ● | http://root-dot1over.trce.info/ |
^.{1,}$ | × | ● | ● | ● | ● | http://root-dot1overcd.trce.info/ |
.{2} | × | ● | ● | ×404 | ● | http://root-dot2.trce.info/ |
^.{2}$ | × | ● | ● | ×404 | ● | http://root-dot2cd.trce.info/ |
.{2,} | × | ● | ● | ×404 | ● | http://root-dot2over.trce.info/ |
^.{2,}$ | × | ● | ● | ×404 | ● | http://root-dot2overcd.trce.info/ |
尚、上記の要求パスはそれぞれ以下のような意味合いで指定しています。
- /: 通常のドメインルートへのアクセス
- /1: マッチング文字列として1文字を追加したパターンでディレクトリが存在
- /11: マッチング文字列として2文字を追加したパターンでディレクトリが存在
- /2: マッチング文字列として1文字を追加したパターンでディレクトリは存在しない
- /22: マッチング文字列として2文字を追加したパターンでディレクトリは存在しない
上記のパターンにて、それぞれのマッチング繰り返し回数が
どのように判定しているのかが読み取れます。
.{0}では、全パターンにマッチしていることが分かります。
.{1}では、/1, /11, /2, /22 にマッチするが、/にはマッチしていない。
これによって「/」は任意の1文字ではあるが、2文字目がない為、1回の繰り返しに該当しない。
.{2}では、
全てにマッチさせるパターン
上記のことから、要求パスのすべてにマッチングさせるには、
「.」のみでは正しく判定されず、せめて「.{0,}」という0回以上の繰り返しが必要です。
ですが、MSDNでも書かれているように「* は {0,} と同じ意味になります」 とのことから、
「.*」と記述することは、「.{0,}」と書いても同じ判定条件になることになります。
結果「.{0,}」と書くよりも「.*」の方が一般的ですので
基本的には「.*」を採用すればいいことが分かります。
検証時の挙動証跡
上記の検証においての挙動は以下でご紹介しています。
「.{0}」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule .{0} http://redirect.trce.info/root-dot0/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot0.trce.info/ ⇒ http://redirect.trce.info/root-dot0/
ディレクトリがある場合
http://root-dot0.trce.info/1 ⇒ http://redirect.trce.info/root-dot0/
http://root-dot0.trce.info/11 ⇒ http://redirect.trce.info/root-dot0/
ディレクトリがない場合
http://root-dot0.trce.info/2 ⇒ http://redirect.trce.info/root-dot0/
http://root-dot0.trce.info/22 ⇒ http://redirect.trce.info/root-dot0/
この場合、要求パスのすべてに一致しています。
^(開始)、$(終了)の指定をしていない為、
要求パスに何かしらの1文字が含まれれば対象に含まれます。
その為「/」にもマッチしています。
「^.{0}$」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^.{0}$ http://redirect.trce.info/root-dot0cd/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot0cd.trce.info/ ⇒ http://redirect.trce.info/root-dot0cd/
ディレクトリがある場合
http://root-dot0cd.trce.info/1 ⇒ 転送不可(http://root-dot0cd.trce.info/1/)
http://root-dot0cd.trce.info/11 ⇒ 転送不可(http://root-dot0cd.trce.info/11/)
ディレクトリがない場合
http://root-dot0cd.trce.info/2 ⇒ 転送不可(404)
http://root-dot0cd.trce.info/22 ⇒ 転送不可(404)
この場合、要求パスの「/」のみにマッチしています。
^(開始)、$(終了)の指定をしした為、
パスが任意の1文字で繰り返しがなし(1文字)となり「/」にのみマッチしています。
「.{0,}」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule .{0,} http://redirect.trce.info/root-dot0over/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot0over.trce.info/ ⇒ http://redirect.trce.info/root-dot0over/
ディレクトリがある場合
http://root-dot0over.trce.info/1 ⇒ http://redirect.trce.info/root-dot0over/
http://root-dot0over.trce.info/11 ⇒ http://redirect.trce.info/root-dot0over/
ディレクトリがない場合
http://root-dot0over.trce.info/2 ⇒ http://redirect.trce.info/root-dot0over/
http://root-dot0over.trce.info/22 ⇒ http://redirect.trce.info/root-dot0over/
この場合、すべての要求パスにマッチしています。
^(開始)、$(終了)の指定はしていませんが、
「,」によって「任意の文字が少なくとも0回以上」という条件が付与され、
「/」もその他のパスにもマッチしています。
「^.{0,}$」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^.{0,}$ http://redirect.trce.info/root-dot0overcd/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot0overcd.trce.info/ ⇒ http://redirect.trce.info/root-dot0overcd/
ディレクトリがある場合
http://root-dot0overcd.trce.info/1 ⇒ http://redirect.trce.info/root-dot0overcd/
http://root-dot0overcd.trce.info/11 ⇒ http://redirect.trce.info/root-dot0overcd/
ディレクトリがない場合
http://root-dot0overcd.trce.info/2 ⇒ http://redirect.trce.info/root-dot0overcd/
http://root-dot0overcd.trce.info/22 ⇒ http://redirect.trce.info/root-dot0overcd/
この場合もすべての要求パスにマッチしています。
^(開始)、$(終了)の指定をしていますが、
上記同様開始終了の範囲内で任意の文字が少なくとも0回以上としてマッチしています。
「.{1}」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule .{1} http://redirect.trce.info/root-dot1/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot1.trce.info/ ⇒ 転送不可(http://root-dot1.trce.info/)
ディレクトリがある場合
http://root-dot1.trce.info/1 ⇒ http://redirect.trce.info/root-dot1/
http://root-dot1.trce.info/11 ⇒ http://redirect.trce.info/root-dot1/
ディレクトリがない場合
http://root-dot1.trce.info/2 ⇒ http://redirect.trce.info/root-dot1/
http://root-dot1.trce.info/22 ⇒ http://redirect.trce.info/root-dot1/
この場合、任意の文字が1回の繰り返しの条件となり、
任意の文字が2文字あることが条件になっています。
その為「/」のみにはマッチせず、その他の場合のみマッチしています。
「^.{1}$」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^.{1}$ http://redirect.trce.info/root-dot1cd/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot1cd.trce.info/ ⇒ 転送不可(http://root-dot1cd.trce.info/)
ディレクトリがある場合
http://root-dot1cd.trce.info/1 ⇒ http://redirect.trce.info/root-dot1/
http://root-dot1cd.trce.info/11 ⇒ 転送不可(http://root-dot1cd.trce.info/11/)
ディレクトリがない場合
http://root-dot1cd.trce.info/2 ⇒ http://redirect.trce.info/root-dot1/
http://root-dot1cd.trce.info/22 ⇒ 転送不可(404)
この場合、開始終了を指定していますので、
任意の文字が1回の繰り返しの条件から、任意の文字が2文字で終了している必要があります。
よって「/1」「/2」にのみマッチしています。
「.{1,}」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule .{1,} http://redirect.trce.info/root-dot1over/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot1over.trce.info/ ⇒ 転送不可(http://root-dot1over.trce.info/)
ディレクトリがある場合
http://root-dot1over.trce.info/1 ⇒ http://redirect.trce.info/root-dot1over/
http://root-dot1over.trce.info/11 ⇒ http://redirect.trce.info/root-dot1over/
ディレクトリがない場合
http://root-dot1over.trce.info/2 ⇒ http://redirect.trce.info/root-dot1over/
http://root-dot1over.trce.info/22 ⇒ http://redirect.trce.info/root-dot1over/
この場合、開始終了を指定してませんが、
任意の文字が1回以上の繰り返しの条件から「/」以外がマッチしています。
「^.{1,}$」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^.{1,}$ http://redirect.trce.info/root-dot1overcd/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot1overcd.trce.info/ ⇒ 転送不可(http://root-dot1overcd.trce.info/)
ディレクトリがある場合
http://root-dot1overcd.trce.info/1 ⇒ http://redirect.trce.info/root-dot1overcd/
http://root-dot1overcd.trce.info/11 ⇒ http://redirect.trce.info/root-dot1overcd/
ディレクトリがない場合
http://root-dot1overcd.trce.info/2 ⇒ http://redirect.trce.info/root-dot1overcd/
http://root-dot1overcd.trce.info/22 ⇒ http://redirect.trce.info/root-dot1overcd/
この場合、開始終了を指定していますが、
任意の文字が1回以上の繰り返しの条件で既にマッチしている為、
「/」以外がマッチしています。
「.{2}」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule .{2} http://redirect.trce.info/root-dot2/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot2.trce.info/ ⇒ 転送不可(http://root-dot2.trce.info/)
ディレクトリがある場合
http://root-dot2.trce.info/1 ⇒ http://redirect.trce.info/root-dot2/
http://root-dot2.trce.info/11 ⇒http://redirect.trce.info/root-dot2/
ディレクトリがない場合
http://root-dot2.trce.info/2 ⇒ 転送不可(404)
http://root-dot2.trce.info/22 ⇒ http://redirect.trce.info/root-dot2/
この場合、任意の文字が2回の繰り返しの条件となり、
任意の文字が3文字あることが条件になっています。
その為「/」「/1」「/2」にはマッチせず「/11」「/22」のみマッチしています。
「^.{2}$」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^.{2}$ http://redirect.trce.info/root-dot2cd/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot2cd.trce.info/ ⇒ 転送不可(http://root-dot2cd.trce.info/)
ディレクトリがある場合
http://root-dot2cd.trce.info/1 ⇒ http://redirect.trce.info/root-dot2cd/
http://root-dot2cd.trce.info/11 ⇒ http://redirect.trce.info/root-dot2cd/
ディレクトリがない場合
http://root-dot2cd.trce.info/2 ⇒ 転送不可(404)
http://root-dot2cd.trce.info/22 ⇒ http://redirect.trce.info/root-dot2cd/
この場合、任意の文字が2回の繰り返しの条件となり、
任意の文字が3文字あることが条件になっています。
かつその3文字で終了している必要があります。
その為「/」「/1」「/2」にはマッチせず「/11」「/22」のみマッチしています。
さらに、実在しないURLにはなりますが、
http://root-dot2cd.trce.info/222 では、
3文字で終了していない為、転送不可(404)になります。
「.{2,}」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule .{2,} http://redirect.trce.info/root-dot2over/ [R=301,L] </IfModule> |
ルートディレクトリ
ディレクトリがある場合
http://root-dot2over.trce.info/1 ⇒ http://redirect.trce.info/root-dot2over/
http://root-dot2over.trce.info/11 ⇒ http://redirect.trce.info/root-dot2over/
ディレクトリがない場合
http://root-dot2over.trce.info/2 ⇒ 転送不可(404)
http://root-dot2over.trce.info/22 ⇒ http://redirect.trce.info/root-dot2over/
この場合、任意の文字が少なくとも2回以上の繰り返しの条件となり、
任意の文字が3文字以上あることが条件になっています。
その為「/」「/1」「/2」にはマッチせず「/11」「/22」のみマッチするはずなのですが、
ここでは「/1」が該当して、転送されてしまっています。
この挙動については、現状では説明がつかないので、今後とも調査を継続します。
「^.{2,}$ 」の検証
.htaccessには以下のように記述しています。
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^.{2,}$ http://redirect.trce.info/root-dot2overcd/ [R=301,L] </IfModule> |
ルートディレクトリ
http://root-dot2overcd.trce.info/ ⇒ 転送不可(http://root-dot2overcd.trce.info/)
ディレクトリがある場合
http://root-dot2overcd.trce.info/1 ⇒ http://redirect.trce.info/root-dot2/
http://root-dot2overcd.trce.info/11 ⇒ http://redirect.trce.info/root-dot2/
ディレクトリがない場合
http://root-dot2overcd.trce.info/2 ⇒ 転送不可(404)
http://root-dot2overcd.trce.info/22 ⇒ http://redirect.trce.info/root-dot2/
この場合も任意の文字が少なくとも2回以上の繰り返しの条件となり、
任意の文字が3文字以上あることが条件になっています。
存在しないURLになりますが、
http://root-dot2overcd.trce.info/222 でも3文字以上なので転送されます。
その為「/」「/1」「/2」にはマッチせず「/11」「/22」のみマッチするはずなのですが、
ここでは「/1」が該当して、転送されてしまっています。
この挙動については、現状では説明がつかないので、今後とも調査を継続します。
さいごに
このように何も考えずに「.*」を利用すれば、特に気にすることもないのですが、
「.」という任意の1文字を表す記号が、どのように解釈されるのかを見てきました。
「.」のみですべてのパス形式に対応するような魔法でもありませんし、
「*」なり「{0,}」なりで、繰り返し回数を明示する必要があることが分かりました。
時に読めない挙動をみせる場合もあるようですが、
概ね「.」との付き合い方が見えたように感じます。
Apache,Apache Hadoop,Apache Subversion,Hadoop,HDFS,HBase,Hive,Mahout,Pigは、
Apache Software Foundationの米国およびその他の国における登録商標または商標です。
ApacheソフトウェアはApache Software License (原文)および
Apache License, 2.0 (原文)に基づきOpen Source Initiativeに承認されライセンスされています。
公開日:
最終更新日:2014/12/17