Я хочу создать mod_rewrite RewriteRule который не зависит от места, где установлена веб-страница. Я хочу определить правило перезаписи в файле .htaccess. Возьмем это для примера:
RewriteEngine on
RewriteRule ^(.*)\.html html.php
С помощью этого правила я хочу сопоставить все запросы * .html со сценарием html.php, который находится в корневом веб-каталоге. Проблема в том, что общедоступный базовый URL-адрес корневого веб-сайта может измениться. Таким образом, корень сети может быть расположен на http://www.somewhere.tld/
или в каком-то подкаталоге на http://www.somewhere.tld/foo/bar/
.
Но использование относительного пути в правиле перезаписи не работает. Поэтому я должен написать одно из них:
/html.php (When web is located in root directory of the web)
/foo/bar/html.php (When web is located in foo/bar sub directory)
В качестве альтернативы я могу установить RewriteBase, но я просто не хочу настраивать этот путь вообще. Я хочу, чтобы apache автоматически выполнял правильные действия, чтобы я мог просто скопировать Интернет в какой-либо каталог, и он просто работал, не сообщая правилам перезаписи, где находится Интернет. Как я могу это сделать?
Я боролся с той же проблемой и по той же причине. Я пытаюсь сделать веб-приложение независимым от места, где оно установлено, не прибегая к сценарию конфигурации или ручному вмешательству пользователя. Просто перетащите приложение куда-нибудь, и пусть оно сделает свое дело.
И, похоже, решение все-таки есть, по крайней мере, для Apache 2. Занимает четыре строчки. Однако для объяснения того, что за этим стоит, уходит более четырех строк;)
Tl; dr попробуйте это:
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)\1$
RewriteRule ^(.*)$ %2index.php [QSA,L]
Вот как и почему
Мы не можем установить RewriteBase динамически, поэтому мы устанавливаем его раз и навсегда на корневой URL-адрес сервера: RewriteBase /
. Это обеспечивает согласованность, но это также означает, что мы должны сами установить URL-путь к текущему каталогу и добавить его к перезаписанному URL-адресу.
Так в каком каталоге мы находимся? Предположим, что REQUEST_URI
из / некоторый / путь / app-root / virtual / stuff. Наш htaccess находится в корневом каталоге приложения. Если мы возьмем виртуальную часть - virtual / stuff - и удалим ее из REQUEST_URI
, у нас остается URL-путь к нашему каталогу приложения.
Захват виртуальной части несложен и может происходить в самом правиле перезаписи. RewriteRule ^(.*)$ ...
делает его доступным в $1
переменная.
Теперь мы выполняем нашу небольшую строковую операцию и удаляем виртуальную часть из URI запроса. У нас нет строковых команд для этого, но RewriteCond может сопоставлять строки и захватывать подстроки. Итак, мы добавим RewriteCond с единственной целью - извлечь URL-путь к текущему каталогу. Помимо этого, «условие» не должно мешать нам и всегда быть верным.
Мы можем использовать $1
из RewriteRule в RewriteCond, потому что mod_rewrite фактически обрабатывает набор правил в обратном порядке. Он начинается с шаблона в самом правиле и, если он совпадает, переходит к проверке условий. Так что к тому времени переменная будет доступна.
В то время как тестовая строка в RewriteCond может использовать переменную, фактическое регулярное выражение условия не может. Внутри условия мы можем использовать только внутренние обратные ссылки. Итак, сначала мы собираем тестовую строку «[виртуальная часть] [некоторый разделитель] [запрос uri]». Символ '#' является хорошим разделителем, потому что он не отображается в URL-адресе. Затем мы сопоставляем его с условием
([^#]*) - anything up to the separator, captures the virtual part
# - the separator
(.*?) - anything in the request uri up to what we've captured in group one,
grabs the current directory url-path
\1$ - group one again, ie the virtual part of the request uri
Итак, вот полное условие: RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)\1$
.
Вторая захваченная группа в регулярном выражении RewriteCond - это наше местоположение. Нам просто нужно добавить префикс к перезаписанному URL-адресу %2
ссылка. Это оставляет нас с RewriteRule ^(.*)$ %2index.php [QSA,L]
. Вуаля.
Я еще не проводил обширного тестирования, но установил, что он работает как с обычными виртуальными хостами, так и с массовым виртуальным хостингом (с использованием VirtualDocumentRoot). Подразумевается, что и другие местоположения с псевдонимом тоже подойдут.
Apache 1.3
К сожалению, Apache 1.3 все еще существует, и он подавится шаблоном RewriteCond. Apache 1.3 не поддерживает модификатор ungreedy ('?' В (.*?)
).
Но для Apache 2 это должно помочь. Я определенно буду признателен за любую обратную связь, особенно если она не работает в вашей среде.
Редактировать: Я только что разместил более подробную статью на эту тему на своем блог ("Использование mod_rewrite в файлах .htaccess без знания RewriteBase"). Подробнее см. Там.
Насколько мне известно, вы не можете этого добиться. Вам необходимо настроить RewriteBase. Один из способов - автоматизировать настройку RewriteBase с помощью скрипта PHP? Но для этого потребуется разрешение на запись (как минимум) в .htaccess. Но вам нужно будет настроить RewriteBase в .htaccess.
я нахожу Документация Apache вводить в заблуждение:
При использовании механизма перезаписи в файлах .htaccess префикс для каталога (что всегда одинаково для определенного каталога) автоматически удаляется для сопоставления с образцом RewriteRule и автоматически добавлен после любой относительной (не начинающейся с косой черты или имени протокола) подстановки встречает конец набора правил. См. Директиву RewriteBase для получения дополнительной информации о том, какой префикс будет добавлен обратно к относительным заменам.
Но префикс, который он добавляет обратно, совершенно другой (путь на диске вместо исходного URL). Я не могу представить себе ситуацию, когда это было бы правильным поведением.
Как насчет чего-то вроде
RewriteEngine on
RewriteRule ^(.*)\.html $1/html.php
В моем примере сохраняется часть имени файла html файла - например, page1.html будет перенаправлен на page1 / html.php. (Примечание: я это вообще не тестировал, попробуйте на свой страх и риск :))
Также, руководство по mod_rewrite есть масса примеров, похожих на вашу проблему. Вы это уже видели?
В вопросе непонятно, что на самом деле определяет расположение «веб-корня» в этом контексте? (Поскольку он явно отличается от корень документа.)
Ради ответа я предполагаю, что «корень сети» - это каталог, в котором установлено веб-приложение. Это также должно быть расположение .htaccess
файл, управляющий этим "веб-приложением" (не в корне документа).
В этом случае вы жестяная банка просто используйте замену относительного пути. Вы не должен использовать RewriteBase
директива (которая отменяет префикс каталога, который добавляется позже и не может быть установлен «динамически»).
Итак, если "веб-корень" /foo/bar
затем .htaccess
в /foo/bar/.htaccess
должно читаться примерно так:
RewriteEngine On
RewriteRule \.html$ html.php [L]
(The RewriteRule
шаблон суффикс ^(.*)
здесь лишнее.)
Итак, учитывая запрос на /foo/bar/baz/something.html
тогда запрос будет внутренне переписан на <document-root>/foo/bar/html.php
(путь к файловой системе). <document-root>/foo/bar/
"префикс каталога" (путь в файловой системе, где находится .htaccess
file), который добавляется обратно ко всем заменам относительного пути.
Стандартный шаблон переднего контроллера (.htaccess
файл, расположенный в <web-application-root>/.htaccess
):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
Не устанавливайте RewriteBase
директива.
Обратите внимание, что вопрос и все примеры на этой странице относятся к внутренние перезаписине внешние перенаправления. Только если мы имеем дело с внешние перенаправления нужно ли нам (динамически) установить / вычислить эффективный базовый URL (или RewriteBase
). Потому что, если вы разрешите добавление префикса каталога обратно к относительному замена в случае внешнего перенаправления вы, скорее всего, столкнетесь с недействительным перенаправлением.