具有重写功能的基本文件夹中的绝对URL


Absolute URL from base folder with rewrite

我有一个项目在WampServer上本地运行。它是一个类似MVC的结构;它将URL重写为CCD_ 1。完整.htaccess:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

当我想使用PHP location: <location>将用户发送到另一个页面时,由于重写(尽管从技术上讲,我总是在index.php中),它无法正确地执行此操作。

例如,如果我在http://localhost/project_name/controller/method/上,并且此控制器的构造函数或方法试图将我发送到:

  • header('location: another_controller/method');将我发送到http://localhost/project_name/controller/method/another_controller/method/
  • header('location: /another_controller/method');将我发送到http://localhost/another_controller/method/

但我希望它像这样发给我:

  • index.php?url=$10将我发送到http://localhost/project_name/another_controller/method/

现在我找到的唯一解决方案是:

define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');

但这也不完美,因为每当域名或文件夹名更改时,我都必须更改这个定义的常量BASE_URL。我也可以在BaseController中创建一个创建绝对URL的方法,但这个方法基本上也只是在BASE_URL之前。

注意:HTML的srchref属性不会出现同样的问题,它们可以使用相对路径(路径中没有project_name文件夹)。我不明白为什么。因为如果头location导致浏览器将相对URL附加到当前位置,为什么它在查找.css.js文件时没有相同的行为。

所以这给我提出了几个问题:

  1. 如果我有虚拟主机,我会遇到这个问题吗
  2. 解决这个问题的最佳方法是什么
  3. 最好只是有完整的绝对URL吗
  4. 为什么HTML的srchref属性不共享这种行为

现在我找到的唯一解决方案是:

define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');

但这也不完美,因为这让我不得不改变每当域或文件夹名称更改。

您不需要更改定义的常量。这些值可以动态找到。

示例:

if ($_SERVER['DOCUMENT_ROOT'] == dirname($_SERVER['SCRIPT_FILENAME'])) {
    define('BASE_PATH', '/');
} else {
    define('BASE_PATH', dirname($_SERVER['SCRIPT_NAME']) . '/');
}
$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
define('BASE_URL', $protocol . $_SERVER['SERVER_NAME'] . BASE_PATH);

此外,不必担心是指定一个绝对URL还是一个路径,您可以将重定向封装到一个可以同时处理这两个问题的函数中:

function redirect($path = null) {
    if (isset($path)) {
        if (filter_var($path, FILTER_VALIDATE_URL)) {
            header('Location: ' . $path);
        } else {
            header('Location: ' . BASE_URL . $path);
        }
    } else {
        header('Location: ' . BASE_URL);
    }
    exit;
}

最后,正如@HarshSanghani在评论中提到的那样,.htaccess文件中的基本路径应该与代码中的基础路径匹配。因此,如果BASE_PATH(基于上面的例子)输出/project_name/,那么您的.htaccess应该适应它:

RewriteBase /project_name/

回答您的问题:

  1. 这取决于虚拟主机的配置方式
  2. 您可以简单地动态生成BASE_URL:$baseUrl = dirname($_SERVER['SCRIPT_NAME']);。这样,如果您的文件夹或域发生更改,您就不必更改任何代码
  3. 您不需要域部分
  4. html srchref由浏览器进行解释,浏览器会考虑页面的<base>标记。浏览器会相应地更改带有<base>标记的页面上的所有路径

您从服务器发送的HTTP标头(用于重定向)与您发送的html页面无关,因此不会更新。

  1. 如果你把你的项目设置在一个子目录中,你就会遇到这个问题。如果你想在project_name.localhost上设置虚拟主机,那么使用虚拟主机将是解决这个问题的一种方法
  2. 在我的项目中,我使用一个环境变量来加载不同的配置文件,用于开发、暂存或生产。在这个过程中,我以某种方式设置了一个$baseUri
  3. 最好的做法是使用绝对URL(包括域)来解决这个问题和SEO。就功能而言,您不需要域部分
  4. src和href标记通常以相同的方式工作,但正如Andreas所提到的,它们可能会受到基本标记的影响

您应该在htaccess文件中指定RewriteBase。在你的链接中使用相对路径,你就不需要更多了。

RewriteBase /project_name/
RewriteEngine on
RewriteCond $1 !'.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]