Назад | Перейти на главную страницу

Относительная подстановка в mod_rewrite RewriteRule

Я хочу создать 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). Потому что, если вы разрешите добавление префикса каталога обратно к относительному замена в случае внешнего перенаправления вы, скорее всего, столкнетесь с недействительным перенаправлением.