Я пытаюсь установить переменные среды Apache (для использования в PHP) с флагом [E=VAR:VAL]
в правилах RewriteRule в файле .htaccess.
Я уже обнаружил, что переменные доступны в PHP как серверные переменные $_SERVER
а не $_ENV
(что делает определенный смысл). Однако моя проблема заключается в некоторых правилах, флаг [E=VAR:VAL]
работает так, как ожидалось, и я получаю переменную $_SERVER['VAR']
но для других правил я заканчиваю переменной $_SERVER['REDIRECT_VAR']
или $_SERVER['REDIRECT_REDIRECT_VAR']
и т. д.
A. Что вызывает переменную окружения, установленную в Apache, используя флаг [E=VAR:VAL]
чтобы переименовать, добавив «REDIRECT_» к имени переменной?
B. Что я могу сделать, чтобы убедиться, что в конечном итоге вы измените переменную среды с неизменным именем, чтобы я мог получить доступ к ней в PHP как $_SERVER['VAR']
не прибегая к проверке вариантов имени переменной, имеющего один из добавлено больше экземпляров «REDIRECT_»?
Найдено частичное решение . Добавление следующего к началу правил перезаписи воссоздает исходный ENV: VAR при каждом перенаправлении (а также оставляя там версии REDIRECT_VAR), если они необходимы:
RewriteCond %{ENV:REDIRECT_VAR} !^$ RewriteRule .* - [E=VAR:%{ENV:REDIRECT_VAR}]
Такое поведение является неудачным и даже не документируется.
Вот что происходит в контексте .htaccess
каждого каталога (per-dir):
Предположим, что Apache обрабатывает файл .htaccess
содержащий директивы rewrite.
Apache заполняет карту переменных среды со всеми стандартными переменными CGI / Apache
Переписывание начинается
Переменные среды задаются в директивах RewriteRule
Когда Apache перестает обрабатывать директивы RewriteRule
(из-за L
флага или конца набора правил), а URL-адрес был изменен с помощью RewriteRule
, Apache перезапускает обработку запроса.
Если вы не знакомы с этой частью, см. Документацию по L
:
таким образом, набор правил может снова запускаться с самого начала. Чаще всего это произойдет, если одно из правил вызывает перенаправление – внутреннее или внешнее – заставляя процесс запроса начать работу.
Из того, что я могу наблюдать, я считаю, что при # 4, повторение # 1, переменные среды, которые были установлены в директивах RewriteRule
, добавляются с REDIRECT_
и добавляются в карту окружения окружающей среды (не обязательно в этом порядке, но конец результат состоит из этой комбинации).
Этот шаг – это то, где выбитые имена переменных уничтожаются, и через какое-то время я объясню, почему это так важно и неудобно.
Когда я впервые столкнулся с этой проблемой, я делал что-то вроде следующего в .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
s Apache перезапускает процедуру и снова обрабатывает .htaccess
. Во второй раз первый RewriteRule
пропускается из-за директивы RewriteCond
, но второй RewriteRule
соответствует, устанавливает переменную среды (снова) и, что важно, не изменяет URL . Таким образом, процесс запроса / перезаписи не начинается, а имя переменной я выбрал. В этом случае на самом деле у меня есть как REDIRECT_EFFECTIVE_DOCUMENT_ROOT
и EFFECTIVE_DOCUMENT_ROOT
. Если бы я использовал флаг L
в первом RewriteRule
, у меня был бы только EFFECTIVE_DOCUMENT_ROOT
.
Частичное решение trowel работает аналогично: директивы rewrite обрабатываются снова, переименованная переменная снова присваивается исходному имени, и если URL-адрес не изменяется, процесс завершается, и имя назначенной переменной сохраняется.
Обе эти технологии страдают от серьезного недостатка: когда правила перезаписи в файле .htaccess
где вы устанавливаете переменные среды, переписываете URL-адрес в более глубоко вложенный каталог с файлом .htaccess
который выполняет любую переписывание, имя вашей назначенной переменной вытирается снова.
Скажем, у вас есть макет каталога, как это:
docroot/ .htaccess A.php B.php sub/ .htaccess A.php B.php
к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
в docroot/sub/.htaccess
(даже просто RewriteEngine Off
или RewriteEngine On
), ваша MAJOR
переменная исчезает. Это связано с тем, что, как только URL-адрес переписан на sub/B.php
, docroot/sub/.htaccess
, и если он содержит какие-либо директивы rewrite, переписывать директивы в docroot/.htaccess
не обрабатываются снова. Если у вас был REDIRECT_MAJOR
после обработки docroot/.htaccess
(например, если вы опускаете флаг L
из первого RewriteRule
), вы все равно будете иметь его, но эти директивы не будут запускаться снова, чтобы установить ваше имя выбранной переменной.
Итак, скажите, что вы хотите:
задайте переменные окружения в директивах RewriteRule
на определенном уровне дерева каталогов (например, docroot/.htaccess
)
иметь их доступными в сценариях на более глубоких уровнях
иметь их доступными с назначенными именами
иметь возможность переписывать директивы в более глубоко вложенных файлах .htaccess
Возможным решением является использование директив RewriteOptions inherit
в более глубоко вложенных файлах .htaccess
. Это позволяет повторно запускать директивы rewrite в менее глубоко вложенных файлах и использовать описанные выше методы для установки переменных с выбранными именами. Однако обратите внимание, что это увеличивает сложность, потому что вам нужно быть более осторожным при разработке директив перезаписи в менее глубоко вложенных файлах, чтобы они не вызывали проблем при повторном запуске из более глубоко вложенных каталогов. Я считаю, что Apache использует префикс per-dir для более глубоко вложенного каталога и запускает директивы rewrite в менее глубоко вложенных файлах этого значения.
Насколько я вижу, поддержка использования такой конструкции, как %{ENV:REDIRECT_VAR}
в компоненте значения RewriteRule
E
(например, [E=VAR:%{ENV:REDIRECT_VAR}]
), как представляется, не документирована :
VAL может содержать обратные ссылки ($ N или% N), которые будут расширены.
Кажется, он работает, но если вы хотите не полагаться на что-то недокументированное (пожалуйста, поправьте меня, если я ошибаюсь в этом), это можно сделать следующим образом:
RewriteCond %{ENV:REDIRECT_VAR} (.+) RewriteRule .* - [E=VAR:%1]
Я не рекомендую полагаться на это, потому что он, похоже, не согласуется с документированным поведением (см. Ниже), но это (в docroot/.htaccess
, с Apache 2.2.20) работает для меня:
SetEnvIf REDIRECT_VAR (.+) VAR=$1
Только те переменные среды, которые определены ранее установленными директивами SetEnvIf [NoCase], доступны для тестирования таким образом.
Я не знаю, какое обоснование для префикса этих имен с помощью REDIRECT_
– неудивительно, поскольку он не упоминается в разделах документации Apache для директив mod_rewrite , флагов RewriteRule
или переменных среды .
На данный момент это кажется большой неприятностью для меня, в отсутствие объяснения, почему это лучше, чем оставить назначенные имена в одиночку. Отсутствие документации только способствует моему скептицизму.
Возможность присвоить переменные среды в правилах перезаписи является полезной или, по крайней мере, будет. Но полезность значительно уменьшена этим изменением названия. Сложность этого поста иллюстрирует, как орехи такого поведения и обручи, которые нужно перепрыгнуть, чтобы попытаться преодолеть это.
Я не тестировал это вообще, и я знаю, что он не касается точек A или B, но есть описание этой проблемы в комментариях в документации PHP и некоторые возможные решения для доступа к этим переменным с помощью $_SERVER['VAR']
:
http://www.php.net/manual/en/reserved.variables.php#79811
EDIT – еще несколько ответов на предложенный вопрос:
A: Переменные среды переименовываются Apache, если они участвуют в перенаправлении. Например, если у вас есть следующее правило:
RewriteRule ^index.php - [E=VAR1:'hello',E=VAR2:'world']
Затем вы можете получить доступ к VAR1 и VAR2 с помощью $_SERVER['VAR1']
и $_SERVER['VAR2']
. Однако, если вы перенаправляете страницу следующим образом:
RewriteRule ^index.php index2.php [E=VAR1:'hello',E=VAR2:'world']
Затем вы должны использовать $_SERVER['REDIRECT_VAR1']
и т. Д.
B: Лучший способ преодолеть эту проблему – обработать переменные, которые вам интересны при использовании PHP. Создайте функцию, которая проходит через массив $_SERVER
и найдет нужные вам элементы. Вы можете использовать такую функцию:
function myGetEnv($key) { $prefix = "REDIRECT_"; if(array_key_exists($key, $_SERVER)) return $_SERVER[$key]; foreach($_SERVER as $k=>$v) { if(substr($k, 0, strlen($prefix)) == $prefix) { if(substr($k, -(strlen($key))) == $key) return $v; } } return null; }