Академия mod_rewrite. Урок 3: RewriteCond и переменные %{...}

RewriteRule сам по себе смотрит только на путь запроса. Чтобы проверить протокол, хост, метод, заголовки, IP, наличие файла — нужен RewriteCond. Это условие, которое стоит перед правилом и управляет тем, сработает ли оно. В уроке разберём синтаксис, серверные переменные и практические примеры.

Урок 3 из 5 · ← предыдущий | следующий → · оглавление курса

Зачем нужен RewriteCond

RewriteRule матчит только путь запроса (например, blog/5). Но часто нужно проверить что-то ещё:

  • «Выполнить редирект, только если запрос по HTTP, а не HTTPS»
  • «Сработать, только если хост начинается с www.»
  • «Заблокировать, только если User-Agent содержит "bot"»
  • «Перезаписать в index.php, только если файл физически не существует»

Всё это — задача RewriteCond.

Синтаксис RewriteCond

Синтаксис: RewriteCond ТестоваяСтрока Паттерн [Флаги].

  • RewriteCond ставится перед RewriteRule и действует только на ближайший следующий RewriteRule.
  • Несколько RewriteCond подряд — все должны быть истинны (логическое И).
  • Флаг [OR] на условии объединяет его со следующим через «ИЛИ».
  • Флаг [NC] — сравнение без учёта регистра.
  • Ведущий ! перед паттерном — инверсия: «не совпадает».
.htaccessкопировать
RewriteEngine On

# Одно условие перед правилом:
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Два условия (оба должны быть истинны):
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]

Часто используемые переменные

Серверные переменные записываются в формате %{ИМЯ}:

  • %{HTTP_HOST} — хост из запроса: example.com или www.example.com.
  • %{HTTPS}on, если запрос по HTTPS, иначе off. За reverse-proxy или CDN может всегда быть off — тогда используйте %{HTTP:X-Forwarded-Proto}.
  • %{REQUEST_URI} — путь запроса (/blog/5), без строки запроса. Меняется при внутренней перезаписи.
  • %{QUERY_STRING} — строка запроса (то, что после ?). Важно: query string НЕ входит в паттерн RewriteRule — её можно проверить только через RewriteCond %{QUERY_STRING}.
  • %{REQUEST_METHOD}GET, POST, HEAD, …
  • %{REMOTE_ADDR} — IP-адрес клиента.
  • %{HTTP_USER_AGENT} — строка User-Agent браузера или бота.
  • %{HTTP_REFERER} — заголовок Referer.
  • %{HTTP:X-Forwarded-Proto} — любой произвольный заголовок (здесь: X-Forwarded-Proto).
  • %{REQUEST_FILENAME} — полный путь на диске, соответствующий запросу. Используется с проверками -f/-d.
  • %{THE_REQUEST} — полная первая строка HTTP-запроса (GET /blog/5 HTTP/1.1). Не меняется при внутренних перезаписях — полезно для защиты от петель редиректов.

Специальные проверки: -f, -d, -s, -l

Вместо паттерна-регулярки в RewriteCond можно использовать проверки файловой системы:

  • -f — запрошенный путь соответствует существующему обычному файлу.
  • -d — соответствует существующему каталогу.
  • -s — файл существует и непустой (size > 0).
  • -l — символическая ссылка.
  • Ведущий ! — инверсия: !-f = «файл НЕ существует».

Лексикографические сравнения (вместо regex): =строка (точное равенство), <строка, >строка. Числовые (Apache 2.4): -eq, -lt, -gt и др.

Бэкрефы %1 из условий

Группы захвата ( ) в паттерне RewriteCond доступны как %1, %2, … в подстановке следующего RewriteRule и в последующих RewriteCond.

Это позволяет извлечь часть значения переменной. Классический пример — www-канонизация: перенаправить www.example.com на example.com, захватив основной домен:

.htaccessкопировать
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

Здесь %1 — всё, что захватила группа (.+) из хоста, то есть домен без www.. %{REQUEST_URI} — исходный путь (добавляем в подстановку, чтобы не потерять).

Практические примеры

HTTPS-редирект:

.htaccessкопировать
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

За прокси/CDN используйте: RewriteCond %{HTTP:X-Forwarded-Proto} !https.

Режим обслуживания для всех, кроме своего IP:

.htaccessкопировать
RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^192\.168\.1\.100$
RewriteCond %{REQUEST_URI} !^/maintenance\.html$
RewriteRule ^ /maintenance.html [R=302,L]

Блокировка по User-Agent:

.htaccessкопировать
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (scrapy|wget|python-requests) [NC]
RewriteRule ^ - [F,L]

Попробуй сам

Тестер RewriteRule поддерживает RewriteCond — вставьте блок с условиями и заполните поля «переменные сервера» (хост, HTTPS, User-Agent). Посмотрите в трассировке, какие условия прошли и почему.

Упражнения

  1. Напишите правило, которое делает редирект http → https, и проверьте его в тестере RewriteRule.
    Подсказка: RewriteCond %{HTTPS} off перед правилом.
  2. Напишите правило, которое редиректит на без-www, но только если хост начинается на www..
    Подсказка: RewriteCond %{HTTP_HOST} ^www\.(.+)$ и %1 в подстановке.
    Проверьте в тестере RewriteRule.
  3. Напишите правило режима обслуживания: всем отдаётся /maintenance.html, кроме своего IP (например, 10.0.0.1).
    Подсказка: два RewriteCond — на IP и на URL самой страницы обслуживания (чтобы не зациклиться).
  4. Почему RewriteCond %{QUERY_STRING} иногда обязателен? Назовите ситуацию, когда без него не обойтись.
    Подсказка: паттерн RewriteRule не видит строку запроса.

Что дальше

В уроке 4 погрузимся в регулярные выражения: якоря, классы символов, кванторы, группы захвата и готовые паттерны для типовых задач. Всё это с практикой в тестере regex.