Эффективные методы RewriteRule для index.php

Раздел: Настройка Apache .htaccess -> Перенаправление с помощью mod_rewrite

Настройка RewriteRule для index.php

Основное правило фронт-контроллера

Наиболее эффективное решение для передачи всех запросов на index.php, если файл или каталог не существует физически. Правило избегает циклических перенаправлений и не затрагивает статические ресурсы.

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

Rewriterule index php (правило rewriterule для index.php)

Пояснение:

  • RewriteEngine On – включает модуль mod_rewrite.
  • RewriteCond с флагами !-f и !-d проверяет, что запрошенный путь не является существующим файлом или директорией.
  • RewriteRule захватывает весь путь (^(.*)$) и перенаправляет его на index.php.
  • Флаг QSA (Query String Append) добавляет существующие GET-параметры к новому запросу.
  • Флаг L (Last) останавливает обработку правил после этого совпадения.

Это правило подходит для большинства современных PHP-фреймворков, таких как Laravel, Symfony, CodeIgniter, а также для самописных MVC-приложений.

Типичная ошибка: правило не срабатывает, если модуль rewrite не включен. Проверка выполняется командой a2enmod rewrite (на Debian/Ubuntu) или перезагрузкой Apache. Другая проблема – неправильный путь к index.php, если .htaccess находится не в корневой директории. В таких случаях используется RewriteBase.

Вариант 1: Как заставить сервер обрабатывать все запросы через index.php, даже если файл существует?

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule ^(.*)$ index.php [QSA,L]

В этом варианте проверка на существование файла отсутствует, поэтому запросы к реальным .css, .js, .png файлам также будут переданы в index.php. Это может быть полезно, если нужно применить к ним какую-то логику, но чаще приводит к падению производительности и ошибкам в терминологии. Для исключения самого index.php добавлено условие: перенаправление не применяется, если запрос уже к index.php.

Проблема: при отсутствии условия может возникнуть бесконечный цикл – сервер будет постоянно перенаправлять на index.php, пока не будет достигнут лимит внутренних редиректов (обычно 10). Симптомы: ошибка 500 Internal Server Error. Решение – добавить условие %{REQUEST_URI} !^/index\.php$ или, лучше, использовать проверку на существование файла.

Вариант 2: Как настроить обработку только PHP-запросов, которых нет на сервере?

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

Этот вариант ограничивает перезапись только URI, заканчивающимися на .php. Все запросы к несуществующим PHP-файлам будут обработаны index.php. Статические файлы (html, css, jpg) останутся без изменений, даже если они отсутствуют.

Недостаток: запросы без расширения (например, /blog или /post/123) не будут перенаправлены. Если приложение использует ЧПУ без расширения, правило не подходит. Также возможна путаница, если существует файл .php, но он должен быть обработан по-другому.

Вариант 3: Как правильно задать базовый путь для относительных ссылок в RewriteRule?

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

Директива RewriteBase указывает корневой URI для относительных путей в подстановке. Без неё правило по умолчанию использует корень документа. Если .htaccess лежит в поддиректории /myapp/, то index.php в правиле будет интерпретирован как /myapp/index.php при наличии RewriteBase. В противном случае потребуется полный путь от корня.

Ошибка: неправильный RewriteBase может привести к тому, что редирект будет на неверный URI. Например, указан /sub/, а приложение находится в /root/sub/. Рекомендуется устанавливать RewriteBase в соответствии с расположением .htaccess относительно DocumentRoot.

Вариант 4: Как передать запрошенный URI в index.php как параметр?

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

В этом варианте весь оригинальный путь передаётся в переменную $_GET['url']. Это удобно для маршрутизации: PHP-код обрабатывает $_GET['url'] и определяет контроллер. Флаг QSA сохраняет остальные GET-параметры. Если флаг QSA не указан, все существующие параметры будут потеряны.

Проблема: если в запросе уже есть параметр url, он будет перезаписан. Решение – использовать другое имя параметра, например route, или обрабатывать в PHP через разбор $_SERVER['REQUEST_URI'].

Вариант 5: Как исключить статические ресурсы из перезаписи?

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

Добавлено третье условие, которое проверяет, что начало URI не совпадает с указанными папками. Статические файлы, лежащие в этих каталогах, будут отданы напрямую, даже если они не существуют (тогда возникнет 404, но не будет задействован PHP).

Ошибка: если в папке /assets/ есть подпапки, правило сработает, но для вложенных путей может потребоваться уточнение. Также не сработает, если статика расположена в корне. Лучше комбинировать с проверкой на существование файлов.

Вариант 6: Как с помощью RewriteRule перехватить ошибку 404 и передать её в index.php?

ErrorDocument 404 /index.php
# или с RewriteRule
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [R=404,L]

Первый способ: ErrorDocument указывает, что все ошибки 404 должны обрабатываться index.php. Второй способ: при несовпадении условий правило возвращает код 404, но при этом перенаправляет на index.php. Флаг R=404 вызывает полный редирект с HTTP-кодом 404. При этом браузер видит адрес без изменения, но получает статус 404.

Нюанс: при использовании R=404 вместе с L Apache может выполнить внешний редирект, что изменит URL в строке браузера (если не использовать PT или не указать неявно). Рекомендуется использовать ErrorDocument для простоты.

Расширенные примеры и нестандартные сценарии

Пример 1. Отладка правил RewriteRule с использованием RewriteLog

Для отладки можно включить лог реврайта в конфигурации виртуального хоста (не в .htaccess, так как директиву RewriteLog поддерживает только основная конфигурация):

Пример
RewriteEngine On
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 9

# Затем в .htaccess использовать стандартные правила
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Результат: в лог будет записываться каждый шаг обработки, что поможет понять, какое условие не сработало.

# Пример записи лога:
[rewrite] pass through /test?param=1
[rewrite] applying pattern '^(.*)$' to uri '/test'
[rewrite] rewrite '/test' -> 'index.php'
[rewrite] add query string '?param=1' -> 'index.php?param=1'

Пример 2. Перенаправление всех запросов на index.php с постоянным редиректом (HTTP 301)

Если старое приложение полностью заменено на новое, можно сделать 301 редирект на index.php. При этом посетители и поисковые системы увидят новый адрес.

Пример
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule ^(.*)$ /index.php?from=$1 [R=301,L,QSA]

Результат: запрос /old-page?lang=en приведёт к переходу на /index.php?from=old-page&lang=en со статусом 301.

Пример 3. Использование регулярных выражений для выборки определённых шаблонов URL

Допустим, нужно переписывать только числовые идентификаторы на index.php.

Пример
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^article/(\d+)$ index.php?id=$1 [L,QSA]

Результат: URL /article/42?ref=home преобразуется в /index.php?id=42&ref=home. Все остальные запросы (например, /contact) не будут обработаны этим правилом и могут уйти в 404.

Пример 4. Правило RewriteRule для index.php в поддиректории с использованием переменной окружения

Иногда требуется передать не только путь, но и информацию о протоколе или домене.

Пример
RewriteEngine On
RewriteBase /subdir/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1&protocol=%{REQUEST_SCHEME}&host=%{HTTP_HOST} [QSA,L]

Результат: запрос /subdir/photo?size=big приведёт к /subdir/index.php?url=photo&protocol=https&host=example.com&size=big. Это может быть полезно для проверки HTTPS или мультидоменной маршрутизации.

Пример 5. Условная перезапись в зависимости от IP-адреса клиента

Например, для административного доступа к системе через index.php, а для остальных – отдавать статический сайт.

Пример
RewriteEngine On
RewriteCond %{REMOTE_ADDR} ^192\.168\.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^admin/(.*)$ index.php?admin=$1 [L]

# Для всех остальных
RewriteCond %{REMOTE_ADDR} !^192\.168\.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]

Результат: пользователи из локальной сети (192.168.x.x) увидят обработанные через index.php админские URL, остальные – стандартную обработку всех запросов через index.php.

Пример 6. Комбинирование нескольких правил с приоритетами

Пример
RewriteEngine On

# 1. Исключить файлы с определёнными расширениями из перезаписи
RewriteRule \.(ico|pdf|flv|jpg|jpeg|png|gif|svg|css|js)$ - [NC,L]

# 2. Перенаправление на index.php для всех остальных
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Результат: запросы к файлам с указанными расширениями не будут обрабатываться вообще (правило с дефисом означает отсутствие перезаписи, только флаг L). Все остальные запросы пойдут в index.php.

Правило RewriteRule для index.php - comments

En
Rewriterule index php (php)