Абсолютный 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]