首先我会告诉你如何阅读你的 RewriteRule:
您从第一个(或下一个)RewriteRule 条目开始:
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
第一个参数是一个可以匹配您请求的 URL 的正则表达式。^(.*)$
匹配所有内容,并将这个“所有内容”存储在一个可以稍后使用的变量中。
仅当存在前面的 RewriteCond 条目时,它们才会被评估:
RewriteCond $1 !^(index\.php|resources|robots\.txt)
$1
是对 RewriteRule 的第一个括号内匹配的内容的引用。这与第二个参数进行比较,第二个参数是一个正则表达式,说明几个显式名称,并且!
否定表达式,例如,此规则仅在正则表达式不匹配时才允许执行 RewriteRule。如果此条件返回 true,则将查看下一个条件。
RewriteCond %{REQUEST_FILENAME} !-f
如果请求的文件名不是硬盘上的真实文件,则此条件为真。
RewriteCond %{REQUEST_FILENAME} !-d
如果请求的文件名不是真正的目录,则此条件为真。
只有当所有这些条件都为真(它们用 AND 链接在一起)时,我们才回到重写规则:
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
这个重写步骤的结果被定义为第二个和第三个参数。$1
再次与匹配内容一起使用,并且参数定义此规则,如果最初匹配,将是最后一个规则 (L),并且重写目标中定义的任何查询字符串都将附加到任何查询字符串原始 URL (QSA)。
批判:
MVC 框架的通常重写尝试尽可能提高性能。您的重写条件都必须经过评估才能成功重写。仅当任何 RewriteCond 返回 false 时才会停止。每个被重写的请求都要经过大量的 CPU 密集型测试。首先是 RewriteRule 正则表达式,然后是第一个 RewriteCond 中的正则表达式,然后是文件系统上的两个硬盘测试文件是否存在。
另一方面,第一个 RewriteCond 似乎是不必要的。它测试某些名称,如果找到,则中止重写。“index.php”应该被第二个 RewriteCond 检测到,因为它是一个现有文件(如果不是,重写将如何工作)。任何以“resources”开头的东西也会被匹配,但出于同样的原因可能不应该匹配:现有资源将被第二个 RewriteCond 找到。最后是“robots.txt”文件。如果您想在机器人获取您的网站时避免 404,那么拥有一个可能是空的总是一个好主意。
由于您没有更改查询字符串中的任何内容,因此不需要 [QSA] 指令。
改进:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [L]
RewriteRule ^.*$ index.php [L]
第一个 RewriteRule 将匹配整个请求的路径。两个 RewriteCond 用 [OR] 连接,所以第一个返回 true 的 RewriteCond 将取消进一步的评估。第一个 RewriteCond 测试请求的文件是否存在。如果存在,则返回true,处理返回到第一个RewriteRule。目标表达式为“-”,表示“不重写”。[L] 停止对重写规则的进一步处理。所以最后,对于一个现有文件,我们只有一个正则表达式和一个文件系统测试,然后,这个现有文件将被发送到浏览器。
如果没有找到文件,第一个 RewriteRule 和 RewriteCond 不会触发,所以那里的 [L] 不会停止进程。所以第二个 RewriteRule 被执行。这个是无条件的,正则表达式和之前一样,匹配一切,重写为“index.php”。
如果存在任何文件,包括 /forum/login.php,此重写将不会调用您的 index.php。
RewriteRule ^.*$ index.php/$0 [L]
如果您确实想继续解析$_SERVER['PATH_INFO']
而不是.您可以将第二个更改为$_SERVER['REQUEST_URI']
。