Абсолютный URL из базовой папки с переписыванием

У меня есть проект, работающий локально на 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: <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/

Но я хочу, чтобы он пришёл мне так:

  • header('location: /another_controller/method'); отправляет меня 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 src и href, которые могут использовать относительные пути (без project_name папки в пути). Однако я не понимаю, почему. Потому что, если заголовок location заставляет браузер добавлять относительный URL-адрес к текущему местоположению, почему он не имеет такого же поведения при поиске файлов .css или .js.

Итак... для меня возникает несколько вопросов:

  • Будет ли у меня эта проблема, если бы у меня были виртуальные хосты?
  • Каков наилучший способ решить эту проблему?
  • Лучше всего иметь полный абсолютный URL-адрес?
  • Почему атрибуты HTML src и href не используют это поведение?

Ответ 1

Теперь единственным решением, которое я нашел, является:

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

Но это не идеально, потому что это заставляет меня менять это определяется константой BASE_URL всякий раз, когда имя домена или папки изменения.

Вам не нужно менять определенную константу. Эти значения можно найти динамически.

Пример:

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/

Ответ 2

Чтобы ответить на ваши вопросы:

  • Это зависит от того, как будут настроены ваши виртуальные хосты.
  • Вы можете просто генерировать свой BASE_URL динамически: $baseUrl = dirname($_SERVER['SCRIPT_NAME']);. Таким образом, вам не придется менять код, если ваша папка или домен меняются.
  • Вам не нужна часть домена.
  • html src и href интерпретируются вашим браузером, который учитывает тег <base>. Все пути на странице с тегом <base> будут соответствующим образом изменены вашим браузером.

HTTP-заголовки, отправляемые с вашего сервера (для перенаправления), не имеют ничего общего с отправляемой вами html-страницей и поэтому не обновляются.

Ответ 3

  • У вас будет эта проблема, если ваш проект настроен в подкаталоге. Использование виртуальных хостов было бы способом обойти эту проблему, если бы вы захотели установить их по имени, project_name.localhost.
  • В моих проектах я использую переменную среды для загрузки другого конфигурационного файла для разработки, постановки или производства. В этом я как-то установил $baseUri.
  • Лучше всего использовать абсолютные URL-адреса (включая домен) как для решения этой проблемы, так и для SEO. Что касается функциональности, вам не нужна часть домена.
  • Теги src и href обычно работают одинаково, но, как сказал Андреас, на них может повлиять базовый тег.

Ответ 4

Вы должны указать RewriteBase в файле htaccess. Используйте относительные пути в своих ссылках, и вам больше ничего не нужно.

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]