Условия перенаправления запросов на index.php через RewriteCond
Настройка условий 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.