mod_rewrite使用[N,QSA]时%1变量未更新致GET数组异常问题
mod_rewrite循环中%1变量未更新的问题分析与解决
问题场景
你编写的mod_rewrite脚本意图移除不存在的路径段,并将这些路径段以数组形式传递给PHP脚本,但实际运行时,$_GET['folder']数组的所有元素都是第一个路径段的值(比如['this','this','this','this']),而非预期的['this','folder','isnt','real']。原代码如下:
RewriteEngine On LogLevel alert rewrite:trace3 # 当前请求指向的文件/文件夹是否不存在? RewriteCond /var/www/vhosts/example.org/httpdocs/fswtest%{REQUEST_FILENAME} !-f RewriteCond /var/www/vhosts/example.org/httpdocs/fswtest%{REQUEST_FILENAME} !-d # URL中是否存在文件夹?获取列表中的第一个 RewriteCond %{REQUEST_URI} /([^/]+)/ # 仅从REQUEST_URI中移除第一个文件夹并重新开始 RewriteRule ./(.*) /$1?folder[]=%1 [N,QSA]
问题原因
核心问题出在RewriteCond的反向引用(%1)在[N]循环中不会重新更新:
- 当使用
[N]标志触发循环时,Apache会重新执行整个重写规则集,但RewriteCond中的捕获组(%1)是在规则集第一次执行时捕获的初始值,后续循环不会重新匹配RewriteCond的正则表达式来更新%1。 - 简单说,
%1被缓存成了第一次匹配到的this,后续循环复用了这个值,导致每次添加到数组的都是同一个字符串。
解决方案
把路径段的捕获逻辑从RewriteCond转移到RewriteRule中,利用RewriteRule的捕获组($1、$2等)——这些捕获组会在每次循环时基于当前更新后的URI重新计算:
RewriteEngine On LogLevel alert rewrite:trace3 # 当前请求指向的文件/文件夹是否不存在? RewriteCond /var/www/vhosts/example.org/httpdocs/fswtest%{REQUEST_FILENAME} !-f RewriteCond /var/www/vhosts/example.org/httpdocs/fswtest%{REQUEST_FILENAME} !-d # 匹配并捕获当前URI的第一个路径段,移除后继续循环 RewriteRule ^/([^/]+)/(.*)$ /$2?folder[]=$1 [N,QSA]
工作原理
- 第一次循环:匹配
/this/folder/isnt/real/whatever.php,捕获$1=this,重写为/folder/isnt/real/whatever.php?folder[]=this,触发循环。 - 第二次循环:匹配
/folder/isnt/real/whatever.php,捕获$1=folder,重写为/isnt/real/whatever.php?folder[]=this&folder[]=folder,触发循环。 - 重复此过程,直到URI变为
/whatever.php,此时检查文件存在,循环停止。最终$_GET['folder']会得到预期的数组['this','folder','isnt','real']。
内容的提问来源于stack exchange,提问作者Lance McDonald
相关产品推荐
相关产品推荐

