mod_rewrite は Apache にある機能で、モジュールを組み込むことで利用できる。 URL(ドメイン以下のパス)のリダイレクト、置き換えなどが行える。 一般的な正規表現を利用して RewriteRule を書くことができる。
Apache2.x の場合は Apache インストール時の ./configureに --enable-so --enable-rewrite=shared を付けて、その後 make する。 Apache のバージョンによって書き方が多少異なる。 Apache のインストールは Apache・aprのインストール・設定を ご覧ください。
その後、Apache の modules ディレクトリに mod_rewrite.so があるか確認する。 httpd.conf に LoadModule rewrite_module modules/mod_rewrite.so という1行を追加する。 最初から書いてあればそのままで、コメントアウトされているならそれを外して有効にする。
RewriteEngine On RewriteBase /
RewriteRule を使う場合、最初に RewriteEngine On を書いて使用可能な状態にする。 RewriteBase はベースとなる階層を指定できるが、必要なければ書かなくても良い。
以下、RewriteEngine On を記述した状態として説明する。
RewriteRule ^example.html$ /hoge.php [L]
この場合、example.html にアクセスすると、hoge.php を実行する。 ブラウザの表示は example.html のまま。 [L] はルールの最終行(Last)を意味し、ルールが一致した場合、それ以降のルールは処理されない。
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の末尾にスラッシュがあってもなくても実行されるようにしている。
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 には 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 を表示する。
mod_rewrite、RewriteRule のより詳しい情報は Apache Module mod_rewrite に書かれている。
使用例では基本的に RewriteEngine On を前提とし、以下を省略して説明している。
RewriteEngine On RewriteBase /
レンタルサーバーによってはドメインを登録後、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]
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月に仕様が変わり、他社と同様の記述でリダイレクトできるようになった。 レンタルサーバの仕様変更について(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以外という条件を指定している。 空白(^$)を指定しても良い。
検索エンジンが 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を変更したり、クエリの仕様を変更した場合、以下のように書きたいところだが、これは出来ない。
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エンコードされる場合がある。 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]
ページのリダイレクトの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 の適当な場所に記述する。
RewriteEngine On RewriteRule (.+)\.html$ /item/view.php?p=$1 [L]
http.conf に書いた後は Apache を再起動する。
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule (.+)\.html$ /item/view.php?p=$1 [L] </IfModule>
<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>