ApacheのSetEnvで設定した環境変数は、RewriteCond,SetEnvIfでは参照できない
先にも書いたように、
ApacheのSetEnvで設定した環境変数は、 RewriteCond , SetEnvIf など環境変数を参照するディレクティブから参照できないです。
できないことを確認してみる
先のように ApacheのSetEnvで設定した環境変数は、RewriteCond,SetEnvIfでは参照できない ことを確認してみます。
例えば、/var/www/html/ がドキュメントのルートディレクトリとすると、以下のように設定したとします。
/var/www/html/.htaccess
RewriteEngine On
SetEnv VAL_A 1
RewriteCond %{ENV:VAL_A} 1
RewriteRule ^$ /readme.html
|
これの期待している動作は、
無条件にルートディレクトリへの参照は、readme.html へリダイレクトする
なのですが、これは、全く動作しません。
これは、Rewriteモジュールのログを確認してみるとすぐにわかります。
...
192.168.1.100 - - [18/Apr/2013:09:27:18 +0900] [www.example.com/sid#2e78450][rid#30ee798/initial] (4) [perdir /var/www/html/] RewriteCond: input='' pattern='1' => not-matched
...
|
このログの意味は、
RewriteCond
で指定された入力情報(ここでは、 %{ENV:VAL_A}
)が 空(=”)で、チェックパターンは、‘1’でした。
結果は、not-matched
(一致しなかった)ということです。
当然ですよね、入力情報が空(=”)なんですからね。
このように直前で設定した環境変数は参照できません。(参照しても値が設定されていないのです。)
先のログ出力のように Rewriteの判定内容などのログを出力するには、
Rewriteモジュールのログを 以下のように
VirtualHost
内に設定すればOKです。
<VirtualHost *:80>
ServerName www.example.com
DocumentRoot "/var/www/html"
DirectoryIndex index.php index.html
...
RewriteLog "/var/log/httpd.rewrite.log"
RewriteLogLevel 9
...
</VirtualHost>
|
RewriteLog
: ログの出力先ファイル名を指定します。
RewriteLogLevel
: ログレベルを指定します。9以上は、ほぼ全てのログ情報を出力しますので、何か問題があって情報を採取したい場合は、まず、9を設定しておきましょう。
設定を終えたら、Apacheを再起動しましょう。
$ /etc/init.d/httpd restart
...
|
回避先(SetEnvIf)を確認してみる
この回避策としてあるのが、SetEnvIf (or SetEnvIfNoCase)
ディレクティブを SetEnv
の代わりに使用することです。
先の できないことを確認してみる で設定した例(/var/www/html/.htaccess)は、以下のように編集することになります。
/var/www/html/.htaccess
RewriteEngine On
SetEnvIf _ .* VAL_A=1
RewriteCond %{ENV:VAL_A} 1
RewriteRule ^$ /readme.html
|
SetEnv VAL_A 1
→ SetEnvIf _ .* VAL_A=1
と変更されました。
この設定では、無条件にVAL_A
に 1 を設定するようになっています。
これを実行してみると、
無条件にルートディレクトリへの参照は、readme.html へリダイレクトする
ようになります。
これも同じように、Rewriteモジュールのログを確認してみるとすぐにわかります。
...
192.168.1.100 - - [18/Apr/2013:11:36:46 +0900] [www.example.com/sid#2e78450][rid#30ee798/initial] (4) [perdir /var/www/html/] RewriteCond: input='1' pattern='1' => matched
...
|
RewriteCond
で指定された入力情報(ここでは、 %{ENV:VAL_A}
)が ‘1’で、チェックパターンは、‘1’でした。
結果は、matched
(一致した)となって期待どおりの動作になりました。
複雑な条件でリダイレクトしてみる(おまけ)
最後に、この環境設定(SetEnvIf (or SetEnvIfNoCase)
ディレクティブ)を上手く使うとリダイレクトの条件設定が楽になることがあります。
先の 回避先(SetEnvIf)を確認してみる で設定した例(/var/www/html/.htaccess)は、あまりにも単純ですが、
実際にリダイレクト(転送)の条件は、そうそう単純でもありません。
例えば、以下のような処理を考えてみます。
if ( (変数A=1 AND 変数B=2) OR (変数C=3 AND 変数C=4) ) {
RewriteCond ^$ /readme.html
}
|
RewriteCond
は、上から順番に 何も指定がなければ AND 処理を行います。
上記のように括弧で順番がある場合は、結構、面倒なことになります。
これを環境変数で代替えすれば、案外、すっきりすることがあります。
/var/www/html/.htaccess
RewriteEngine On
# 変数A=1 ?
SetEnvIf VAL_A 1 check_a=1
# 変数B=2 ?
SetEnvIf VAL_B 2 check_b=1
# 変数C=3 ?
SetEnvIf VAL_C 3 check_c=1
# 変数D=4 ?
SetEnvIf VAL_D 4 check_d=1
# (変数A=1 AND 変数B=2) ?
SetEnvIf check_b !1 check_a=0
# (変数C=3 AND 変数C=4) ?
SetEnvIf check_d !1 check_c=0
RewriteCond %{ENV:check_a} 1 [OR]
RewriteCond %{ENV:check_c} 1
RewriteRule ^$ /readme.html
|
RewriteCond
だけで実現しようと思うと、結構、面倒くさいことになりますが、SetEnvIf
を絡めるとわかりやすくはなりますね。
(これでも Nginxの設定に比べると回りくどいですが・・・。)
Apacheとnginxの両方を扱ったことがある方には、ここら辺のApacheのまどろっこしさは嫌になる点ではないでしょうか。
nginxは、後発だけあって、Apacheの悪いところは、引き継がないように設計されているんだと思います。なので、概ね、ほぼ、思ったとおりの動作してくれます。
しかし、Apacheは、何かにつけて条件が付いてきます。ここでの SetEnv
でもそうです。
マニュアルも読まずに、普通に これぐらいできるだろう・・・なんてやっていると大はまりしてしまいます。
マニュアルを ちゃんと読まないヤツが悪いんですけどね。気を付けましょ。
コメントを投稿 :