2010-04-16 45 views
0

我试图编写一个规则来使这个可以概括,因为多个页面传递的值是不同的。现在我可以这样做:URL中的很多未定义参数的一般RewriteRule

RewriteRule ^forum/([^/]{1,255})/([\+]{1})/((([a-z]+)([_]{1})([a-zA-Z0-9]+)([/]?))+)$ forum.php?name=$1&$5=$7 [L] 

为了解决诸如:

Nome+del+Forum/+/page_1/action_do 

应返回:

forum.php?name=Nome+del+Forum&page=1&action=do 

相反,只需要最后一个参数(在这种情况下行动=):

forum.php?name=Nome+del+Forum&action=do 

我该如何解决?提前致谢!

回答

0

最简单的方法是,如果您可以在网站配置中输入RewriteMap prg:foo。请注意,就我所知,您不能在.htaccess中使用RewriteMap

如果你有访问服务器的配置文件,添加这样的事情,无论是在全球还是在<VirtualHost>

RewriteMap forum prg:/path/to/forum-rewriter.pl 

然后在你选择的.htaccess尝试:

RewriteRule ^forum/.* ${forum:$0} [QSA] 

(在你尝试RewriteRule它看起来像你想匹配的路径开始于forum/所以这就是我在这里做的。)

接下来你需要做forum-rewriter.pl

#!/usr/bin/perl 

use strict; 
use warnings; 


$| = 1; 
while ($_ = <STDIN>) { 
    chomp($_); 
    if (s,^forum/([^/]+)(/\+)?(/.*)?,forum.php?name=$1, && $3) { 
     my $query_string = $3; 
     $query_string =~ s,/([^/_]+)_([^/_]+),&$1=$2,g; 
     $_ .= $query_string; 
    } 
    print "$_\n"; 
} 

确保chmod 755 /path/to/forum-rewriter.pl

RewriteMap将导致Apache在启动时为每个httpd进程启动forum-rewriter.pl一次。每当RewriteRule的模式匹配时,它就会写入forum-rewriter.pl stdin的路径。 forum-rewriter.pl将在URL上完成其工作(如果有)并将结果打印回Apache。

仅供参考,它很容易测试forum-rewriter.pl。只要运行它,并开始发送它的路径:

$ /tmp/forum-rewriter.pl 
forum/Nome+del+Forum/+/page_1/action_do 
forum.php?name=Nome+del+Forum&page=1&action=do 
forum/Nome+del+Forum/page_1/action_do 
forum.php?name=Nome+del+Forum&page=1&action=do 
forum/Nome+del+Forum 
forum.php?name=Nome+del+Forum 
foo 
foo 

如果您不能使用RewriteMap,我想这可能与mod_rewrite但我认为这是很危险的

RewriteCond %{ENV:SetForumName} ="" 
RewriteRule ^forum/([^/]+)(/\+)?(/.*)? /forum.php$3?name=$1 [QSA,E=SetForumName:1] 
RewriteCond %{ENV:SetForumName} !="" 
RewriteRule ^forum.php/([^/_]+)_([^/_]+)(/.*)? /forum.php$3?$1=$2 [N,QSA] 

这是危险的,因为这[N]导致Apache在第二个RewriteRule匹配时重新开始处理所有重写规则。如果你不小心,你会创建一个无限循环,并且Apache将要求500或者咆哮。还要注意它设置SetForumName环境变量的副作用。但是,这是我能找到的唯一方法,可以告诉mod_rewrite“在查询字符串中用foo=bar替换全部foo_bar”。

0

类似于this

另请参阅this了解其他信息。

的基本信息是这些规则

RewriteCond %{QUERY_STRING} ^(.*)$ 
RewriteRule ^(.*/)([^/]+)/([^/]+) $1?$2=$3&%1 [L] 
RewriteCond %{QUERY_STRING} ^(.*)$ 
RewriteRule ^([^/]+)/ $1?%1 [L] 

将改写以下

/mypage/param1/val1/param2/val2/param3/val3/...  ---> 
/mypage?param1=val1&param2=val2&param3=val3&... 

它采用第一个参数,调用页面。剩下的参数变成查询字符串。

编辑更多关于代码如何工作。

第一行(和第三行)仅捕获“?”后的所有内容以便可以将其添加回重写的URL的末尾。同样的事情 可以用[QSA]标志完成,但我更愿意明确地做到这一点,所以它是可见的。

该字符串保存在%1变量中。

第二行使用正则表达式将URL拆分为三部分。

$ 2和$ 3是路径的最后两部分。 $ 1就是之前的一切。

所以这样的:

/mypage/param1/val1/param2/val2/param3/val3/param4/val4/param5/val5/ 

变为这样:

$1              $2  $3 
/mypage/param1/val1/param2/val2/param3/val3/param4/val4/ param5 val5 

,并改写为这个(空间增加了可读性):

/mypage/param1/val1/param2/val2/param3/val3/param4/val4/ ? param5 = val5 

如果你的URL采用了比其他分隔斜线,您可以相应地修改常规 表达式。

[L](“last”)标志防止其余规则运行。 然而 - 这是关键 - mod_rewrite调用网址为 的网址,并且新的网址再次通过mod_rewrite发送!这有时被称为mod_rewrite递归,正是你想要的工作。

下一次通过时,接下来的两部分被剥离结束并将 添加到查询字符串。

此:

$1           $2  $3  %1 
/mypage/param1/val1/param2/val2/param3/val3 param4 val4 ? param5=val5 

变为这样:

/mypage/param1/val1/param2/val2/param3/val3 ? param4 = val4 & param5=val5 

这不断发生,直到URL的所有部分被转换成 部分查询字符串。当发生这种情况时,第二行不符合 ,但第四行不符合。这是什么给你最终的URL来呼吁你想要的 程序。上面的链接显示的答案略有不同 ,允许不同的规则。

另请注意,mod_rewrite 可能递归的次数有限制。请参阅.htaccess中的 MaxRedirects和您的apache conf文件中的设置 LimitInternalRecursion

+0

对不起,但我不明白!我不想要完整的代码,但了解代码如何。 页面将始终是论坛和值不用斜线分隔,而是“_”或“:”。使用此代码:

\t RewriteCond %{QUERY_STRING} ^(.*)$ \t RewriteRule ^forum/([^/]{1,255})/([^/]+)([:]{1})([^/]+) \t viewforum.php?name=$1&$2=$4&%3 [L] 
它工作一半,只取第一个参数。 谢谢! – 2010-04-17 08:37:45

+0

FedericoBiccheddu,我添加了更多的解释。我希望这有帮助。我知道你的URL使用'_'而不是'/',但是如果你使用一个稍微不同的正则表达式,这个概念应该也可以工作。 – bmb 2010-04-17 15:51:16