RewriteCondディレクティブ:URLのリライト/リダイレクトを行う条件を定義する

RewriteCond ディレクティブは、 RewriteRule ディレクティブによって URL のリライトやリダイレクトが行われる条件を定義します。一つまたは複数の条件を定義し、条件が真となった場合にその直後に記述された RewriteRule ディレクティブが評価されます。ここでは Apache の RewriteCond ディレクティブの使い方について解説します。

(Last modified: )

RewriteCondディレクティブの使い方

RewriteCond ディレクティブはリライト/リダイレクト先が実行される条件を定義する場合に使用します。書式は次のとおりです。

RewriteCond 文字列|変数 正規表現パターン [フラグ]

記述できる場所は httpd.conf, VirtualHost, Directory, .htaccess です。 .htaccess で設定する場合は AllowOverride FileInfo が設定されている必要があります。

RewriteCond ディレクティブでは文字列または変数に格納された値が正規表現パターンとマッチするかどうかを調べます。マッチした場合は、直後に記述された RewriteRule ディレクティブを評価します。

RewriteEngine on
RewriteCond xxx xxxxx
RewriteRule yyy yyyyy

RewriteCond ディレクティブで設定した条件が適用されるのは、直後に記述された RewriteRule ディレクティブだけです。別の RewriteRule ディレクティブに対して条件を設定したい場合は別途 RewriteCond ディレクティブを記述する必要があります。

複数の条件をANDまたはORで記述する

一つの RewriteRule ディレクティブに対して複数の RewriteCond ディレクティブを設定することができます。

RewriteEngine on
RewriteCond xxx1 xxxxx1
RewriteCond xxx2 xxxxx2
RewriteCond xxx3 xxxxx3
RewriteRule yyy yyyyy

複数の RewriteCond ディレクティブで記述した場合、特に指定しなければ AND の扱いとなります。上記の場合であれば 3 つの RewriteCond ディレクティブがすべて真となった場合だけ RewriteRule ディレクティブが評価されます。

複数の RewriteCond ディレクティブで記述した場合に、少なくとも一つの RewriteCond ディレクティブが真となった場合に RewriteRule ディレクティブが評価されるようにするには、フラグに[OR]を指定します。

RewriteEngine on
RewriteCond xxx1 xxxxx1 [OR]
RewriteCond xxx2 xxxxx2 [OR]
RewriteCond xxx3 xxxxx3
RewriteRule yyy yyyyy

上記の場合であれば 3 つの RewriteCond ディレクティブの少なくともひとつが真となった場合に RewriteRule ディレクティブが評価されます。

使用可能な変数の一覧

RewriteCond ディレクティブでは文字列または変数をそのあとに記述した正規表現パターンとマッチするかどうかを調べますが、変数を使用する場合は次の変数が使用可能です 。

【HTTP headers】
HTTP_ACCEPT        クライアントがサポート可能なMIMEタイプ
HTTP_COOKIE        クッキーに関するデータ
HTTP_FORWARDED     プロキシのURI
HTTP_HOST          リクエスト先のサーバ名
HTTP_PROXY_CONNECTION  プロキシの接続形態
HTTP_REFERER       参照元のURL
HTTP_USER_AGENT    ユーザーエージェント

【connection & request】
AUTH_TYPE          認証方式
CONN_REMOTE_ADDR   ピアIPアドレス
CONTEXT_PREFIX
CONTEXT_DOCUMENT_ROOT
IPV6               IPv6ならon、そうでないならoff
PATH_INFO          パス情報
QUERY_STRING       クエリ文字列
REMOTE_ADDR        リモートアドレス
REMOTE_HOST        リモートホスト
REMOTE_IDENT       IDENTによるユーザー名
REMOTE_PORT        ポート番号
REMOTE_USER        認証されたユーザー名
REQUEST_METHOD     HTTPリクエストメソッド(GETなど)
SCRIPT_FILENAME    REQUEST_FILENAMEと同じ

【server internals】
DOCUMENT_ROOT      DocumentRootディレクティブの値
SCRIPT_GROUP       スクリプトグループのグループ名
SCRIPT_USER        スクリプトオーナーのユーザー名
SERVER_ADDR        サーバアドレス
SERVER_ADMIN       ServerAdminディレクティブ
SERVER_NAME        ServerNameディレクティブ
SERVER_PORT        ServerNameディレクティブのポート番号
SERVER_PROTOCOL    リクエストのプロトコル名とバージョン
SERVER_SOFTWARE    サーバのソフトウェア情報

【date and time】
TIME_YEAR          現在の年(2021)
TIME_MON           現在の月(01,02,...,12)
TIME_DAY           現在の日(01,02,...,31)
TIME_HOUR          現在の時(00,01,...,23)
TIME_MIN           現在の分(00,01,...,59)
TIME_SEC           現在の秒(00,01,...,59)
TIME_WDAY          現在の曜日(0,1,...6) 0=Sunday
TIME               日付と時刻(20211231235959)

【specials】
API_VERSION        APIバージョン
CONN_REMOTE_ADDR   ピアIPアドレス
HTTPS              HTTPSならonそうでないならoff
IS_SUBREQ          サブリクエストならtrue
REMOTE_ADDR        リモートホストのIPアドレス
REQUEST_FILENAME   リクエストに一致するファイルやスクリプトのパス
REQUEST_SCHEME     リクエストスキーマ
REQUEST_URI        リクエストURIのパス部分
THE_REQUEST        完全なリクエストライン(GET /index.html HTTP/1.1)

上記に記載した変数名の一覧の中から使用する変数名を %{変数名} として記述します。例えばリクエスト先のサーバ名が www.example.com と一致するか調べる場合は次のように記述します。

RewriteCond %{HTTP_HOST} ^www\.example\.com$

また次の変数も利用可能です。

%{ENV:variable}  指定した環境変数の値
%{SSL:variable}  指定したSSL環境変数の値
%{HTTP:header}   指定したHTTPリクエストヘッダの値

リクエストに対して各変数に実際にどのような値が格納されるのかを簡単に確認してみます。下記は http://www.example.com/old/hello.html?num=10 へアクセスした場合に各変数に格納された値です。

%{HTTP_HOST}         www.example.com
%{HTTP_USER_AGENT}   Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/88.0.4324.104%20Safari/537.36

%{IPV6}              off
%{QUERY_STRING}      num=10
%{REMOTE_ADDR}       192.168.10.104
%{REQUEST_METHOD}    GET
%{SCRIPT_FILENAME}   D:/pg/Apache/Apache24/htdocs/old/hello.html

%{DOCUMENT_ROOT}     D:/pg/Apache/Apache24/htdocs
%{SERVER_PROTOCOL}   HTTP/1.1
%{SERVER_SOFTWARE}   Apache/2.4.43%20(Win64)%20PHP/7.4.7

%{TIME_YEAR}         2021
%{TIME_MON}          02
%{TIME_DAY}          07
%{TIME_HOUR}         21
%{TIME_MIN}          39
%{TIME_SEC}          56
%{TIME_WDAY}         0
%{TIME}              20210207213956

%{API_VERSION}       20120211:92
%{HTTPS}             off
%{REMOTE_ADDR}       192.168.10.104
%{REQUEST_FILENAME}  D:/pg/Apache/Apache24/htdocs/old/hello.html
%{REQUEST_SCHEME}    http
%{REQUEST_URI}       /old/hello.html
%{THE_REQUEST}       GET%20/old/hello.html%3fnum=10%20HTTP/1.1

%{HTTP:Accept-Encoding}  gzip,%20deflate
%{HTTP:Accept-Language}  ja,en;q=0.9,en-US;q=0.8

正規表現パターンを指定する

文字列または変数の値が、指定した正規表現パターンとマッチした場合に真となり直後に記述された RewriteRule が評価されます。 Apache で使用する正規表現は Perl 互換のものです。例えば www.example.com とマッチするパターンは次のように記述できます。

^www\.example\.com$

^ は先頭とマッチし、 $ は末尾とマッチします。この正規表現は、先頭から www.example.com で始まり、そしてこの文字列の後には何も記述されていない文字列とマッチします。

※ 正規表現を使った詳しいパターンの記述方法については「正規表現入門」を参照されてください。

正規表現パターンで利用可能な構文

正規表現パターンの箇所には正規表現のパターンを記述するだけでなく次の構文を記述することもできます。

!パターン       マッチしない場合にtrue
<パターン       文字列として比較、辞書順で小さい場合にtrue
>パターン       文字列として比較、辞書順で大きい場合にtrue
=パターン       文字列として比較、辞書順で等しい場合にtrue
<=パターン      文字列として比較、辞書順で等しいか小さい場合にtrue
>=パターン      文字列として比較、辞書順で等しいか大きい場合にtrue
-eqパターン     数値として比較、等しい場合にtrue
-geパターン     数値として比較、等しいか大きい場合にtrue
-gtパターン     数値として比較、大きい場合にtrue
-leパターン     数値として比較、等しいか小さい場合にtrue
-ltパターン     数値として比較、小さい場合にtrue
-neパターン     数値として比較、値が異なる場合にtrue(!-eqと同じ)

-d           実際に存在しディレクトリだった場合にtrue
-f           実際に存在しファイルの場合にtrue
-F           アクセス可能な有効なパスの場合にtrue
-h           -l と同じ(-lを使うとまぎらしい場合に使用)
-l           シンボリックリンクの場合にtrue
-L           -l と同じ(-lを使うとまぎらしい場合に使用)
-s           サイズが0でないファイルの場合にtrue
-U           アクセス可能な有効なURLの場合にtrue
-x           実行権限がある場合にtrue

例えば 2020/12/31 23:59:59 までは http://example.com/ へリダイレクトを行い、それ以降は http://www.example.jp/ へリダイレクトする場合は次のように記述します。

RewriteEngine On
RewriteCond %{TIME} <20201231235959
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
RewriteCond %{TIME} >=20210101000000
RewriteRule ^(.*)$ http://example.jp/$1 [R=301,L]

※ 上記の例ですが実際には 2 つ目の RewriteCond ディレクティブは記載しなくても同じ結果になるのですが、分かりやすいようにあえて記載してあります。

フラグを設定する

RewriteCond ディレクティブではフラグを設定することで条件を判定する場合の挙動を変更することができます。

RewriteCond 文字列|変数 正規表現パターン [フラグ]

RewriteCond ディレクティブで用意されているフラグは 3 つですが、複数のフラグを設定する場合はカンマ(,)で区切って記述します。空白などをいれないようにご注意ください。

[フラグA,フラグB]

それぞれのフラグの使い方についてご説明します。

NCフラグ

文字列または変数の値と正規表現パターンを比較するときに大文字と小文字を区別せずに比較します。

RewriteCond 文字列|変数 正規表現パターン [NC]

ORフラグ

複数の RewriteCond ディレクティブを記述するときに、 AND ではなく OR で真か偽かを判定する。つまり複数のディレクティブのいずれか一つでも真だった場合は、直後にある RewriteRule ディレクティブを評価する。

RewriteCond 文字列|変数 正規表現パターン [OR]

NVフラグ

RewriteCond ディレクティブの変数名で HTTP ヘッダーを指定した場合に、レスポンスの Vary ヘッダーに HTTP ヘッダを設定します。

RewriteCond 文字列|変数 正規表現パターン [OR]

※ Vary ヘッダーについては少し古い記事ですがこちらが参考になりました。「スマホ向け表示を分けているときはVary HTTPヘッダーを使うこと

RewriteCondディレクティブの動作確認

それでは実際に RewriteCond ディレクティブを記述してみます。今回はドキュメントルートに設置した .htaccess の中で記述します。今回は wwww なしの example.com へアクセスがあった場合に www 付きの www.example.com へリダイレクトする処理を記述します。その為に、 RewriteCond ディレクティブを使って www なしの example.com へアクセスがあったかどうかの条件判断を記述します。

まずドキュメントルートに .htaccess を作成します。( .htaccess の中でリライトに関する設定が有効となるように httpd.conf にて AllowOverride ディレクティブの設定が必要です。詳しくは「AllowOverrideディレクティブ:.htaccessを使った設定の上書きを許可する」を参照されてください)。

RewriteCondディレクティブの動作確認(1)

.htaccess には次のように記述しました。

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

※ RewriteEngine ディレクティブはリライト機能を有効にするためのディレクティブです。

それでは www なしの http://example.com/new/hello.html へアクセスしてください。

RewriteCondディレクティブの動作確認(2)

RewriteCond ディレクティブが真となるためその直後に記述された RewriteRule ディレクティブが評価され、 www 付きの www.example.com へリダイレクトされます。

RewriteCondディレクティブの動作確認(3)

正規表現パターンで後方参照を使用する

RewriteCond ディレクティブの正規表現パターンの中で括弧()で囲んだパターンとマッチした文字列を、 RewriteRule ディレクティブの置換 URL の中で参照して使用することができます。次の例をみてください。

RewriteEngine on
RewriteCond %{QUERY_STRING} page=(.*)
RewriteRule ^index.html$ /%1/index.html? [R=301,L]

ドキュメントルートに設置した .htaccess に記述しました。 RewriteCond ディレクティブの正規表現パターンの中の括弧で囲まれた .* の部分にマッチした文字列を、 RewriteRule ディレクティブの置換 URL の中で %1 として参照しています。

今回の場合は、リクエストの中のクエリー文字列の page に対する値の部分が .* の部分にマッチします。そして直後の RewriteRule ディレクティブの中で、リダイレクト先のディレクトリとして参照した値を使用しています。なおリダイレクト先の最後に ? が記述してあるのは、リクエストにあったクエリー文字列をリダイレクト先では付けないようにするためです。

例えば http://www.example.com/index.html?page=old へアクセスしてみます。

正規表現パターンで後方参照を使用する(1)

括弧で囲まれた .* の部分には old がマッチするため、 http://www.example.com/old/index.html へリダイレクトされます。

正規表現パターンで後方参照を使用する(2)

-- --

Apache の RewriteCond ディレクティブの使い方について解説しました。

( Written by Tatsuo Ikura )

Profile
profile_img

著者 / TATSUO IKURA

プログラミングや開発環境構築の解説サイトを運営しています。