在Apache RewriteRule指令中设置环境variables时,是什么原因导致variables名以“REDIRECT_”为前缀?

我试图用.htaccess文件中的RewriteRule规则中的[E=VAR:VAL]标志设置Apache环境variables(用于PHP)。

我已经发现variables在PHP中作为服务器variables$_SERVER而不是$_ENV (这有一定的意义)被访问。 然而,我的问题是一些规则[E=VAR:VAL]标志按预期工作,最后我得到了一个variables$_SERVER['VAR']但对于其他规则我以variables$_SERVER['REDIRECT_VAR']$_SERVER['REDIRECT_REDIRECT_VAR']

A.什么原因使用[E=VAR:VAL]标志在Apache中设置的环境variables通过将“REDIRECT_”添加到variables名称来重命名?

B.我能做些什么来确保最终得到一个名称不变的环境variables,这样我就可以在PHP中以$_SERVER['VAR']访问它,而不必求助于variables名的变体它有更多的“REDIRECT_”实例吗?

部分解决schemefind 。 将以下内容添加到重写规则的开始处,重新创build每个redirect上的原始ENV:VAR(以及在那里保留REDIRECT_VAR版本)(如果需要的话):

 RewriteCond %{ENV:REDIRECT_VAR} !^$ RewriteRule .* - [E=VAR:%{ENV:REDIRECT_VAR}] 

这种行为是不幸的,甚至没有logging。

.htaccess per-dir上下文

以下是在每个目录(per-dir)上下文中.htaccess出现的情况:

假定Apache处理包含重写指令的.htaccess文件。

  1. Apache使用所有标准的CGI / Apachevariables填充其环境variables映射

  2. 重写开始

  3. 环境variables在RewriteRule指令中设置

  4. 当Apache停止处理RewriteRule指令(由于L标志或规则集的末尾),并且URL已被RewriteRule更改时,Apache将重新启动请求处理。

    如果您不熟悉这部分,请参阅L标志文档 :

    因此规则集可以从头再次运行。 如果其中一个规则导致redirect(无论是内部的还是外部的)导致请求过程重新开始,则通常会发生这种情况。

  5. 从我所能观察到的情况来看,我认为当#4发生时,#1被重复,那么在RewriteRule指令中设置的环境variables被预置为REDIRECT_并被添加到环境variables映射中(不一定按顺序,但结束结果由该组合组成)。

    这一步是selectvariables名被删除的地方,一会儿我会解释为什么这么重要和不方便。

恢复variables名称

当我最初遇到这个问题时,我在.htaccess (简体)中做了如下的事情:

 RewriteCond %{HTTP_HOST} (.+)\.projects\. RewriteRule (.*) subdomains/%1/docroot/$1 RewriteRule (.+/docroot)/ - [L,E=EFFECTIVE_DOCUMENT_ROOT:$1] 

如果我要在第一个RewriteRule设置环境variables,Apache将重新启动重写过程,并在REDIRECT_ (上述步骤#4和5)前加上variables,因此我将无法通过分配的名称访问该variables。

在这种情况下,第一个RewriteRule更改URL,所以在两个RewriteRule都被处理之后,Apache将重新启动该过程并再次处理.htaccess 。 第二次,由于RewriteCond指令,第一个RewriteRule被跳过,但第二个RewriteRule匹配,设置环境variables(重新),重要的是, 不改变URL 。 所以请求/重写过程不会重新开始,而我select的variables名称为stick。 在这种情况下,我实际上同时拥有REDIRECT_EFFECTIVE_DOCUMENT_ROOTEFFECTIVE_DOCUMENT_ROOT 。 如果我在第一个RewriteRule上使用L标志,我只会有EFFECTIVE_DOCUMENT_ROOT

@ trowel的部分解决scheme的工作原理类似:重写指令再次被处理,重命名的variables再次被分配给原始名称,并且如果URL不改变,则该过程结束并且分配的variables名称被粘住。

为什么这些技术是不够的

这两种技术都有一个主要缺陷:当设置环境variables的.htaccess文件中的重写规则将URL重写为更深层嵌套的目录,而该目录具有执行任何重写的.htaccess文件时,将分配您的variables名称再次出来。

假设你有这样的目录布局:

 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 。 你仍然有你的MAJORvariables。

但是,如果在docroot/sub/.htaccess有任何重写指令(即使只是RewriteEngine OffRewriteEngine On ), MAJORvariables也会消失。 这是因为一旦URL被重写为sub/B.phpdocroot/sub/.htaccess被处理,并且如果它包含任何重写指令,则docroot/.htaccess中的重写指令不会再被处理。 如果在docroot/.htaccess被处理后有一个REDIRECT_MAJOR (例如,如果你省略了第一个RewriteRuleL标志),你仍然可以拥有它,但是那些指令不会再运行来设置你select的variables名。

遗产

所以,你要说:

  1. RewriteRule指令中设置目录树的特定级别的环境variables(如docroot/.htaccess

  2. 让他们在更深层次的脚本中可用

  3. 让他们与指定的名称

  4. 能够在更深嵌套的.htaccess文件中重写指令

一个可能的解决scheme是在嵌套更深的.htaccess文件中使用RewriteOptions inherit指令。 这允许您在较less深度嵌套的文件中重新运行重写指令,并使用上述技巧来使用所选名称设置variables。 但是请注意,这会增加复杂性,因为您必须更小心地在嵌套较less的文件中构build重写指令,以便在从更深层嵌套的目录再次运行时不会造成问题。 我相信Apache会剥离更深层嵌套的目录的per-dir前缀,并在该值较深的嵌套文件中运行重写指令。

@抹子的技术

就我所见,支持在RewriteRule E标志的值组件(例如[E=VAR:%{ENV:REDIRECT_VAR}] )中使用类似%{ENV:REDIRECT_VAR}的构造似乎没有logging :

VAL可能包含将被扩展的反向引用($ N或%N)。

它似乎工作,但如果你想避免依赖没有logging的东西(请纠正我,如果我错了),可以很容易地做到这一点:

 RewriteCond %{ENV:REDIRECT_VAR} (.+) RewriteRule .* - [E=VAR:%1] 

SetEnvIf之后

我不build议依靠这个,因为它似乎不符合logging的行为 (见下文),但是这个(在Apache 2.2.20的docroot/.htaccess )适用于我:

 SetEnvIf REDIRECT_VAR (.+) VAR=$1 

只有那些由早期的SetEnvIf [NoCase]指令定义的环境variables才能以这种方式进行testing。

为什么?

我不知道用REDIRECT_为这些名称加前缀的基本原理是什么 – 这并不奇怪,因为在Apache文档部分没有提到mod_rewrite指令 , RewriteRule标志或环境variables 。

目前,对于我来说这似乎是一个很大的麻烦,因为没有解释为什么比单独分配名字更好。 文件的缺乏只会造成我对此的怀疑。

能够在重写规则中分配环境variables是有用的,或者至less是这样。 但是这种改变名字的行为大大减less了用处。 这个post的复杂性说明了这个行为是如何的坚决,以及为了克服这个行为而必须跳过的环节。

我没有testing过这一点,我知道它没有解决A或B的问题,但是在PHP文档的注释中有一些关于这个问题的描述,以及一些使用$_SERVER['VAR']

http://www.php.net/manual/en/reserved.variables.php#79811

编辑 – 对提供的问题做出更多回应:

答:如果涉及到redirect,环境variables将由Apache重命名。 例如,如果您有以下规则:

 RewriteRule ^index.php - [E=VAR1:'hello',E=VAR2:'world'] 

然后你可以使用$_SERVER['VAR1']$_SERVER['VAR2']来访问VAR1和VAR2。 但是,如果您像这样redirect页面:

 RewriteRule ^index.php index2.php [E=VAR1:'hello',E=VAR2:'world'] 

那么你必须使用$_SERVER['REDIRECT_VAR1']

B:解决这个问题的最好方法是处理你对使用PHP感兴趣的variables。 创build一个运行在$_SERVER数组中的函数,并find你需要的项目。 你甚至可以使用这样的函数:

 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; }