Такое поведение вызывает сожаление и даже не выглядит документированным.
.htaccess для каждого каталога dir
Вот что, похоже, происходит в .htaccess
для каждого каталога (для каждого каталога).dir) context:
Предположим, что Apache обрабатывает файл .htaccess
, содержащий директивы перезаписи.
-
Apache заполняет свою карту переменных среды всеми стандартными CGI / Apacheпеременные
Перезапись начинается
Переменные окружения устанавливаются в директивах RewriteRule
Когда Apacheпрекращает обработку директив RewriteRule
(из-за флага L
или конца набора правил), а URL-адрес был изменен с помощью RewriteRule
, Apache возобновляет обработку запроса.
Если вы не знакомы с этой частью, см. Документацию флага L
:
, поэтому набор правил может быть снова запущен с самого начала.Чаще всего это происходит, если одно из правил вызывает перенаправление - либо внутреннее, либо внешнее - и процесс запроса запускается заново.
Из того, что я могу наблюдать, я считаю, что когда происходит # 4, повторяется # 1, тогда переменные окружения, которые были установлены в директивах RewriteRule
, начинаются с REDIRECT_
идобавлена карта среды vars (не обязательно в этом порядке, но конечный результат состоит из этой комбинации).
На этом этапе имена выбранных переменных стираются, и через минуту я объясню, почему это так важно и неудобно.
Восстановление имен переменных
Когда я впервые столкнулся с этой проблемой, я делал что-то вроде следующего в .htaccess
(упрощенно):
RewriteCond %{HTTP_HOST} (.+)\.projects\.
RewriteRule (.*) subdomains/%1/docroot/$1
RewriteRule (.+/docroot)/ - [L,E=EFFECTIVE_DOCUMENT_ROOT:$1]
Если бы я установил переменную среды в первом RewriteRule
, Apache перезапустил бы процесс перезаписи и добавил бы переменную с REDIRECT_
(шаги 4 и 5 выше), таким образом, я бы потерял доступ к ней черезимя, которое я присвоил.
В этом случае первый RewriteRule
изменяет URL-адрес, поэтому после обработки обоих RewriteRule
Apache перезапускает процедуру и снова обрабатывает .htaccess
.Во второй раз первый RewriteRule
пропускается из-за директивы RewriteCond
, но второй RewriteRule
совпадает, устанавливает переменную среды (снова), и, что важно, не меняет URL .Таким образом, процесс запроса / перезаписи не начинается заново, и выбранное мной имя переменной остается неизменным.В этом случае у меня фактически есть и REDIRECT_EFFECTIVE_DOCUMENT_ROOT
, и EFFECTIVE_DOCUMENT_ROOT
.Если бы я использовал флаг L
на первом RewriteRule
, у меня было бы только частичное решение EFFECTIVE_DOCUMENT_ROOT
.
@ trowel работает аналогично: директивы перезаписи обрабатываются снова, переименованная переменнаяснова назначается исходное имя, и если URL-адрес не изменяется, процесс завершается, и назначенное имя переменной остается неизменным.
Почему эти методы неадекватны
Оба эти метода страдают отглавный недостаток: когда правила перезаписи в файле .htaccess
, в котором вы устанавливаете переменные среды, переписывают URL-адрес в более глубоко вложенный каталог с файлом .htaccess
, который выполняет любое переписывание, назначенное имя переменной снова стирается.
Скажем, у вас есть макет каталога, подобный следующему:
docroot/
.htaccess
A.php
B.php
sub/
.htaccess
A.php
B.php
И docroot/.htaccess
вот так:
RewriteRule ^A\.php sub/B.php [L]
RewriteRule .* - [E=MAJOR:flaw]
Итак, вы запрашиваете /A.php
, и он переписывается вsub/B.php
.У вас все еще есть переменная MAJOR
.
Однако, если у вас есть какие-либо директивы перезаписи в docroot/sub/.htaccess
(даже просто RewriteEngine Off
или RewriteEngine On
), ваша переменная MAJOR
исчезнет.Это связано с тем, что после перезаписи URL на sub/B.php
обрабатывается docroot/sub/.htaccess
, и если он содержит какие-либо директивы перезаписи, директивы перезаписи в docroot/.htaccess
не обрабатываются снова.Если у вас был REDIRECT_MAJOR
после обработки docroot/.htaccess
(например, если вы опускаете флаг L
в первом RewriteRule
), он все равно будет у вас, но эти директивы больше не будут запускаться для установки выбранного вами.имя переменной.
Наследование
Итак, скажем, вы хотите:
-
установить переменные окружения в директивах RewriteRule
на определенном уровне дерева каталогов (например, docroot/.htaccess
)
сделать их доступными в скриптах на более глубоких уровнях
иметь их в наличии с назначенными именами
иметь возможность перезаписывать директивы в более глубоко вложенных .htaccess
файлах
AВозможное решение - использовать директивы RewriteOptions inherit
в более глубоко вложенных файлах .htaccess
.Это позволяет вам повторно запускать директивы перезаписи в файлах с меньшей глубиной вложенности и использовать методы, описанные выше, для установки переменных с выбранными именами.Тем не менее, обратите внимание, что это увеличивает сложность, потому что вы должны быть более осторожными при составлении директив перезаписи в менее глубоко вложенных файлах, чтобы они не вызывали проблем при повторном запуске из более глубоко вложенных каталогов.Я полагаю, что Apache удаляет префикс per-dir для более глубоко вложенного каталога и запускает директивы перезаписи в менее глубоко вложенных файлах с этим значением.
@ метод trowel
Насколько я могувидите, поддержка использования конструкции, подобной %{ENV:REDIRECT_VAR}
в компоненте значения флага RewriteRule
E
(например, [E=VAR:%{ENV:REDIRECT_VAR}]
), не представляется документированной :
VAL может содержать обратные ссылки ($ N или% N), которые будут расширены.
Кажется, это работает, но если вы хотите не полагаться на что-то недокументированное (пожалуйста, исправьте меня, если я 'я ошибаюсь), вместо этого это можно легко сделать следующим образом:
RewriteCond %{ENV:REDIRECT_VAR} (.+)
RewriteRule .* - [E=VAR:%1]
SetEnvIf
Я не рекомендую полагаться на это, потому что это не соответствует документированное поведение (см. ниже), но это (в docroot/.htaccess
, с Apache 2.2.20) работает для меня:
SetEnvIf REDIRECT_VAR (.+) VAR=$1
Только те переменные среды, которые определеныболее ранние директивы SetEnvIf [NoCase] доступны для тестированиятаким образом.
Почему?
Я не знаю, каково обоснование для префикса этих имен с REDIRECT_
- не удивительно, так как это, кажется, небыть упомянутым в разделах документации Apache для директив mod_rewrite , RewriteRule
flags или переменных среды .
На данный момент это выглядит такбольшая неприятность для меня, из-за отсутствия объяснения, почему это лучше, чем оставлять назначенные имена в покое.Отсутствие документации только способствует моему скептицизму по этому поводу.
Возможность присваивать переменные окружения в правилах перезаписи полезна, или, по крайней мере, так будет.Но полезность значительно снижается этим изменяющим имя поведением.Сложность этого поста иллюстрирует, насколько безумны это поведение и обручи, которые нужно преодолеть, чтобы попытаться его преодолеть.