Полное руководство по mod_rewrite (часть 4): Директива RewriteCond
Оглавление. Полное руководство по mod_rewrite
1. Как включить и как работает mod_rewrite
2. Регулярные выражения mod_rewrite
4.1 Функции и синтаксис RewriteCond
4.2 Строка тестирования RewriteCond
4.3 Шаблон условия RewriteCond
5. Частые случаи и примеры использования mod_rewrite
8. Директива RewriteOptions, технические подробности, когда НЕ использовать mod_rewrite
Функции и синтаксис RewriteCond
Директива RewriteCond определяет условие, при котором будет иметь место перезапись. То есть мы ставим в зависимость выполнения правила не только от условия совпадения с Шаблоном, но и от других условий, которые могут не относиться к содержимому строки запроса. Например, правило может срабатывать (или наоборот, не срабатывать) если запрашиваемый адрес указывает на реально существующий в файловой системе файл, правило может быть отключено для определённых клиентских браузеров, либо в определённое время суток. Всё это можно сделать с помощью RewriteCond.
Синтаксис использования:
RewriteCond СтрокаТестирования ШаблонУсловия [флаги]
RewriteCond определяет условие применения правила. Одна или более директив RewriteCond могут предшествовать директиве RewriteRule. Последующее правило будет использоваться только в том случае, если текущее состояние URI соответствует его Шаблону, И если выполняются условия RewriteCond.
Строка тестирования RewriteCond
СтрокаТестирования – это строка, которая может содержать следующие расширенные конструкции в дополнение к простому тексту:
- Обратные ссылки RewriteRule: это обратные ссылки вида $N (0 <= N <= 9). С $1 по $9 обеспечивают доступ к сгруппированным частям (помещённым в скобки) Шаблона из RewriteRule, который является субъектом текущего набора условий RewriteCond. $0 предоставляет доступ к целой строке, совпавшей с этим Шаблоном.
- Обратные ссылки RewriteCond: это обратные ссылки вида %N (0 <= N <= 9). С %1 по %9 предоставляют доступ к сгруппированным частям (снова в кавычках) Шаблона из последнего совпавшего RewriteCond в текущем наборе условий. %0 предоставляет доступ к целой строке, совпавшей с этим Шаблоном.
- Расширения RewriteMap: это расширения в форме ${mapname:key|default}. Смотрите документацию по RewriteMap для дополнительной информации.
- Серверные переменные: это переменные вида %{ NAME_OF_VARIABLE } где NAME_OF_VARIABLE может быть строкой, взятой из следующего списка:
Переменные | Описание |
---|---|
HTTP заголовки | |
HTTP_ACCEPT | Запрашивает типы контента, выраженные в виде типов MIME, которые клиент может понять. Используя согласование контента, сервер затем выбирает одно из предложений, использует его и информирует клиента о своём выборе заголовком ответа Content-Type. Браузеры устанавливают соответствующие значения для этого заголовка в зависимости от контекста, в котором выполняется запрос: при обработке таблицы стилей CSS для запроса задается другое значение, чем при выборе изображения, видео или сценария. |
HTTP_COOKIE | Содержит сохраненные HTTP-файлы cookie, ранее отправленные сервером с заголовком Set-Cookie. |
HTTP_FORWARDED | Содержит информацию с клиентской стороны, которая изменена или потеряна когда в путь запроса вовлечён прокси. |
HTTP_HOST | Указывает доменное имя сервера (для виртуального хостинга) и (необязательно) номер порта TCP, который прослушивает сервер. |
HTTP_PROXY_CONNECTION | Определяет, остается ли сетевое соединение открытым после завершения текущей транзакции. Если отправляется keep-alive, соединение является постоянным и не закрытым, что позволяет выполнять последующие запросы на один и тот же сервер. |
HTTP_REFERER | Содержит адрес предыдущей веб-страницы, с которой была сделана ссылка на запрашиваемую страницу. |
HTTP_USER_AGENT | Содержит строку-характеристику, которая позволяет сетевым протоколам идентифицировать тип приложения, операционную систему, поставщика программного обеспечения или версию программного обеспечения запрашивающего программного агента. |
Внутренние сервера | |
DOCUMENT_ROOT | DocumentRoot текущего vhost. |
SCRIPT_GROUP | Имя группы скрипта. |
SCRIPT_USER | Имя пользователя владельца скрипта. |
SERVER_ADDR | IP-адрес виртуального хоста, обслуживающего запрос. |
SERVER_ADMIN | ServerAdmin текущего vhost |
SERVER_NAME | ServerName (включает схему, доменное имя или IP адрес и порт) текущего vhost. |
SERVER_PORT | Порт сервера текущего vhost, также смотрите ServerName. |
SERVER_PROTOCOL | Протокол, используемый запросом. |
SERVER_SOFTWARE | Строка с версией сервера. |
Подключение и запросы | |
AUTH_TYPE | Настроенный AuthType (варианты: None|Basic|Digest|Form) |
CONN_REMOTE_ADDR | С 2.4.8: IP адрес пира соединения (смотрите модуль mod_remoteip). |
CONTEXT_PREFIX | Префикс URI, который соответствует каталогу CONTEXT_DOCUMENT_ROOT, без конечной косой черты |
CONTEXT_DOCUMENT_ROOT | Корневой каталог контекста на диске для текущего ресурса, без конечного слэша |
IPV6 | "on" если подключение использует IPv6, в противном случае "off" |
PATH_INFO | Завершающая информация имени пути, которая следует после реального расположения файла или несуществующий файл в существующем каталоге независимо от того, является ли запрос принятым или отклонённым, смотрите AcceptPathInfo. Например, допустим расположение /test/ указывает на директорию, которая содержит только один файл here.html. Тогда запрос /test/here.html/more и /test/nothere.html/more оба соберут /more в качестве значения PATH_INFO. |
QUERY_STRING | Строка запроса (следует после символа ? (знак вопроса)) текущего запроса к серверу. |
REMOTE_ADDR | IP адрес удалённого хоста. |
REMOTE_HOST | Имя хоста удалённого хоста. |
REMOTE_IDENT | Имя пользователя, утсановленное mod_ident. |
REMOTE_PORT | Порт удалённого хоста (2.4.26 и более поздние) |
REMOTE_USER | Имя аутентифицированного пользователя, если есть. |
REQUEST_METHOD | HTTP метод входящего запроса (например, GET, POST, HEAD). |
SCRIPT_FILENAME | То же самое, что и REQUEST_FILENAME. |
Дата и время | |
TIME_YEAR | Текущий год (например, (2018) |
TIME_MON | Текущий месяц (01, …, 12) |
TIME_DAY | Текущий день месяца (01, …) |
TIME_HOUR | Часы текущего времени (00, …, 23) |
TIME_MIN | Минуты текущего времени |
TIME_SEC | Секунды текущего времени |
TIME_WDAY | День недели (начинается с 0 для Воскресенья) |
TIME | Дата и время в формате 20180924214559 |
Специальные | |
API_VERSION | Версия Apache httpd module API (внутреннего интерфейса между сервером и модулем) в текущей сборке httpd, как определена в include/ap_mmn.h. Версия модуля API соответствует версии используемого Apache httpd. Обычно это интересно только для авторов модулей. |
CONN_REMOTE_ADDR | С 2.4.8: IP адрес пира соединения (смотрите модуль mod_remoteip). |
HTTPS | Будет содержать текст "on" если соединение использует SSL/TLS, в противном случае - "off". (Эта переменная может безопасно использоваться независимо от того, загружен модуль mod_ssl или нет). |
IS_SUBREQ | Будет содержать текст "true" если обрабатываемый в данный момент запрос является подзапросом, в противном случае "false". Подзапросы могут генерироваться модулями, которым нужно преобразовать дополнительные файлы или URI чтобы завершить их задачи. |
REMOTE_ADDR | IP удалённого хоста (смотрите модуль mod_remoteip). |
REQUEST_FILENAME | Полный путь в локальной файловой системе до файла или скрипта, совпадающего с запросом, если он уже был определён сервером во время упоминания REQUEST_FILENAME. В зависимости от значения AcceptPathInfo, сервер может использовать только некоторые предшествующие компоненты REQUEST_URI для сопоставления запроса с файлом. |
REQUEST_SCHEME | Будет содержать схему запроса (обычно "http" или "https"). На это значение может влиять ServerName. |
REQUEST_URI | Компонент пути запрошенного URI, такой как "/index.html". Здесь исключена строка запроса, которая доступна в своей собственной переменной под именем QUERY_STRING. |
THE_REQUEST | Полная строка запроса HTTP отправленная браузером к серверу (например, "GET /index.html HTTP/1.1"). Она не включает любые дополнительные заголовки, отправленные браузером. Это значение не экранировано (кодировано), в отличии от большинства других переменных. |
Эти переменные все соответствуют названным подобным образом HTTP MIME-заголовкам, переменным C для Apache HTTP сервера или полям struct tm системы Unix.
SERVER_NAME и SERVER_PORT зависят от значений UseCanonicalName и UseCanonicalPhysicalPort соответственно.
Если СтрокаТестирования имеет специальное значение expr, ШаблонУсловия будет обрабатываться как ap_expr. HTTP заголовки, на которые указано в выражении, будут добавлены к заголовку Vary, если не дан флаг novary.
Другие вещи, о которых вы должны знать:
- Переменные SCRIPT_FILENAME и REQUEST_FILENAME содержат одинаковое значение – значение поля filename внутренней структуры request_rec сервера Apache HTTP. Первое имя – это имя хорошо известной CGI переменной, а второе – соответствующий двойник REQUEST_URI (которые содержит значение поля uri из of request_rec).
Если случилась подстановка и перезапись продолжается, значение обеих переменных соответственно будет обновлено.
Если используется контекст сервера (то есть до того, как запрос сопоставляется с файловой системой), SCRIPT_FILENAME и REQUEST_FILENAME не могут содержать полный путь к локальной файловой системе, поскольку на этом этапе обработки путь неизвестен. В этом случае изначально обе переменные будут содержать значение REQUEST_URI. Чтобы получить полный путь в локальной файловой системе запроса в контексте сервера, используйте основанный на URL look-ahead %{LA-U:REQUEST_FILENAME}, для определения конечного значение REQUEST_FILENAME.
- %{ENV:переменная}, где переменная может быть переменной окружения, также доступно. Она ищется через внутреннюю структуру Apache httpd и (если там не найдена) через getenv() из процесса Apache httpd.
- %{SSL:переменная}, где переменная – это имя переменной окружения SSL, может использоваться в независимости от того, загружен ли mod_ssl, но всегда будет раскрываться в пустую строку, если не загружен. Пример: %{SSL:SSL_CIPHER_USEKEYSIZE} может раскрыться в 128. Эти переменные доступны даже без настройки опции StdEnvVars директивы SSLOptions.
- %{HTTP:заголовок}, где заголовок может быть именем HTTP MIME-заголовка, может всегда использоваться для получения значения заголовка, отправленного в HTTP запросе. Пример: %{HTTP:Proxy-Connection} – это значение HTTP заголовка «Proxy-Connection:».
Если HTTP заголовок используется в условии, этот заголовок добавляется к заголовку Vary ответа в случае, если для данного запроса условие вычисляется как истина. Он не добавляется если условие вычисляется для заголовка как лож. Добавление HTTP заголовка к заголовку Vary ответа необходимо для правильного кэширования.
Следует иметь в виду, что условия соответствуют логике короткого контура в случае флага 'ornext|OR', так что некоторые условия могут вообще не оцениваться.
- %{LA-U:переменная}может использоваться для look-aheads, которые выполняют внутренний запрос (основанный на URL) для определения конечного значения переменной. Это можно использовать для доступа к переменной для перезаписи, которая недоступна на текущем этапе, но будет установлена на более поздней стадии.
Например, чтобы переписать в соответствии с переменной REMOTE_USER из контекста сервера (файл httpd.conf), вы должны использовать %{LA-U:REMOTE_USER} - эта переменная задается фазами авторизации, которые появляются после преобразования URL (во время которой работает mod_rewrite).
С другой стороны, поскольку mod_rewrite реализует контекст для каталога (файл .htaccess) через фазу Fixup API и, поскольку фазы авторизации приходят до этого этапа, вы можете использовать %{REMOTE_USER} в этом контексте.
- %{LA-F:переменная} может использоваться для выполнения внутреннего подзапроса (на основе имени файла) для определения конечного значения переменной. В большинстве случаев это то же самое, что и LA-U выше.
Шаблон условия RewriteCond
ШаблонУсловия – это шаблон условия, регулярное выражение, которое применяется к текущему экземпляру СтрокаТестирования. СтрокаТестирования сначала оценивается перед сопоставлением с ШаблономУсловия.
ШаблонУсловия обычно является регулярным выражением, совместимым с perl, но имеется дополнительный синтаксис для выполнения других полезных тестов в отношении СтрокиТестирования:
- Вы можете добавить перед строкой шаблона символ '!' (восклицательный знак) для отрицания результата условия, независимо от того, какой тип ШаблонаУсловия используется.
Пример правила блокировки всех пользователей с пустым Referer, кроме одного IP адреса (127.0.0.1):
RewriteEngine on RewriteCond "%{REMOTE_ADDR}" "!127.0.0.1" RewriteCond %{HTTP_REFERER} ^$ RewriteRule ^.* - [F,L]
- Вы можете выполнять лексикографическое сравнение строк (сводится к тому, какая бы строка шла первой в случае их расстановки в алфавитном порядке):
<CondPattern
Лексикографически предшествует
Обрабатывает ШаблонУсловия как обычную строку и сравнивает ее лексикографически со СтрокойТестирования. Истина, если СтрокаТестирования лексикографически предшествует ШаблонуУсловия.
>CondPattern
Лексикографически следует
Обрабатывает ШаблонУсловия как обычную строку и сравнивает ее лексикографически со СтрокойТестирования. Истинно, если СтрокаТестирования лексикографически следует ШаблонуУсловия.
=CondPattern
Лексикографически равный
Обрабатывает ШаблонУсловия как обычную строку и сравнивает ее лексикографически со СтрокойТестирования. Истина, если СтрокаТестирования лексикографически равна ШаблонуУсловия (две строки в точности равны, символ в символ). Если ШаблонУсловия является "" (двумя кавычками), это сравнивает СтрокуТестирования с пустой строкой.
<=CondPattern
Лексикографически меньше или равно
Обрабатывает ШаблонУсловия как обычную строку и сравнивает ее лексикографически со СтрокойТестирования. Истина, если СтрокаТестирования лексикографически предшествует ШаблонуУсловия или равна ШаблонуУсловия (две строки равны, символ в символ).
>=CondPattern
Лексикографически больше или равно
Обрабатывает ШаблонУсловия как обычную строку и сравнивает ее лексикографически со СтрокойТестирования. Истина, если со СтрокаТестирования лексикографически следует за ШаблономУсловия или равна ШаблонуУсловия (две строки равны, символ в символ).
- Вы можете выполнять целочисленные сравнения:
-eq
Численно равна
СтрокаТестирования обрабатывается как целое число и численно сравнивается со СтрокойТестирования. Истина, если они численно равны.
-ge
Численно больше или равно
СтрокаТестирования обрабатывается как целое число и численно сравнивается с ШаблономУсловия. Истинно, если СтрокаТестирования численно больше или равно ШаблонаУсловия.
-gt
Численно больше, чем
СтрокаТестирования обрабатывается как целое число и численно сравнивается с ШаблономУсловия. Истинно, если СтрокаТестирования численно больше, чем ШаблонУсловия.
-le
Численно меньше или равно
СтрокаТестирования обрабатывается как целое число и численно сравнивается с ШаблономУсловия. Истинно, если СтрокаТестирования численно меньше или равно ШаблонуУсловия. Избегайте путаницы с -l, при использовании вариант -L или -h.
-lt
Численно меньше
СтрокаТестирования обрабатывается как целое число и численно сравнивается с ШаблономУсловия. Истинно, если СтрокаТестирования численно меньше ШаблонаУсловия. Избегайте путаницы с -l, используя вариант -L или -h.
-ne
Численно не равна
СтрокаТестирования обрабатывается как целое число и численно сравнивается с ШаблономУсловия. Истинно, если они отличаются друг от друга. Это эквивалентно !-eq.
- Вы можете выполнять различные тесты атрибутов файлов:
-d
Является ли это каталогом
Обрабатывает СтрокуТестирования как путь и проверяет, существует ли она или нет, и является ли каталогом.
-f
Является ли это обычным файлом
Обрабатывает СтрокуТестирования как путь и проверяет, существует ли она или нет, и является ли обычным файлом.
-F
Существующий файл, через подзапрос.
Проверяет, является ли СтрокаТестирования допустимым файлом, доступным через все настроенные в данный момент элементы управления доступом для этого пути. Для выполнения проверки используется внутренний подзапрос, поэтому используйте его с осторожностью – это может повлиять на производительность вашего сервера!
-h
Является ли это символической ссылкой, псевдоним для -l.
См. -l.
-l
Является ли это символической ссылкой.
Обрабатывает СтрокуТестирования как путь и проверяет, существует ли она или нет, и является ли символической ссылкой. Можно также использовать -L или -h, если есть вероятность путаницы, например, при использовании тестов -lt или -le.
-L
Является ли символической ссылкой, псевдоним для -l.
См. -l.
-s
Является ли обычным файлом с размером.
Обрабатывает СтрокуТестирования как путь и проверяет, существует ли она или нет, и является ли обычным файлом с размером больше нуля.
-U
Является ли существующим URL-адресом через подзапрос.
Проверяет, является ли СтрокаТестирования допустимым URL-адресом, доступным через все настроенные в данный момент элементы управления доступом для этого пути. Для выполнения проверки используется внутренний подзапрос, поэтому используйте это с осторожностью – это может повлиять на производительность вашего сервера!
Этот флаг возвращает только информацию о таких вещах, как управление доступом, аутентификация и авторизация. Этот флаг не возвращает информацию о коде состояния, который должен был бы вернуть сконфигурированный обработчик (статический файл, CGI, прокси и т. д.).
-x
Имеет ли разрешения на выполнение.
Обрабатывает СтрокуТестирования как путь и проверяет, существует ли она или нет, и имеет ли разрешения на выполнение. Эти разрешения определяются в соответствии с ОС на которой работает сервер.
Например:
RewriteCond /var/www/%{REQUEST_URI} !-f RewriteRule ^(.+) /other/archive/$1 [R]
- Если СтрокаТестирования имеет специальное значение expr, ШаблонУсловия будет рассматриваться как ap_expr.
В приведенном ниже примере -strmatch используется для сравнения REFERER с именем хоста сайта для блокирования нежелательноого хотлинкинга.
RewriteCond expr "! %{HTTP_REFERER} -strmatch '*://%{HTTP_HOST}/*'" RewriteRule "^/images" "-" [F]
Флаги RewriteCond
Вы также можете установить специальные флаги для CondPattern, добавив [флаги] в качестве третьего аргумента в директиву RewriteCond, где flags – список, разделенный запятыми, из любого из следующих флагов:
- 'nocase|NC' (без учёта регистра)
Это делает тест нечувствительным к регистру – различия между «A-Z» и «a-z» игнорируются как в расширенной СтрокеТестирования , так и в ШаблонеУсловия. Этот флаг эффективен только для сравнения между СтрокойТестирования и ШаблономУсловия. Он не влияет на проверки файловой системы и подзапросов.
- 'ornext|OR' (или следующее условие)
Используйте это, чтобы комбинировать условия правила связкой ИЛИ вместо И, которая подразумевается по умолчанию. Типичный пример:
RewriteCond "%{REMOTE_HOST}" "^host1" [OR] RewriteCond "%{REMOTE_HOST}" "^host2" [OR] RewriteCond "%{REMOTE_HOST}" "^host3" RewriteRule ...какие-то специальные правила для любого из этих хостов... Без этого флага, вам бы пришлось писать три раза пару условие/правило.
- 'novary|NV' (без vary)
Если в условии используется HTTP-заголовок, этот флаг предотвращает добавление этого заголовка в заголовок ответа Vary.
Использование этого флага может нарушить правильное кэширование ответа, если представление этого ответа зависит от значения этого заголовка. Поэтому этот флаг должен использоваться только в том случае, если смысл заголовка Vary хорошо понят.
Пример:
Чтобы показать главную страницу сайта в соответствии с заголовком запроса «User-Agent:», вы можете использовать следующее:
RewriteCond "%{HTTP_USER_AGENT}" "(iPhone|Blackberry|Android)" RewriteRule "^/$" "/homepage.mobile.html" [L] RewriteRule "^/$" "/homepage.std.html" [L]
Объяснение: Если вы используете браузер, который идентифицирует себя как мобильный браузер (обратите внимание, что пример неполный, так как есть много других мобильных платформ), показывается мобильная версия домашней страницы. В противном случае будет использоваться стандартная страница.
Продолжение: «Полное руководство по mod_rewrite (часть 5): Частые случаи и примеры использования mod_rewrite».
Связанные статьи:
- Полное руководство по mod_rewrite (часть 1): Как включить и как работает mod_rewrite (100%)
- Полное руководство по mod_rewrite (часть 2): Регулярные выражения (100%)
- Полное руководство по mod_rewrite (часть 3): Флаги RewriteRule (100%)
- Полное руководство по mod_rewrite (часть 5): Частые случаи и примеры использования mod_rewrite (100%)
- Полное руководство по mod_rewrite (часть 6): Продвинутые техники применения mod_rewrite (100%)
- NetBIOS: что это, как работает и как проверить (RANDOM - 50%)
может не срабатывать (или наоборот, не срабатывать)
Опечатка. Поправил - спасибо, что обратили внимание.