Mod Rewrite + QSA:在重写目标和查询字符串中使用相同的查询字符串参数 - 强制使用目标可能吗?

时间:2012-12-07 15:45:40

标签: mod-rewrite query-string

我们有以下重写规则:

 RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L,QSA]

我们想知道是否有办法让?rewrite = $ 1优先于通过请求uri中的查询字符串传递的那个?

因为现在,由于 QSA标志(我们确实需要顺便说一句),如果点击以下网址:

 http://www.domain.com/this_rewrite_will_match_the_above_rule?rewrite=some_value

PHP中$ _GET ['rewrite']的值为 some_value ,而不是 this_rewrite_will_match_the_above规则

在我们进入并开始修改重写并添加RewriteCond以匹配查询字符串等之前......我们希望有一个标志设置以便目标url(index.php?rewrite = $ 1 in这种情况)优先于传递的查询字符串值。

希望这是有道理的。

感谢。

4 个答案:

答案 0 :(得分:2)

稍微hackish

RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]

这是有效的,因为在php中,第二个rewrite=...会覆盖第一个。{/ p>

答案 1 :(得分:2)

我已经搜索了一些机制,在Apache重写中多次覆盖单个查询字符串参数并且非常强烈,但看起来没有选项可以做到这一点,即使使用最新的Apache版本(2.4.3时)这篇文章)。

但是有一种替代方法可以利用PHP查询字符串解析器只返回多个同心查询字符串参数的最后一个事实。

示例:

http://www.domain.com/index.php?id=123&id=456

这将返回$ _GET中的以下单个(!)条目:

array(1) {
  ["id"]=>
  string(3) "456"
}

因此,您可以通过追加任何覆盖参数到现有查询字符串的末尾来解决您的问题(不在查询字符串中删除它们)。重复参数的最后一次出现是进入$ _GET数组的参数。

不幸的是QSA开关不适合这种技术,因为它总是将原始参数附加到新查询字符串的末尾。没有可以预先建立旧参数的开关。所以你必须绕着RewriteCond绕道去捕捉并预先添加原始的查询字符串,而不是使用QSA:

RewriteCond  %{QUERY_STRING}  ^(.*)$
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%1&rewrite=$1 [L]

RewriteCond的唯一功能是捕获%1中的查询字符串。条件的正则表达式(.*)始终匹配,因此始终执行以下RewriteRule。

使用这种技术,您的上述测试用例将重写为...

http://www.domain.com/index.php?rewrite=some_value&rewrite=this_rewrite_will_match_the_above_rule

...将由PHP查询字符串解析器解释为

$_GET["id"] => "this_rewrite_will_match_the_above_rule"

......这就是你想要的。

请注意,只有从PHP的$ _GET数组中获取查询字符串值时,这才有效。如果您自己解析$_SERVER["QUERY_STRING"]的内容或使用任何其他编程语言,它将不一定有效。

答案 2 :(得分:1)

我选择创建自己的答案,因为它比Jpsy和Gerben提供的示例略微清晰。

在信用到期的情况下,他们的建议是让我在这里的,我只是扩展了它们:

因此,我们的最终解决方案包括2条规则。

# check if querystring is not empty (this is the addition vs other answers)
RewriteCond %{QUERY_STRING} !^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]

如果上述查询字符串失败(主要是查询字符串为空),则此规则将适用。

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L]

我选择使用这种双规则设置的原因是,如果查询字符串为空,则避免使用“?& rewrite = ....”污染php服务器变量。

感谢jpsy和gerben的帮助。

答案 3 :(得分:0)

我使用了以下说明:

RewriteRule ([^\?]*)\?(.*) $1?$2 [N]                          (1)
RewriteCond %{QUERY_STRING} (.*?)&?(rewrite=[^&]+)&?(.*)      
RewriteRule ^(.*)$ $1?%1&%3 [N]                               (2)
RewriteRule ^(.*)$ $1?domain=newValue [L,QSA]                 (3)

技巧由前两个规则中的[N]标志完成,这会导致重写引擎以重新处理输出。

规则(1)简单地重写url。我需要它,因为我正在使用mod_rewrite togheter和mod_proxy_ajp,并且在第一次迭代中,查询字符串不会从url中分割出来。在执行第一行之后,url保持不变,但引擎将从查询字符串中拆分路径。

规则(2)迭代并从查询字符串中删除所有出现的参数“rewrite”。

规则(3)设置参数的新值,并附加规则(2)完成的替换中存活的查询字符串。