mod_rewrite のインストールと設定、RewriteRule の書き方

更新:

mod_rewrite のインストールと設定、RewriteRule の書き方について説明する。

mod_rewrite のインストールと設定

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行を追加する。 最初から書いてあればそのままで、コメントアウトされているならそれを外して有効にする。

RewriteRule の書き方

まず RewriteEngine On

RewriteEngine On
RewriteBase /

RewriteRule を使う場合、最初に RewriteEngine On を書いて使用可能な状態にする。 RewriteBase はベースとなる階層を指定できるが、必要なければ書かなくても良い。

Last

RewriteEngine On
RewriteRule ^example.html$ /hoge.php [L]

この場合、example.html にアクセスすると、hoge.php を実行する。 ブラウザの表示は example.html のまま。 [L] はルールの最終行(Last)を意味し、ルールが一致した場合、それ以降のルールは処理されない。

Redirect

RewriteEngine On
RewriteRule ^example.html$ /hoge.php [R,L]

この場合、example.html にアクセスすると、hoge.php へリダイレクトされる。 ブラウザの表示は hoge.php になる。 [R] はリダイレクトを意味する。 リダイレクトを行う際、任意のHTTPステータスコードを指定でき、何も指定しない場合は通常302がデフォルトとなる。

RewriteEngine On
RewriteRule ^example.html$ /hoge.php [R=301,L]

正規表現とパターン

RewriteRule は正規表現を用いてページへのアクセスを柔軟に制御できる。 正規表現はPHPなどでも使われる一般的な書き方。

RewriteEngine On
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つ

RewriteEngine On
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: を書く。 これらの変数は、サーバの仕様により取得できたりできなかったりするので確認する必要がある。

RewriteEngine On
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 に書かれている。

さくらインターネットのレンタルサーバでの利用

さくらインターネットのレンタルサーバでは mod_rewrite がインストールされており、RewriteRule を使用できる。

RewriteEngine On
RewriteRule book([0-9a-zA-Z_\-]+)\.html$ http://example.com/dir1/index.php?bookid=$1

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule test/(.+)\.php$ http://example.com/dir1/test/view.php?para=$1

dir1 ディレクトリに上記定義を書いた .htaccess を置く。
この場合、http://example.com/dir1/book123.html にアクセスすると、http://example.com/dir1/index.php?bookid=123 が実行される(Apache 1.3 のとき)。 また、2013年頃からさくらインターネットでは Apache 2.2 を導入し始め、上記では今までのように動作しなくなったので下記のように変更した。

RewriteEngine On
RewriteBase /
RewriteRule book([0-9a-zA-Z_\-]+)\.html$ /dir1/index.php?bookid=$1

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^test/(.+)\.php$ /dir1/test/view.php?para=$1

引数ありのURLを別のURLへリダイレクトする

引数(クエリ)付きのURLを変更したり、クエリの仕様を変更した場合、以下のように書きたいところだが、これは出来ない。

RewriteEngine On
RewriteBase /
RewriteRule ^example/test.php?a=([%-\w]+)&b=([\d]+) /example/new.php?x=$1&y=$2 [R=301,L]

以下のようにクエリを定義する必要がある。

RewriteEngine On
RewriteBase /
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] というのを書く。

RewriteEngine On
RewriteBase /
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"> へ移動させる例。

RewriteEngine On
RewriteBase /
RewriteRule ^example/(.*)$ /hoge.php#info [NE,R,L]

ドメインのwwwあり・なしへのリダイレクト

さくらのレンタルサーバはドメインを設定後、初期状態ではwwwありとなし両方のアドレスが使えるようになり、マルチドメインの設定で「wwwを付与せずマルチドメインとして使用する(上級者向け)」もあるが、.htaccess に以下のように書くとwwwありでアクセスしてきた人をwwwなしのアドレスへリダイレクトできる。

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

逆にwwwなしをwwwありにリダイレクトする場合は、wwwを書く場所を入れ替えれば良い。

httpをhttps(SSL)へリダイレクト

SSLを導入後、httpでアクセスしてきた人を強制的にhttpsへリダイレクトしたい場合は .htaccess に以下のように書く。

RewriteEngine On
RewriteBase /
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月) に説明がある。

RewriteEngine On
RewriteBase /
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 で各ディレクトリのトップページを /(スラッシュ)で終わるアドレスに統一しておく場合は以下のように書く。

RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} ^.*/index.php
RewriteRule ^(.*)index.php$ http://example.com/$1 [R=301,L]

いわゆるURLの正規化というやつ。

記述場所

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>
このエントリーをはてなブックマークに追加