.htaccess RewriteRule - DOCUMENT_ROOT 和 RewriteBase

发布于 2024-10-01 01:22:35 字数 575 浏览 0 评论 0原文

我有一个 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 可以解决这个问题。然而,这些部分中的每一个似乎都是必需的。我想知道为什么以及每个人在我的案例中取得了什么成就。

I have a secure/ sub-directory with several files that I want to perform some simple RewriteRules on, just defaulting a PHP extension. I had a hard time getting these to work and after some trial and error stumbled upon the following.

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]

My lack of understanding is around %{DOCUMENT_ROOT} and appending /secure/. I believed either %{DOCUMENT_ROOT} or using the RewriteBase would handle this. However, each of these pieces seems to be required. I'd like to know why and what each achieves in my case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

会傲 2024-10-08 01:22:35

RewriteBase 指令 由 mod_rewrite 在重定向步骤中专门使用,并且在所有其他处理过程中都会被忽略。与文档所述相反,通常没有必要,因为(如您的情况)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

这将检查/subdirectory/file,确定它不是实际文件,并将其重写为index.php。此时,必须将新的 URL 返回给 Apache 进行内部重定向,以完成重写。由于它没有参考点,因此它最终会发送整个路径,即发送/directory/index.php。这不是您想要的,因为访问此位置的 URL 实际上是 /location/index.php。这就是 RewriteBase 的用武之地。通过

RewriteBase /location/

在 .htaccess 文件中指定,目录前缀 /directory/ 将被替换为 /location/ 作为重写后处理的一部分,导致内部重定向到预期的 URL /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]

The RewriteBase directive is used by mod_rewrite exclusively during redirection steps, and is ignored during all other processing. Contrary to what the documentation states, it's often not necessary, since (as in your case) it's fairly common for the URL to map to subdirectories in the file system beyond the DOCUMENT_ROOT.

So, what does the directive do? When your rules are being evaluated in a per-directory context as they are when using a .htaccess file, the URL is passed to mod_rewrite very late in Apache's request handling chain. This means that the URL may have already been partially translated into a file system path, so a path in /directory/subdirectory/file may have actually been accessed through the web server via /location/subdirectory/file.

This doesn't seem like much of an issue, but the fact that the /location/ piece has been lost poses an issue for mod_rewrite. To understand why, you have to know how mod_rewrite makes per-directory context rewriting possible.

When you perform a rewrite in a .htaccess file, mod_rewrite reinjects the modified request into Apache as an internal redirect, as if it was a URL. This is problematic, since the request path might not be an appropriate URL to pass. For instance, if the request ended up at /directory/subdirectory/file (which we'll assume is outside the DOCUMENT_ROOT), we might have this rule in /directory/.htaccess:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php

This would examine /subdirectory/file, decide it wasn't an actual file, and rewrite it to index.php. At this point a new URL has to be given back to Apache for the internal redirect to finalize the rewrite. Since it has no point of reference, it ends up sending the whole path—that is, it sends /directory/index.php. This isn't what you want, since the URL to access this location would actually be /location/index.php. That's where RewriteBase comes in. By specifying

RewriteBase /location/

in the .htaccess file, the directory prefix /directory/ would be swapped out for /location/ as part of this post-rewrite processing, resulting in an internal redirect to the anticipated URL /location/index.php.

This also has implications with external redirects as well. If you attempt to externally redirect using the [R] flag with just a path, and the path doesn't have a leading forward slash, the entire directory will be sent back to the client in the manner described above unless it's replaced with the value given in RewriteBase.

Neither of these points appear relevant to your situation though, so you should be fine without specifying the RewriteBase.

The %{DOCUMENT_ROOT} variable is just the the value of Apache's internal DOCUMENT_ROOT variable, which is set in your server/virtual host configuration. It always corresponds to the directory that a request to / resolves to. The -f and -d checks require a full file system path, which is why %{DOCUMENT_ROOT} needs to prepend to the relative path when using them.

For resolving the path of the current request however, mod_rewrite takes care of this for you with the %{REQUEST_FILENAME} variable. For instance, assuming that the .htaccess file lives in your /secure subdirectory, you could modify your rule set as follows:

RewriteEngine On

# Force PHP extension if not a directory
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*$ $0.php [L]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文