Условия перенаправления запросов на index.php через RewriteCond

Раздел: Администрирование веб-сервера -> Настройка веб-сервера Apache

Настройка условий RewriteCond для перенаправления на index.php

Как настроить базовое перенаправление всех запросов, не соответствующих существующим файлам и директориям, на index.php?

Основной подход заключается в использовании директив RewriteCond с проверками !-f (не файл) и !-d (не директория). Если запрошенный ресурс не является реальным файлом или папкой, правило RewriteRule перенаправляет его на index.php.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

Allow index php (директива allow для index.php в apache)

Пояснения:
RewriteEngine On активирует модуль mod_rewrite.
%{REQUEST_FILENAME} содержит полный путь к запрошенному файлу на сервере. Проверка !-f истина, если такого файла нет. !-d истина, если такой директории нет.
^(.+)$ захватывает весь URI (кроме ведущего слэша).
index.php/$1 подставляет захваченную часть после index.php (например, /news/article превратится в index.php/news/article).
[QSA,L] флаги: QSA (Query String Append) добавляет исходную строку запроса к новому URL, L (Last) останавливает обработку правил.

Типичные проблемы и их решения:

  • Потеря GET-параметров: без флага QSA параметры будут отброшены. Решение: добавить QSA.
  • Бесконечный цикл: если index.php сам попадает под правило. Обычно index.php существует, поэтому проверка !-f его исключает, но при внутреннем перенаправлении может возникнуть повторный проход. Решение: добавить дополнительное условие, исключающее сам index.php (см. вариант ниже).
  • Неправильный путь: если index.php находится в поддиректории, правило может создавать неверные пути. Решение: использовать RewriteBase.

Как исключить из перенаправления определенные URL, например, папки /api или /static?

Добавляются дополнительные RewriteCond, которые проверяют, что URI не начинается с заданного префикса. Условия объединяются по логике И (все должны быть истинны).

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/api/
RewriteCond %{REQUEST_URI} !^/static/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

редирект index php (редирект через index.php)

Такая конфигурация оставит запросы к /api/ и /static/ нетронутыми (они будут обрабатываться напрямую сервером).

Частая ошибка: использование [OR] вместо раздельных условий.

Например, RewriteCond %{REQUEST_URI} !^/api [OR] будет истинным почти всегда (так как если URI не /api, то условие выполнено, и OR даст true). Правильно перечислять условия по одному без OR.

Как предотвратить циклическое перенаправление при запросе к самому index.php?

Хотя проверка !-f обычно защищает, при использовании правил с подстановкой пути (index.php/$1) может возникнуть ситуация, когда запрос к /index.php/some проходит проверку как несуществующий файл (так как файл index.php/some не существует), что приводит к повторному перенаправлению. Для безопасного исключения добавляется проверка URI.

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/index[.]php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

Htaccess index php (настройка .htaccess для index.php)

Здесь !^/index[.]php отвергает любой запрос, начинающийся с /index.php (точка в квадратных скобках не требует экранирования).

Проблема: если index.php находится в поддиректории, префикс будет иным. Адаптируйте путь.

Как настроить перенаправление, если index.php расположен не в корневой директории веб-сервера, а в подпапке?

Используется директива RewriteBase для указания базового пути. Например, приложение установлено в папку /myapp/.

RewriteEngine On
RewriteBase /myapp/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

Rewritecond index php (настройка rewritecond для index.php)

RewriteBase задаёт префикс, который будет добавлен к подстановке. Без неё правило могло бы сгенерировать путь /var/www/html/index.php/news вместо /myapp/index.php/news.

Ошибка: если RewriteBase указан неверно, ссылки могут вести в неверное место.

Как ограничить перенаправление только определенными HTTP методами, например, GET и POST?

Можно проверить метод через %{REQUEST_METHOD}. Это полезно для REST API, где другие методы (PUT, DELETE) могут обрабатываться напрямую.

RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^(GET|POST)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

Первое условие разрешает перенаправление только для GET и POST.

Проблема: если ожидаются HEAD или OPTIONS, они будут проигнорированы. При необходимости следует включить их в список.

Как отлаживать правила RewriteCond, чтобы понять, какие условия срабатывают?

Можно установить переменную окружения с помощью флага [E=...] и затем проверять её в PHP. Также рекомендуется включать логи перезаписи.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [E=rewritten:1,QSA,L]

В коде index.php можно проверить: $rewritten = getenv('rewritten'); если true, то запрос был перенаправлен. Для более детальной отладки на сервере разработки можно включить лог:

# В Apache 2.4
LogLevel alert rewrite:trace6

Лог покажет, какие условия сопоставлялись и какая замена выполнена.

Логирование на уровне trace может создавать большой объем данных; его следует выключать на продуктивных серверах.

Общие ошибки при настройке RewriteCond для index.php

  • Синтаксическая ошибка в регулярном выражении: например, не экранирована точка, неправильный квантификатор. Всегда проверяйте конфигурацию через apachectl configtest.
  • Забыт флаг [L]: без него обработка правил может продолжиться, и следующие правила могут переписать уже изменённый URL.
  • Конфликт с правилами, заданными в основном конфиге или .htaccess выше по каталогу. Проверьте порядок включения.
  • Модуль mod_rewrite не включен. Убедитесь, что он загружен (например, a2enmod rewrite на Debian/Ubuntu).
  • Некорректные права доступа к .htaccess: директива AllowOverride должна разрешать использование mod_rewrite (обычно All или FileInfo).

Пример с включенным логом перезаписи и демонстрация вывода

Конфигурация виртуального хоста с детальным логом:

Пример
<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/html
    <Directory /var/www/html>
        AllowOverride All
        RewriteEngine On
        LogLevel alert rewrite:trace6
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ index.php/$1 [QSA,L]
    </Directory>
</VirtualHost>

После применения этой конфигурации в логах (например, /var/log/apache2/error.log) можно увидеть строки вида:

[rewrite:trace3] [pid 12345] mod_rewrite.c(475): [client 192.168.1.1] RewriteCond: input='/var/www/html/css/style.css' pattern='!-f' => matched
[rewrite:trace3] [pid 12345] mod_rewrite.c(475): [client 192.168.1.1] RewriteCond: input='/var/www/html/css/style.css' pattern='!-d' => matched
[rewrite:trace2] [pid 12345] mod_rewrite.c(475): [client 192.168.1.1] RewriteRule: rewrite '/css/style.css' -> 'index.php/css/style.css'

Лог показывает, что для запроса несуществующего файла выполняются проверки и срабатывает правило.

Комбинация условий с оператором [OR] для выборочного перенаправления

Иногда требуется перенаправлять на index.php только некоторые наборы URL. Используем [OR] для объединения условий, при этом остальные проверки (на файл) остаются обязательными.

Пример
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/blog [OR]
RewriteCond %{REQUEST_URI} ^/news
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?route=$1 [QSA,L]

В этом примере перенаправление происходит, если URI начинается с /blog или /news, и при этом реального файла с таким именем нет. Другие запросы (например, /about) будут обрабатываться напрямую. Результат: запрос /blog/post-1 перенаправляется на index.php?route=/blog/post-1.

Условное перенаправление для отладочного IP

Можно использовать REMOTE_ADDR для того, чтобы только разработчик с определённого IP видел перенаправление на специальную страницу отладки.

Пример
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REMOTE_ADDR} ^192[.]168[.]1[.]100$
RewriteRule ^(.*)$ index.php/debug/$1 [QSA,L]
# Для остальных IP запросы проходят без перенаправления (или используется другое правило)

Если IP клиента равен 192.168.1.100, то запросы направляются в index.php/debug/, иначе перенаправление не применяется. Лог покажет, что условие по IP не сработало для других адресов.

Использование %{THE_REQUEST} для точного захвата пути

Переменная %{THE_REQUEST} содержит полную первую строку HTTP-запроса. Её можно использовать для извлечения пути без учёта строки запроса.

Пример
RewriteEngine On
RewriteCond %{THE_REQUEST} ^(GET|POST) /(.*) HTTP
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?path=%2 [QSA,L]

Здесь %2 ссылается на вторую группу захвата из условия (путь между / и HTTP). Например, запрос "GET /article/123?page=2 HTTP/1.1" даст path = article/123. Результат: перенаправление на index.php?path=article/123&page=2 (QSA добавляет page=2).

Обработка ошибок: если index.php не существует

Если сам index.php отсутствует в корне, правило может привести к ошибке 404. Можно добавить проверку существования index.php и выдать понятное сообщение.

Пример
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/index.php -f
RewriteRule ^(.*)$ index.php/$1 [QSA,L]
# Иначе перенаправляем на собственную страницу ошибки
RewriteRule ^(.*)$ /error.html [L]

Дополнительное условие проверяет, что файл index.php существует в корне документа. Если нет, срабатывает другое правило, отправляющее на error.html.

Настройка RewriteCond для index.php - comments

En
Rewritecond index php (php)