删除除已经重写的所有查询字符串

时间:2013-08-29 20:26:37

标签: php .htaccess mod-rewrite query-string

我有所有查询字符串,我需要将其重写为SEO友好的URL,如

RewriteRule ^item_([0-9]+)/$ database.php?type=product&id=$1 [L]
RewriteRule ^post_([0-9]+)/$ articles.php?id=$1 [L]
... and so on

但是我想删除任何其他查询字符串,例如 item_123 /?foo = bar database.php?foo = bar post_123 /?类型搜索引擎优化和安全原因导致产品& id = 321

显而易见的放置解决方案

RewriteCond %{QUERY_STRING} (.+)
RewriteRule (.*) http://www.example.com/$1? [R=301,L]
<。>在.htaccess的末尾处理之前没有bean处理过的所有事情,并且[L]标签停止实际上会破坏原始的RewriteRule并将 item_123 / 重定向到空的数据库。 php ,没有参数。

是否可以删除除早先mod_rewritten之外的所有查询字符串而不明确写下所有%{REQUEST_URI}和%{QUERY_STRING}对的异常?

编辑:

解决方案A

# You do not need this whole block if you're running Apache v2.3.9+
RequestHeader set SOME-FANCY-NAME-FOR-THE-HEADER-AS-DESCRIBED-IN-THE-ABOVE-LINK 1 env=END

RewriteCond %{HTTP:SOME-FANCY-NAME-FOR-THE-HEADER-AS-DESCRIBED-IN-THE-ABOVE-LINK} =1 [NV]
RewriteRule .* - [L]

由于[END]标志仅适用于Apache v2.3.9 +,因此我使用了a workaround which would emulate this behaviour

# Replace [L,E=END:1] with [END] if running Apache v2.3.9+
RewriteCond %{THE_REQUEST} ^GET\ [^?]+$
RewriteRule ^item_([0-9]+)/$ database.php?type=product&id=$1 [L,E=END:1]

首先简单地限制THE_REQUEST中的任何?将导致找不到item_123/?foo=bar模式的重复页面(404)。 [L,E=END:1]标志告诉mod_rewrite停止当前迭代并重复;下一次迭代将触发RewriteRule .* - [L]并阻止它到达我们之后的潜在循环。 [END]标志如果支持,将立即停止。

RewriteCond %{QUERY_STRING} type=product
RewriteCond %{QUERY_STRING} id=([0-9]+)
RewriteRule ^database\.php$ http://www.example.com/item_%1/? [R=301,L]

这也将database.php?type=product&foo=bar&id=123模式的可能受损的重复页面重定向(301)到正确的URL,而不管查询中的乱码参数。一旦它到达正确的URL,它将停在那里而不会导致循环和错误500。

# If page is accessible without parameters

RewriteCond %{THE_REQUEST} ^GET\ [^?]+$
RewriteRule ^catalog/$ database.php [L,E=END:1]

RewriteCond %{THE_REQUEST} ^GET\ [^?]+\?
RewriteRule ^database\.php$ http://www.example.com/catalog/? [R=301,L]

如果可以访问此页面而不使用上述?type&type等参数,但访问database.php?foo=bardatabase.php?,则会将其重定向(301)到{{1}没有查询字符串。同样,将找不到catalog/模式的页面(404)。

catalog/?foo=bar

如果在没有参数的情况下无法访问页面,我们可以强制停止重写(以避免以后不必要的重定向,例如我们将# If page is not accessible without parameters RewriteCond %{THE_REQUEST} ^GET\ [^?]+\? RewriteRule ^database(\.php|/)?$ database.php [L,E=END:1] 重写为anyotherfile.php)并使页面本身发送404标头一旦它知道没有传递有效参数。

溶液A + B

来自accepted solution的代码本身是正确的,而我的版本扩展了重写以匹配许多其他格式不正确的模式。

在完成上述所有代码后,从接受的解决方案中添加代码将捕获anyotherfile/item_123/?foo=bar模式的(以前)未找到的链接,并将它们(301)重定向到正确的URL {{ 1}}和catalog/?foo=bar没有查询字符串。这是有道理的,因为即使用户遵循由某些RSS聚合器等修改的链接,用户也会到达他想要的位置。在上述代码中将item_123/更改为catalog/并使用%{QUERY_STRING} (.+)代替%{THE_REQUEST} ^GET\ [.?]+\?也会删除跟踪问号 - %{THE_REQUEST} ^GET\ [^?]+$ - 否则会被忽略,如果加入,则计为重复页面。

%{QUERY_STRING} ^$

3 个答案:

答案 0 :(得分:2)

L标志不会停止。如果你更改了URL(你做了),它会重新注入。因此,对于您所做的每个内部重定向(重写),最后一个条件都可以,然后触发最后一次重写:

RewriteCond %{QUERY_STRING} (.+)
RewriteRule (.*) http://www.example.com/$1? [R=301,L]

由于这个删除了查询字符串(以?结尾,没有QSA标志),因此您将使用不带参数的php脚本结束:

rewrite #1/1: item_5/ -> database.php?type=product&id=5
              L triggered, because URL changed, re-inject:
rewrite #1/2: database.php?type=product&id=5 -> http://www.example.com/database.php?
              R triggered, exiting

rewrite #2/1: http://www.example.com/database.php? -
              no rule matches, use as-is

相反,您需要在最后放置一个条件,以便不重定向.php文件:

RewriteCond %{QUERY_STRING} (.+)
RewriteCond %{REQUEST_URI} !^/[a-z]+\.php$    
RewriteRule (.*) http://www.example.com/$1? [R=301,L]

或者如果你有一个更现代的apache服务器版本,只需使用END标志:

RewriteRule ^item_([0-9]+)/$ database.php?type=product&id=$1 [END]
RewriteRule ^post_([0-9]+)/$ articles.php?id=$1 [END]
... and so on

答案 1 :(得分:0)

我不知道这是否有帮助,但我处理的方法是将不存在的文件发送到特定的php文件(rewrite.php)

RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^.*$ ./rewrite.php

这让我可以轻松处理我遇到的每一个案例

答案 2 :(得分:0)

您可以使用以下方法来避免这种情况:

RewriteRule ^item_([0-9]+)/.*$ abc.php?type=product&id=$1 [L]

我添加.*以匹配斜线后的任何内容,但它仍然是重定向的有效模式。