[Apache] mod_rewriteの使い方・.htaccessでリダイレクトする
サイト引っ越し時の 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_ACCEPT | MIMEタイプ(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
リダイレクト、置き換えのルールを定義する
リクエスト 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=num | skip 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>
RewriteRule ^index\.php$ - [L]
「^」は正規表現で、行頭を意味する
「$」は正規表現で、行末を意味する
「-」は正規表現で、書き換えをしないという意味
よって、 [index.php] でリクエストが来たら、そのまま [index.php] が呼び出される
フラグが [L] なので、ルールはここで終了。後続処理は行われない
RewriteCond %{REQUEST_FILENAME} !-f7 行目:
RewriteCond %{REQUEST_FILENAME} !-d
リクエストされたファイルが存在しない、かつ( AND )リクエストされたディレクトリが存在しない場合、 RewriteRule . /hoge/index.php [L] が実行される。
RewriteRule . /hoge/index.php [L]
「.」は正規表現で、任意の 1 文字を意味する
この場合、「.」は「どんなリクエストでも」という解釈となり、リクエストが存在するファイルやディレクトリではない場合、全て [/hoge/index.php] に置き換わる(内部転送)
ちなみに、 [RewriteBase /hoge/] としているが、 [RewriteRule . /hoge/index.php [L]] の置換対象( /hoge/index.php )の頭にスラッシュ( / )があるので、 RewriteBase のパスは適用されない( hoge/hoge/index.php とはならない)