Php 基本文件夹中的绝对URL(带重写)

Php 基本文件夹中的绝对URL(带重写),php,.htaccess,mod-rewrite,relative-path,absolute-path,Php,.htaccess,Mod Rewrite,Relative Path,Absolute Path,我有一个项目在WampServer上本地运行。它是一个类似MVC的结构;它将URL重写为index.php?URL=$1。完整.htaccess: RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-l RewriteRule ^(.+)$ index.php?url=$1 [QSA,L] 当我想使用

我有一个项目在WampServer上本地运行。它是一个类似MVC的结构;它将URL重写为
index.php?URL=$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:
将用户发送到另一个页面时,由于重写的原因,它无法正确执行此操作(尽管从技术上讲,我总是在
index.PHP

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

  • 标题(“位置:另一个控制器/方法”)将我发送到
    
    http://localhost/project_name/controller/method/another_controller/method/
  • header('location:/other_controller/method')将我发送到
    
    http://localhost/another_controller/method/
但我希望它能像这样发送给我:

  • header('location:/other_controller/method')将我发送到
    
    http://localhost/project_name/another_controller/method/
现在我找到的唯一解决方案是:

define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');
define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');
但这也不是完美的,因为每当域名或文件夹名称发生更改时,它都会导致我必须更改定义的常量
BASE\u URL
。我还可以在我的
BaseController
中创建一个方法来创建绝对URL,但这个方法基本上也只是在
BASE\u URL
前面加上前缀

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

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

  • 如果我有虚拟主机,我会有这个问题吗
  • 解决这个问题的最好办法是什么
  • 最好只是拥有完整的绝对URL
  • 为什么HTML的
    src
    href
    属性不共享此行为

  • 回答您的问题:

  • 这取决于虚拟主机的配置方式
  • 只需动态生成基本URL即可:
    $baseUrl=dirname($\u SERVER['SCRIPT\u NAME'])。这样,如果文件夹或域发生更改,您就不必更改任何代码
  • 您不需要域部分
  • html
    src
    href
    由您的浏览器解释,其中考虑了页面的
    标记。浏览器会相应地更改带有
    标记的页面上的所有路径
  • 从服务器发送的HTTP头(用于重定向)与发送的html页面无关,因此不会更新

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

    define('BASE_URL','http://localhost/project_name');
    header('location: '.BASE_URL.'/another_controller/method/');
    
    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\u PATH
    (基于上面的示例)输出
    /project\u name/
    ,那么您的
    .htaccess
    应该适应它:

    RewriteBase /project_name/
    
  • 如果将项目设置在子目录中,就会出现此问题。如果您想在project_name.localhost上设置虚拟主机,那么使用虚拟主机将是解决这个问题的一种方法
  • 在我的项目中,我使用一个环境变量为开发、登台或生产加载不同的配置文件。在这里,我以某种方式设置了一个
    $baseUri
  • 使用绝对URL(包括域)是解决此问题和SEO的最佳实践。就功能而言,您不需要域部分
  • 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]
    

    你能从添加的@HarshSanghani开始为你的htaccess文件添加一些代码吗?你能在RewriteEngine之后添加RewriteBase/project\u name/吗on@HarshSanghani这并没有解决它<代码>标题('位置:/')仍然转到
    http://localhost/
    http://localhost/project_name/
    。我注意到你说“
    标题('location:other_controller/method');
    将我发送到
    http://localhost/project_name/controller/method/another_controller/method/
    ”我想指出的是,这种情况永远都会发生——你忘记了前导斜杠。如果没有前导斜杠,它将始终是从当前URL开始的相对重定向。不确定这是打字错误还是完全无关,但我想我会指出这一点。