mod_rewrite、RewriteRule の設定・書き方
mod_rewrite は Apache のモジュールの1つ。 URL(ドメイン以下のパス、アドレス)のリダイレクト、置き換えなどが行える。 一般的な正規表現を利用して RewriteRule を書くことができる。
より詳しい情報はApache公式サイト mod_rewrite モジュール(Apache) に書かれている。
現状、サイトを構築する上で必須のモジュールと言っても過言ではない。 たいていのレンタルサーバーで標準で利用できる。
RewriteRule の基本
RewriteEngine On
RewriteEngine On RewriteBase /
RewriteRule を使う場合、最初に RewriteEngine On を書いて使用可能な状態にする。 RewriteBase はベースとなる階層を指定できるが、必要なければ書かなくても良い。
以下、RewriteEngine On を記述した状態として説明する。
Last
RewriteRule ^example.html$ /hoge.php [L]
この場合、example.html にアクセスすると、hoge.php を実行する。 ブラウザの表示は example.html のまま。 [L] はルールの最終行(Last)を意味し、ルールが一致した場合、それ以降のルールは処理されない。
Redirect
RewriteRule ^example.html$ /hoge.php [R,L]
この場合、example.html にアクセスすると、hoge.php へリダイレクトされる。 ブラウザの表示は hoge.php になる。 [R] はリダイレクトを意味する。 リダイレクトを行う際、任意のHTTPステータスコードを指定でき、何も指定しない場合は通常302がデフォルトとなる。
RewriteRule ^example.html$ /hoge.php [R=301,L]
正規表現とパターン
RewriteRule は正規表現を用いてページへのアクセスを柔軟に制御できる。 正規表現はPHPなどでも使われる一般的な書き方。
RewriteRule ^/blog/view/([0-9]+)/?$ /blog/view/index.php?id=$1 [L]
この例は、/blog/view/1234/ にアクセスすると、/blog/view/index.php?id=1234 を実行する。 ブラウザの表示は /blog/view/1234/ になる。 ( )内のパターンにマッチした文字列は $1 のように $+数字 で表現される。 ([0-9]+)/ の後の「?」は、URLの末尾にスラッシュがあってもなくても実行されるようにしている。
引数2つ
RewriteRule ^/abc/([0-9a-zA-Z]+)/([0-9\-]+)/?$ /abc/test.php?id=$1&date=$2 [L]
この例は、/abc/suzuki/2006-01-01/ にアクセスすると、/abc/test.php?id=suzuki&date=2006-01-01 を実行する。 ブラウザの表示は /abc/suzuki/2006-01-01/ になる。 ( )のパターンが2つあり、前方から順に $1、$2 となる。
RewriteCond
RewriteCond には RewriteRule の条件を書き、条件に一致した場合 RewriteRule が適用される。 RewriteRule ごとに記述する必要がある。 単に %{変数名} と書くとサーバ変数を参照する。 環境変数の場合は %{ENV:環境変数名} のように ENV: を書く。 HTTPヘッダの場合は %{HTTP:ヘッダ名} のように HTTP: を書く。 これらの変数は、サーバの仕様により取得できたりできなかったりするので確認する必要がある。
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^aaa/(.*)\.html$ /aaa/view.php?a=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f は、リクエストしたファイルと同名のファイルが存在しない場合という意味。 RewriteCond %{REQUEST_FILENAME} !-d は、リクエストしたファイルと同名のディレクトリが存在しない場合という意味。 上記の例では、(.*) に入る文字列が index の場合 /aaa/view.php?a=index を実行する。 このとき、aaa ディレクトリに既に index.html が存在する場合はこの RewriteRule は適用されず、元々存在する index.html を表示する。
RewriteRule の使用例
使用例では基本的に RewriteEngine On を前提とし、以下を省略して説明している。
RewriteEngine On RewriteBase /
ドメインのwwwあり・なしへのリダイレクト
レンタルサーバーによってはドメインを登録後、wwwありとなし両方のアドレスが使えるようになる場合がある。 コントロールパネルでどちらかへ統一(リダイレクト)できる設定がある場合もある。 .htaccess に以下のように書くとwwwありでアクセスしてきた人をwwwなしのアドレスへリダイレクトできる。
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
逆にwwwなしをwwwありにリダイレクトする場合は、wwwを書く場所を入れ替えれば良い。
以下の例だと個別にドメインを書く必要がなく汎用的に使用できる。 #でコメントアウトしている方を利用してもよい。
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
#RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
httpをhttps(SSL)へリダイレクト
SSLを導入後、httpでアクセスしてきた人を強制的にhttpsへリダイレクトしたい場合は .htaccess に以下のように書く。
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
!on というのは ON ではない場合、つまり https ではない場合という意味。 on の逆で off という記述例もたまに見かけるが、私が使っているエックスサーバーなどのレンタルサーバーでは http時(非https時)は off とはならず、空白の場合が多いようだ。 つまり off と書いても条件が一致しないため効果がない。 https時は on になるため、!on という記述が無難かもしれない。
さくらインターネットのレンタルサーバでは %{HTTPS} が取得できず上記の例では動作しなかったが、2018年3月に仕様が変わり、他社と同様の記述でリダイレクトできるようになった。
RewriteCond %{HTTPS} !on
#RewriteCond %{ENV:HTTPS} !^on$
#RewriteCond %{HTTP:X-Sakura-Forwarded-For} ^$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
旧仕様の環境変数 {ENV:HTTPS} は、httpでアクセスした場合は空白(offではない)、httpsでアクセスした場合はonになっているようで、この例ではon以外という条件を指定している。 空白(^$)を指定しても良い。
index.php、index.html などへのアクセスを /(スラッシュ)で終わるアドレスに統一する
検索エンジンが http://example.com/test/index.php と http://example.com/test/ を同一と判断しているとは限らず、バックリンク(被リンク)も同一に評価しているとは限らないので、念のため RewriteRule で各ディレクトリのトップページを /(スラッシュ)で終わるアドレスに統一しておく場合は以下のように書く。
RewriteCond %{THE_REQUEST} ^.*/index.php
RewriteRule ^(.*)index.php$ http://example.com/$1 [R=301,L]
引数ありのURLを別のURLへリダイレクトする
引数(クエリ)付きのURLを変更したり、クエリの仕様を変更した場合、以下のように書きたいところだが、これは出来ない。
RewriteRule ^example/test.php?a=([%-\w]+)&b=([\d]+) /example/new.php?x=$1&y=$2 [R=301,L]
以下のようにクエリを定義する必要がある。
RewriteCond %{QUERY_STRING} a=([%-\w]+)&b=([\d]+)$
RewriteRule ^example/test.php$ /example/new.php?x=%1&y=%2 [R=301,L]
URLエンコードしないようにする
リダイレクトした際、URLエンコードされた引数などは再度URLエンコードされる場合がある。 2重にURLエンコードしないようにするには [NE] というのを書く。
RewriteCond %{QUERY_STRING} a=([%-\w]+)&b=([\d]+)$
RewriteRule ^example/test.php$ /example/new.php?x=%1&y=%2 [NE,R=301,L]
NE は noescape を意味し、特殊文字をエスケープ(URLエンコード)しないようになる。 また、別ページの特定位置へ移動させる際、# が %23 にエンコードされてしまう場合は NE を指定する。 以下は hoge.php というページの <div id="info"> へ移動させる例。
RewriteRule ^example/(.*)$ /hoge.php#info [NE,R,L]
404など指定
ページのリダイレクトのHTTPステータスコードは300番台だが、それ以外の値を指定することもできる。 以下の例は、拡張子が.htm、.htmlに何かしら引数が付いていた場合に404(Not Found)とする。 404のページ(パス)を指定してもよいが、以下のようにハイフン(-)としてもよい。 この場合ErrorDocumentで指定されている404ページが表示される。 NCは大文字・小文字の区別をしない(nocase)という意味。
RewriteCond %{REQUEST_URI} ^.*\.(htm|html)$
RewriteCond %{QUERY_STRING} ^(.+)$
RewriteRule ^.*$ - [NC,R=404,L]
RewriteRule の記述場所
.htaccess や http.conf に記述できる。
.htaccess に記述する例
.htaccess の適当な場所に記述する。
RewriteEngine On RewriteRule (.+)\.html$ /item/view.php?p=$1 [L]
http.conf に記述する例
http.conf に書いた後は Apache を再起動する。
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule (.+)\.html$ /item/view.php?p=$1 [L] </IfModule>
http.conf(VirtualHost)に記述する例
<VirtualHost 192.168.1.2>
ServerName www.example.com
DocumentRoot /test/htdocs
RewriteEngine On
RewriteRule (.+)\.html$ /item/view.php?p=$1
RewriteRule ^/blog/view/([0-9]+)/?$ /blog/view/index.php?id=$1
RewriteRule ^/abc/([0-9a-zA-Z]+)/([0-9\-]+)/?$ /abc/test.php?id=$1&date=$2 [L]
<Directory "/test/htdocs">
Options Includes ExecCGI MultiViews
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>