我已成功创建了一个.htaccess
可以完成我想要的操作的文件(请参阅代码块后的解释和问题):
<IfModule mod_rewrite.c>
RewriteEngine On
#1 If the requested file is not url-mapper.php (to avoid .htaccess loop)
RewriteCond %{REQUEST_FILENAME} (?<!url-mapper\.php)$
#2 If the requested URI does not end with an extension OR if the URI ends with .php*
RewriteCond %{REQUEST_URI} !\.(.*) [OR]
RewriteCond %{REQUEST_URI} \.php.*$ [NC]
#3 If the requested URI is not in an excluded location
RewriteCond %{REQUEST_URI} !^/seo-urls\/(excluded1|excluded2)(/.*)?$
#Then serve the URI via the mapper
RewriteRule .* /seo-urls/url-mapper.php?uri=%{REQUEST_URI} [L,QSA]
</IfModule>
这是应该.htaccess
做的:
规则1检查所请求的文件是否不存在
url-mapper.php
(以避免无限重定向循环)。此文件将始终位于域的根目录中。规则#2必须
.htaccess
仅捕获不以扩展名结尾的 URL(www.example.com
--> 捕获 |www.example.com/catch-me
--> 捕获 |www.example.com/dont-catch.me
--> 不捕获)和以文件结尾的 URL.php\*
(.php
,,,,...)。.php4
.php5
.php123
规则#3一些目录(及子目录)可以从中排除
.htaccess
(在本例中为/seo-urls/excluded1
和/seo-urls/excluded2
)。最后,
.htaccess
向映射器提供隐GET 参数名为uri
包含请求的 URI。
即使我测试过并且一切正常,我也想知道我所做的是否正确(以及这是否是“最佳”方法)。我从这个“项目”中学到了很多东西,但我仍然认为自己是.htaccess
正则表达式的初学者,因此在投入生产之前我想再三检查一下……
答案1
2a 将允许 /some.dir/file,因为中间有“.” 。您可能需要类似的东西!\..[1,3]
,这取决于您的文件/目录结构。
在 RewriteRules 中,使用替换匹配而不是变量名是正常的:
RewriteRule (.*) /seo-urls/url-mapper.php?uri=$5 [L,QSA]
注意,这是$5
因为您当前在所有条件中都有匹配模式。
答案2
<IfModule mod_rewrite.c>
不需要<IfModule>
包装器。请参阅网站管理员堆栈上的这个问题:
https://webmasters.stackexchange.com/questions/112600/is-checking-for-mod-write-really-necessary
#1 If the requested file is not url-mapper.php (to avoid .htaccess loop) RewriteCond %{REQUEST_FILENAME} (?<!url-mapper\.php)$
无需使用负向后视 ( (?<!
)。最好只使用否定正则表达式。即带前缀!
。例如:(!^/url-mapper\.php$
即。不是“/url-mapper.php”)并检查REQUEST_URI
(完整 URL 路径)而不是REQUEST_FILENAME
(绝对文件系统路径)。
但是,您声明“此文件将始终位于域的根目录”,但您正在重写/seo-urls/url-mapper.php
- 它不在域的根目录。
因此,严格来说应该这样写:
RewriteCond %{REQUEST_URI} !^/seo-urls/url-mapper\.php$
url-mapper.php
除非您确信系统上只有一个文件,否则正则表达式可以简化为!/url-mapper\.php$
。
或者,检查一下RewriteRule
图案相反(因为你没有对RewriteRule
图案目前)。这将是略有不同更高效。
#2 If the requested URI does not end with an extension OR if the URI ends with .php* RewriteCond %{REQUEST_URI} !\.(.*) [OR] RewriteCond %{REQUEST_URI} \.php.*$ [NC]
第一个条件太笼统了 - 它捕获 URL 路径中任何只包含点的 URL,而不仅仅是文件扩展名。也不需要捕获子模式。假设文件扩展名介于 2 到 4 个字符之间,那么像这样的模式!\.\w{2,4}$
会更准确地捕获文件扩展名。
正则表达式通常应尽可能严格。第二个条件是火柴 .php
扩展可以变得更加严格,目前它匹配.php
任何地方在 URL 路径中。例如:\.php\d{0,4}$
- 尽管实际上,后面可能最多只有 1 位数字.php
,所以\.php\d?$
可能更好。
我还想问一下NC
这里是否真的需要 (不区分大小写) 标志。你真的需要匹配.PHP
吗.PhP
?
#3 If the requested URI is not in an excluded location RewriteCond %{REQUEST_URI} !^/seo-urls\/(excluded1|excluded2)(/.*)?$
好的,但结尾(/.*)?$
是多余的。你匹配的是任何以“等”开头的/seo-urls/excluded1
内容。此外,不需要对斜杠进行反斜杠转义(奇怪的是,你转义了中间的斜杠,但没有转义其他两个斜杠)。
#Then serve the URI via the mapper RewriteRule .* /seo-urls/url-mapper.php?uri=%{REQUEST_URI} [L,QSA]
好的,尽管正则表达式.*
(匹配所有内容)可以简化为^
- 它对所有内容都成功,但实际上并不匹配任何内容 - 但这就是您所需要的。
不过,我在顶部提到了url-mapper.php
在RewriteRule
图案而是。因此,应该这样写:
RewriteRule !^seo-urls/url-mapper\.php$ /seo-urls/url-mapper.php?uri=%{REQUEST_URI} [L,QSA]
这RewriteRule
图案在任何条件之前都首先被处理,因此最好在指令中执行你能做的事情RewriteRule
,而不是将其分离到另一个条件中。
概括
综合以上几点,我们可以得出:
RewriteEgnine On
#2 If the requested URI does not end with an extension OR if the URI ends with .php*
RewriteCond %{REQUEST_URI} !\.\w{2,4}$ [OR]
RewriteCond %{REQUEST_URI} \.php\d?$
#3 If the requested URI is not in an excluded location
RewriteCond %{REQUEST_URI} !^/seo-urls\/(excluded1|excluded2)
#Then serve the URI via the mapper
RewriteRule !^seo-urls/url-mapper\.php$ /seo-urls/url-mapper.php?uri=%{REQUEST_URI} [QSA,L]