.htaccessファイルのRewriteRuleルールで[E=VAR:VAL]
フラグを使用して(PHPで使用するために)Apache環境変数を設定しようとしています。
変数はPHPサーバー変数として$_SERVER
ではなく$_ENV
(ある程度の意味はあります)]でアクセスされることを既に発見しています。しかし、私の問題はいくつかのルールは[E=VAR:VAL]
フラグが期待どおりに動作し、変数$_SERVER['VAR']
で終わりますが、他のルールでは変数$_SERVER['REDIRECT_VAR']
または$_SERVER['REDIRECT_REDIRECT_VAR']
などで終わります
A. Apacheで[E=VAR:VAL]
フラグを使用して設定された環境変数が、変数名の前に「REDIRECT_」を追加することで名前が変更される原因は何ですか?
B.環境変数の名前が変更されていないことを確認して、バリエーションのチェックに頼らずにPHP as $_SERVER['VAR']
]でアクセスできるようにするためにできること「REDIRECT_」のインスタンスが1つ以上付加された変数名の
部分的な解決策が見つかりました。書き換えルールの先頭に次を追加すると、必要に応じて、各リダイレクトで元のENV:VARが再作成されます(REDIRECT_VARバージョンがそのまま残ります)。
RewriteCond %{ENV:REDIRECT_VAR} !^$
RewriteRule .* - [E=VAR:%{ENV:REDIRECT_VAR}]
この動作は残念であり、文書化されていないようです。
.htaccess
ディレクトリごと(ディレクトリごと)のコンテキストで発生するように見えるものは次のとおりです。
Apacheが書き換えディレクティブを含む.htaccess
ファイルを処理すると仮定します。
Apacheは、環境変数マップにすべての標準CGI/Apache変数を取り込みます
書き換えが始まります
環境変数はRewriteRule
ディレクティブで設定されます
ApacheがRewriteRule
ディレクティブの処理を停止すると(L
フラグまたはルールセットの最後)、RewriteRule
によってURLが変更されると、Apacheは要求処理を再開します。
この部分に慣れていない場合は、 L
フラグのドキュメント を参照してください。
したがって、ルールセットは最初から再度実行される場合があります。最も一般的には、ルールの1つがリダイレクト(内部または外部)を引き起こし、要求プロセスを最初からやり直す場合に発生します。
私が観察できることから、#4が発生すると#1が繰り返され、RewriteRule
ディレクティブで設定された環境変数にREDIRECT_
が追加され、環境変数マップ(必ずしもその順序である必要はありませんが、最終結果はその組み合わせで構成されます)。
このステップでは、選択した変数名が消去されます。すぐに、それが非常に重要で不便な理由を説明します。
もともとこの問題に遭遇したとき、.htaccess
(簡略化)で次のようなことをしていました。
RewriteCond %{HTTP_Host} (.+)\.projects\.
RewriteRule (.*) subdomains/%1/docroot/$1
RewriteRule (.+/docroot)/ - [L,E=EFFECTIVE_DOCUMENT_ROOT:$1]
最初のRewriteRule
で環境変数を設定すると、Apacheは書き換えプロセスを再開し、変数にREDIRECT_
を追加します(上記の手順4および5)。したがって、私が割り当てた名前を介して。
この場合、最初のRewriteRule
がURLを変更するため、両方のRewriteRule
sが処理された後、Apacheはプロシージャを再起動し、.htaccess
を再度処理します。 2回目は、最初のRewriteRule
はRewriteCond
ディレクティブのためにスキップされますが、2番目のRewriteRule
は一致し、環境変数を(再び)設定し、そして重要なことにURLを変更しません。そのため、リクエスト/書き換えプロセスは最初からやり直さず、私が選んだ変数名は固執します。この場合、実際にはREDIRECT_EFFECTIVE_DOCUMENT_ROOT
とEFFECTIVE_DOCUMENT_ROOT
の両方があります。最初のL
でRewriteRule
フラグを使用する場合、EFFECTIVE_DOCUMENT_ROOT
しかありません。
@trowelの部分的な解決策も同様に機能します。書き換えディレクティブが再度処理され、名前が変更された変数が元の名前に再び割り当てられます。URLが変更されない場合、プロセスは終了し、割り当てられた変数名が保持されます。
これらの手法にはどちらも大きな欠陥があります。環境変数を設定する.htaccess
ファイルの書き換えルールが、書き換えを行う.htaccess
ファイルを持つ、より深くネストされたディレクトリにURLを書き換えると、割り当てられた変数名は再び消去されます。
次のようなディレクトリレイアウトがあるとします。
docroot/
.htaccess
A.php
B.php
sub/
.htaccess
A.php
B.php
そして、次のようなdocroot/.htaccess
:
RewriteRule ^A\.php sub/B.php [L]
RewriteRule .* - [E=MAJOR:flaw]
したがって、/A.php
をリクエストすると、sub/B.php
に書き換えられます。 MAJOR
変数がまだあります。
ただし、docroot/sub/.htaccess
に書き換えディレクティブがある場合(RewriteEngine Off
またはRewriteEngine On
だけでも)、MAJOR
変数は消えます。これは、URLがsub/B.php
に書き換えられると、docroot/sub/.htaccess
が処理され、書き換えディレクティブが含まれている場合、docroot/.htaccess
の書き換えディレクティブは再度処理されないためです。 REDIRECT_MAJOR
が処理された後にdocroot/.htaccess
があった場合(たとえば、最初のL
からRewriteRule
フラグを省略した場合)、まだありますが、選択した変数名を設定するためにディレクティブが再び実行されることはありません。
だから、あなたがしたいことを言う:
ディレクトリツリーの特定のレベルでRewriteRule
ディレクティブに環境変数を設定します(docroot/.htaccess
など)
それらをより深いレベルのスクリプトで利用可能にする
割り当てられた名前で利用可能にする
より深くネストされた.htaccess
ファイルに書き換えディレクティブを含めることができる
考えられる解決策は、より深くネストされたRewriteOptions inherit
ファイルで.htaccess
ディレクティブを使用することです。これにより、ネストの浅いファイルで書き換えディレクティブを再実行し、上記の手法を使用して、選択した名前で変数を設定できます。ただし、より深くネストされたディレクトリから再度実行したときに問題が発生しないように、より深くネストされていないファイルの書き換えディレクティブをより慎重に作成する必要があるため、これにより複雑さが増します。 Apacheは、より深くネストされたディレクトリのディレクトリごとのプレフィックスを削除し、その値でより深くネストされていないファイルで書き換えディレクティブを実行すると信じています。
私が見る限り、RewriteRule
E
フラグ(たとえば、%{ENV:REDIRECT_VAR}
)の値コンポーネントで[E=VAR:%{ENV:REDIRECT_VAR}]
のような構造を使用するためのサポートはそうではないようです。 文書化 :
VALには、展開される後方参照($ Nまたは%N)が含まれる場合があります。
それは動作しているように見えますが、文書化されていない何かに依存することを避けたい場合(それについて間違っている場合は私を修正してください)、代わりにこの方法で簡単に行うことができます:
RewriteCond %{ENV:REDIRECT_VAR} (.+)
RewriteRule .* - [E=VAR:%1]
文書化された動作 (以下を参照)と一貫していないように見えるため、これに依存することはお勧めしませんが、これは(docroot/.htaccess
で、Apache 2.2.20で)私のために働く:
SetEnvIf REDIRECT_VAR (.+) VAR=$1
この方法でテストできるのは、以前のSetEnvIf [NoCase]ディレクティブで定義された環境変数のみです。
これらの名前の前にREDIRECT_
を付ける理由はわかりません。 mod_rewrite directives のApacheドキュメントセクションで言及されていないので、驚くことではありません。 RewriteRule
flags 、または 環境変数 。
現時点では、割り当てられた名前をそのままにしておくよりも良い理由についての説明がないので、私には大きな迷惑のようです。ドキュメントの欠如は、それについての私の懐疑にのみ貢献します。
書き換えルールで環境変数を割り当てることができると便利です。または、少なくともそうするでしょう。しかし、この名前を変更する動作により、有用性は大幅に低下します。この投稿の複雑さは、この振る舞いとそれを乗り越えようとする際に乗り越えなければならないフープがいかに重要であるかを示しています。
私はこれをまったくテストしておらず、ポイントAまたはBに対応していないことを知っていますが、PHPドキュメントおよびアクセスするためのいくつかの可能なソリューションのコメントにこの問題の説明があります$_SERVER['VAR']
を使用したこれらの変数:
http://www.php.net/manual/en/reserved.variables.php#79811
[〜#〜] edit [〜#〜]-提示された質問に対するいくつかの回答:
A:環境変数は、リダイレクトに関係している場合、Apacheによって名前が変更されます。たとえば、次のルールがある場合:
RewriteRule ^index.php - [E=VAR1:'hello',E=VAR2:'world']
その後、$_SERVER['VAR1']
と$_SERVER['VAR2']
を使用してVAR1とVAR2にアクセスできます。ただし、次のようにページをリダイレクトする場合:
RewriteRule ^index.php index2.php [E=VAR1:'hello',E=VAR2:'world']
次に、$_SERVER['REDIRECT_VAR1']
などを使用する必要があります。
B:この問題を克服する最良の方法は、PHPの使用に関心のある変数を処理することです。 $_SERVER
配列を実行し、必要なアイテムを見つける関数を作成します。次のような関数を使用することもできます。
function myGetEnv($key) {
$prefix = "REDIRECT_";
if(array_key_exists($key, $_SERVER))
return $_SERVER[$key];
foreach($_SERVER as $k=>$v) {
if(substr($k, 0, strlen($prefix)) == $prefix) {
if(substr($k, -(strlen($key))) == $key)
return $v;
}
}
return null;
}
コードを変更したくないので(使用するライブラリのコードを変更することもできません)、次のアプローチを取りました。 _index.php
_で– _$_ENV
_スーパーグローバルをリワークして、_REDIRECT_
_で始まる変数が通常の目的の名前に書き換えられるようにします。
_// Fix ENV vars getting prepended with `REDIRECT_` by Apache
foreach ($_ENV as $key => $value) {
if (substr($key, 0, 9) === 'REDIRECT_') {
$_ENV[str_replace('REDIRECT_', '', $key)] = $value;
putenv(str_replace('REDIRECT_', '', $key) . '=' . $value);
}
}
_
_$_ENV
_に直接設定するだけでなく、putenv()
を使用して保存します。このようにして、既存のコードとライブラリ(getenv()
を使用する場合があります)は正常に機能します。
補足:コード内でヘッダーを抽出する場合(_HTTP_AUTHORIZATION
_など)、_$_SERVER
_に対して同じ種類の操作を行う必要があります。
_foreach ($_SERVER as $key => $value) {
if (substr($key, 0, 9) === 'REDIRECT_') {
$_SERVER[str_replace('REDIRECT_', '', $key)] = $value;
}
}
_