[Apache] mod_rewriteの使い方・.htaccessでリダイレクトする

2019-05-19環境

サイト引っ越し時の URL の書き換えや、リダイレクトさせたい時に使うのが「 mod_rewrite モジュール」。

WordPress とか XAMPP の「 .htaccess 」ファイルに書いてあるやつで、たまに使うけど、「 RewriteRule 」とか「 RewriteCond 」とか、よくわからないままだったので書かれている意味を調べた。

mod_rewrite とは

Apache のモジュールで、 URL の書き換え・リダイレクト処理のルールを設定するもの
.htaccess 」や「 httpd.conf 」という Apache 設定ファイルに記述する(ここでは「 .htaccess 」への記述方法を解説)
記述にはルールがあり、書き方を間違えると 500 エラーが発生する

ルール
コメントアウト記号は「#」
文字コード UTF-8 ( BOM 無し)
最終行には空行を入れる

サンプル

# こんなやつ
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase /hoge/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /hoge/index.php [L]
</ifModule>

RewriteEngine

「On」:mod_rewrite を有効にする
「Off」:無効にする

mod_rewrite が利用できない場合、エラーが発生するので、if 文で mod_rewrite が使えるなら「On」という記述を書く

<ifModule mod_rewrite.c>
RewriteEngine On
#・・・処理・・・
</ifModule>

RewriteBase

「リダイレクト先」のベース URL を設定する。(リダイレクト元の URL とはなんら関係ないことに注意)
この記述がない場合は、 .htaccess が置いてあるディレクトリが指定される
[ RewriteBase / ]と記述すると、どのディレクトリに .htaccess が置いてあってもドキュメントルートからのパスになる

RewriteCond

RewriteRule を適用するかの条件を定義する( if 文のようなもの)

書式: %{変数名} 条件パターン [フラグ]

%{変数名} を参照して、それが指定した条件パターンと一致していれば(または一致していなければ)、次の条件( RewriteRule )を実行する
RewriteRule の前に書く

使用できる変数名(一部)

変数名
HTTP ヘッダHTTP_USER_AGENTユーザーエージェント
HTTP_HOSTサーバーホスト名(ドメイン名)
HTTP_COOKIEクッキー情報
HTTP_REFERER参照元URL
HTTP_ACCEPTMIMEタイプ(image/webpとか)
HTTP_PROXY_CONNECTIONプロキシサーバー経由か否か
HTTP_FORWARDED経由してきたプロキシサーバーの情報
サーバー内部変数SERVER_ADMINサーバーやサイト管理者の情報(メアドとか)
DOCUMENT_ROOTドキュメントルートのパス(ルートディレクトリ)
SERVER_NAMEサーバー名
SERVER_ADDRサーバーのIPアドレス
SERVER_PORTサーバーのポート番号
SERVER_PROTOCOLサーバープロトコル
SERVER_SOFTWAREサーバーソフトウェア名(Apacheとか)
コネクション & リクエストREMOTE_ADDRホストのIPアドレス
DOCUMENT_ROOTドキュメントルートのパス(ルートディレクトリ)
REMOTE_HOSTリモートホスト名(ドメイン)
QUERY_STRINGクエリ文字列
SCRIPT_FILENAMEスクリプトファイル名とパス
REQUEST_METHODリクエストがGETかPOSTか
mode_rewrite用特殊REQUEST_FILENAMEファイルシステムのファイルパス(/var/www/html/wordpress/....
HTTPSリクエストが「https」なら「ON」、「http」なら「OFF」
REQUEST_URIリクエストURI([http://hoge.com/test/abc.php] なら [/test/abc.php] 頭にスラッシュがつく)

条件パターン

正規表現記号を用いて条件を指定する
パターン意味
!否定
<大きい
>未満
=等しい
=<以上
=>以下
-dディレクトリが存在するか
-fファイルが存在するか
-sファイルが存在し、かつサイズが0より大きい
-l, -H, -Lシンボリックリンクか
-eq= と同じ
-ge<= と同じ
-gt< と同じ
-le>= と同じ
-lt> と同じ
-Uアクセス可能な有効なURLか

使用できるフラグ

[OR]RewriteCondは、RewriteRuleの前に書くもので、複数記述することができる
複数記述した場合、全部一致(AND)か、複数あるうちの1つが一致すればいい(OR)のかを指定する
フラグに何も書かない場合はAND、フラグに[OR]と書くとOR条件となる
[NC]no caseのこと。大文字と小文字を区別しない

RewriteRule

リダイレクト、置き換えのルールを定義する

書式: RewriteRule パターン 置換対象 [フラグ]

リクエスト URL とパターンがマッチすれば、置換対象に置き換えられる
上から順に処理されていく(記述する順番に注意)

パターンには、正規表現を書く

置換対象には、リダイレクト先などを書く。置換対象に相対パス(スラッシュなし)を書くと、 RewriteBase がパスとなる。
例えば、 RewriteBase が [hoge] で、置換対象に [app/index.html] (相対パス)と書くと、生成される URL は [/hoge/app/index.html] となる。
[/app/index.html]とするとそのまま、何も付加されない。

パターンとのマッチング方法は、リクエストされた URL から、 .htaccess が置いてあるディレクトリまでのパス(最後のスラッシュまで)を除いたものが、パターンと比較される。
例えば、 [test] というディレクトリに .htaccess があって、 [http://hoge.com/test/abc.php] でリクエストがあった場合、 [abc.php] がパターンと比較される。

フラグ

RewriteRule の第 3 引数に記述する。省略可。

フラグ意味
[R]指定した先にリダイレクトする。[R](値省略時)は [R=302]となる
例)[R=301] 301にリダイレクト
* 301は恒久的なリダイレクト、302は一次的なリダイレクト
[L]last これ以降のルールは実行されない。ここで終了
[R]を書くときは、必ず[L]を一緒に書く
例) [R=301,L]
[F]HTTPレスポンス403(Forbidden = アクセス権限がない)を返す
[G]HTTPレスポンス410(Gone = 指定ファイルがない)を返す
[C]ルールを連続して処理する。1のルールを通過後、2のルール、3のルール…とチェーンしていく
[N]>next 置換後のURLに対し、ルールを再実行(ループ処理のような者)
[NC]no case 大文字小文字を区別しない
[NE]noescape URLエスケープしない(通常はURLエスケープされる)
[NS]現在のリクエストがサブリクエストである場合、ルールをスキップ
[S]S=numskip Sで指定した数だけ後続のルールをスキップする
[T]T=MIME-type>ターゲットファイルのMIMEタイプを、強制的に指定したMIMEタイプに置き換える
例)[T=image/webp]
[E]E=VAR:VAL,!VAR環境変数の値をセットする。(環境変数VARの値をVALにする)
[E=!VAR]だとVARが削除される
例)[E=accept:1] 変数acceptの値を1にする

サンプルの解説

最初にあげたサンプルの意味を解説

#上のサンプルと一緒のコード
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase /hoge/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /hoge/index.php [L]
</ifModule>
5 行目: RewriteRule ^index\.php$ - [L]

「^」は正規表現で、行頭を意味する
「$」は正規表現で、行末を意味する
「-」は正規表現で、書き換えをしないという意味
よって、 [index.php] でリクエストが来たら、そのまま [index.php] が呼び出される
フラグが [L] なので、ルールはここで終了。後続処理は行われない

6 行目: RewriteCond %{REQUEST_FILENAME} !-f
7 行目: RewriteCond %{REQUEST_FILENAME} !-d

リクエストされたファイルが存在しない、かつ( AND )リクエストされたディレクトリが存在しない場合、 RewriteRule . /hoge/index.php [L] が実行される。

8 行目: RewriteRule . /hoge/index.php [L]

「.」は正規表現で、任意の 1 文字を意味する
この場合、「.」は「どんなリクエストでも」という解釈となり、リクエストが存在するファイルやディレクトリではない場合、全て [/hoge/index.php] に置き換わる(内部転送)

ちなみに、 [RewriteBase /hoge/] としているが、 [RewriteRule . /hoge/index.php [L]] の置換対象( /hoge/index.php )の頭にスラッシュ( / )があるので、 RewriteBase のパスは適用されない( hoge/hoge/index.php とはならない)

Posted by Agopeanuts