我有一个带有几个文件的 secure / 子目录,我想要执行一些简单的RewriteRules,只是默认PHP扩展。我很难让这些工作起来,经过一些试验和错误后发现了以下情况。
RewriteEngine On
RewriteBase /secure
# Force PHP extension if not a directory
RewriteCond %{DOCUMENT_ROOT}/secure/%{REQUEST_URI} -d
RewriteRule ^(.*)$ - [L]
RewriteCond %{DOCUMENT_ROOT}/secure/$1.php -f
RewriteRule ^((.*/)*[^./]+)/*$ $1.php [L]
我缺乏理解的是%{DOCUMENT_ROOT}
并附加/secure/
。我相信%{DOCUMENT_ROOT}
或使用RewriteBase
会处理此问题。但是,似乎需要这些部件中的每一件。我想知道为什么以及每个人在我的案例中取得的成就。
答案 0 :(得分:11)
mod_rewrite在重定向步骤中专门使用RewriteBase directive,并在所有其他处理期间被忽略。与文档所述相反,通常没有必要,因为(在您的情况下),URL映射到文件系统中超出DOCUMENT_ROOT
的子目录是相当常见的。
那么,该指令的作用是什么?当您在使用.htaccess文件时在每个目录上下文中评估规则时,URL会在Apache的请求处理链中很晚地传递给mod_rewrite。这意味着URL可能已经部分转换为文件系统路径,因此 / directory / subdirectory / file 中的路径实际上可能已通过Web服务器通过 / location /访问子目录/文件
这似乎不是什么大问题,但 / location / 部分丢失的事实对mod_rewrite造成了问题。要了解原因,您必须知道mod_rewrite如何使每个目录的上下文重写成为可能。
当您在.htaccess文件中执行重写时,mod_rewrite会将修改后的请求作为内部重定向重新注入Apache,就像它是一个URL一样。这是有问题的,因为请求路径可能不是要传递的适当URL。例如,如果请求最终在 / directory / subdirectory / file (我们假设它在DOCUMENT_ROOT
之外),我们可能在 / directory /中有此规则htaccess的:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php
这将检查 /子目录/文件,确定它不是实际文件,并将其重写为 index.php 。此时,必须将新URL返回给Apache以进行内部重定向以完成重写。由于它没有参考点,它最终会发送整个路径 - 也就是说,它发送 /directory/index.php 。这不是您想要的,因为访问此位置的URL实际上是 /location/index.php 。这就是RewriteBase的用武之地。通过指定
RewriteBase /location/
<。>在.htaccess文件中,目录前缀 / directory / 将作为此重写后处理的一部分换出 / location / ,从而产生内部重定向到预期的网址 /location/index.php 。
这也会影响外部重定向。如果您尝试使用[R]
标志仅使用路径进行外部重定向,并且路径没有前导斜杠,则整个目录将以上述方式发送回客户端,除非它被替换为RewriteBase中给出的值。
这些点都不会与你的情况相关,所以你应该没有指定RewriteBase。
%{DOCUMENT_ROOT}
变量只是Apache内部DOCUMENT_ROOT
变量的值,该变量在服务器/虚拟主机配置中设置。它始终对应于 / 请求解析的目录。 -f
和-d
检查需要完整的文件系统路径,这就是%{DOCUMENT_ROOT}
在使用它们时需要在相对路径前面添加的原因。
然而,为了解析当前请求的路径,mod_rewrite使用%{REQUEST_FILENAME}
变量为您处理此问题。例如,假设.htaccess文件位于 / secure 子目录中,您可以按如下方式修改规则集:
RewriteEngine On
# Force PHP extension if not a directory
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*$ $0.php [L]