Apache 的 mod_rewrite 和 PHP 的 REQUEST_URI 变量

Apache 的 mod_rewrite 和 PHP 的 REQUEST_URI 变量

我遇到一个问题,ApachePHP $_SERVER['REQUEST_URI']将重写后的 URL 而不是原始请求的 URL 传递给变量。

我进行重写是因为我有一个 WordPress 网站,并且想将其移动到子目录而不是放在根路径中,但仍然希望将其 URL 保留为根 URL。

这种情况并不总是发生。如果我请求,它会用(重写后的 URL)www.xyz.com/wp-admin填充 PHPREQUEST_URI变量,但如果我请求(带有尾部斜杠),它实际上会用(重写前的原始 URL)填充 PHP 变量。我想要的是使用重写前的 URL 填充。www.xyz.com/wordpress/wp-adminwww.xyz.com/wp-admin/REQUEST_URIwww.xyz.com/wp-admin/REQUEST_URI

我的.htaccess文件如下:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www.)?xyz.com$
RewriteCond %{REQUEST_URI} !^/wordpress/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /wordpress/$1
RewriteCond %{HTTP_HOST} ^(www.)?xyz.com$
RewriteRule ^(/)?$ wordpress/index.php [L]
</IfModule>`

PHP 版本是 5.3。Apache 版本是 2.4 (Win32)。


更新:我仔细研究了一下,当我输入 URL 时,www.xyz.com/wp-admin首先会出现 301 重定向www.xyz.com/wordpress/wp-admin/,但对于(带有尾部斜杠)则不会出现这种情况www.xyz.com/wp-admin/。对于带有尾部斜杠的 URL,只有重写,正如预期的那样。所以现在的问题是,为什么对于没有尾部斜杠的 URL 首先会发生 301 重定向。

需要澄清的是,没有实际的文件夹/wp-admin/,但有一个文件夹/wordpress/wp-admin/

答案1

该“问题”与 mod_dir 有关(尽管 mod_dir 严格来说不是“该”问题 - 它做了正确的事情并“修复”了 URL)。

由于wp-admin是物理目录,mod_dir 会通过附加尾部斜杠来“修复” URL(这是正确提供目录索引所必需的,例如index.php)。它使用 301 重定向来实现这一点。问题是这种情况正在发生您的内部重写导致重写变成重定向,从而暴露您的/wordpress子目录。

因此,正确的 URL 严格为/wp-admin/(末尾带有斜杠)。如果您没有/wordpress子目录,并且所有内容都在文档根目录中,则 mod_dir 只会重定向/wp-admin/wp-admin/,然后会导致/wp-admin/index.php提供服务(作为内部子请求)。

您需要做的是手动添加尾部斜杠。如果请求的 URL 不是以斜杠结尾,但会映射到子目录中的物理目录,/wordpress则添加尾部斜杠(通过外部重定向)。此重定向应该发生你的内部重写。

因此,请尝试以下操作您现有的指令:

# Append a slash if it is omitted and would map to a directory
RewriteCond %{REQUEST_URI} !^/wordpress/
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/wordpress/$1 -d
RewriteRule (.*) /$1/ [R=302,L]

这样做的目的是,对于任何尚未开始的请求/wordpress/ 不以斜线结尾,但映射到子目录中的物理目录,然后重定向并附加斜线。因此,只要存在目录,/wordpress请求/wp-admin就会被重定向。(然后您的内部重写将像以前一样路由 URL。)/wp-admin//wordpress/wp-admin

您需要确保清除了浏览器缓存(或者打开浏览器对象检查器进行测试并禁用缓存),因为之前的 301 重定向(由 mod_dir 执行)已经被缓存。

当您确定它工作正常时,请将302(临时)重定向更改为301(永久)-如果这是意图。302 被浏览器缓存,因此使测试变得更容易。


在旁边:

ApacheREQUEST_URI与 PHP$_SERVER['REQUEST_URI']

$_SERVER['REQUEST_URI']...Apache将重写后的 URL传递给 PHP变量,而不是原始请求的 URL。

Apache 实际上不会REQUEST_URI直接将 mod_rewrite 中的变量传递给 PHP。尽管这两个变量具有相同的名称,但据我所知,PHP 本身会从请求中填充此变量。

ApacheREQUEST_URI服务器变量和 PHP 的$_SERVER['REQUEST_URI']超全局变量实际上包含不同的信息:

  • PHP$_SERVER['REQUEST_URI']包含查询字符串,而 Apache 的REQUEST_URI服务器变量不包含;它仅包含 URL 路径。
  • PHP$_SERVER['REQUEST_URI']包含请求中的原始 URL 路径,而不是重写的 URL。而 Apache 的REQUEST_URI服务器变量会在整个请求过程中更新以包含重写的 URL。
  • URL 路径部分$_SERVER['REQUEST_URI']不是URL 已解码(即 % 已解码)。而 ApacheREQUEST_URI服务器变量已解码。(注意:URL 的查询字符串部分在 Apache 和 PHP 中始终保持 % 编码。如果您需要检查 Apache 中 % 编码的 URL 路径,请检查THE_REQUESTApache 服务器变量。)

相关内容