Настройка RewriteCond в .htaccess для PHP: проверка существования и перенаправление запросов
Правило RewriteCond для PHP в .htaccess
Основное решение: перенаправление всех несуществующих файлов на главный PHP-обработчик
Наиболее часто используемая конструкция - проверка, что запрошенный файл или директория не существуют, после чего запрос передаётся на PHP-скрипт (например, index.php). Это основа многих современных веб-приложений с «человекопонятными» URL.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?route=$1 [QSA,L]
Mod rewrite index php (настройка mod_rewrite для index.php)
Пояснение шагов:
RewriteEngine On- включает модуль mod_rewrite.RewriteCond %{REQUEST_FILENAME} !-f- проверяет, что запрошенный путь не является существующим файлом.RewriteCond %{REQUEST_FILENAME} !-d- проверяет, что путь не является существующей директорией.RewriteRule ^(.*)$ index.php?route=$1 [QSA,L]- если условия выполнены, перенаправляет запрос на index.php, передавая исходный URI как параметр route. Флаги QSA (Query String Append) и L (Last) завершают обработку.
Типичные ошибки и их решение:
- Ошибка 500 (Internal Server Error) - часто возникает из-за неверного синтаксиса или отсутствия модуля rewrite. Проверьте, что модуль включён (команда
a2enmod rewriteв Debian/Ubuntu). - Циклический редирект (бесконечный цикл) - если правило перенаправляет на уже обработанный URL. Решение: убедиться, что RewriteCond правильно исключает сам целевой скрипт (например, добавить условие
!-fили!-d). - Параметры запроса не передаются - без флага QSA они теряются. Используйте
[QSA]или[QSA,L].
Как разрешить доступ к реальным файлам, а все остальные запросы передать PHP-обработчику?
Этот вариант противоположен предыдущему: если файл существует, его отдаёт веб-сервер напрямую, иначе запрос идёт на PHP.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(.*)$ index.php [L]
Upstream php fpm (настройка upstream для php-fpm в nginx)
Пояснение: Первые два условия проверяют, что файл или директория существуют. Если условие верно, RewriteRule с минусом (^ -) ничего не делает и флаг L останавливает обработку. В противном случае запрос перенаправляется на index.php.
Проблема: При использовании этого подхода возможно случайное перенаправление запросов к PHP-файлам, которые должны обрабатываться напрямую. Решение - уточнить условия: исключить определённые расширения или пути.
Как проверить, что файл является символической ссылкой, и обработать иначе?
Директива RewriteCond %{REQUEST_FILENAME} -l позволяет проверить, является ли запрошенный путь символической ссылкой. Пример: перенаправление ссылок на специальный скрипт.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^(.+)$ symlink_handler.php?file=$1 [L]
запустить локальный сервер php (запуск локального сервера php)
Пояснение: Если путь является символической ссылкой, запрос обрабатывается скриптом symlink_handler.php с передачей имени файла. Для остальных файлов можно добавить другие правила.
Ошибка: Символическая ссылка может указывать на файл вне DocumentRoot. Убедитесь, что веб-сервер настроен на следование символическим ссылкам (опция FollowSymLinks в <Directory>).
Как защитить от прямого доступа к PHP-файлам в определённой папке?
Используется проверка расширения файла и перенаправление на страницу ошибки или главный обработчик.
RewriteEngine On
RewriteCond %{REQUEST_URI} \.php$
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule ^(.*)$ /error.php [L]
Php non thread safe (php non-thread-safe (не потокобезопасная версия))
Пояснение: Первое условие проверяет, что URI заканчивается на .php. Второе исключает сам файл index.php (чтобы не блокировать его). Если оба условия верны, запрос перенаправляется на /error.php. Это может использоваться для защиты скриптов, которые не должны вызываться напрямую.
Проблема: Блокируются все PHP-файлы, включая те, что нужны для AJAX-запросов. Решение: добавить исключения для конкретных файлов или папок через дополнительные RewriteCond с ! (отрицание).
Как проверить, что файл не пустой (имеет ненулевой размер)?
Условие RewriteCond %{REQUEST_FILENAME} -s истинно, если файл существует и его размер больше 0. Полезно для замены пустых файлов на сгенерированный контент.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule \.(jpg|png|gif)$ placeholder.php?file=$1 [L]
Rewritecond request filename php (правило rewritecond для php в .htaccess)
Пояснение: Если запрашивается изображение с расширением jpg, png или gif, но файл пустой (или не существует - !-s вернёт true), запрос обрабатывается скриптом-заглушкой, который может отдать дефолтное изображение.
Ошибка: !-s вернёт true также для несуществующих файлов. Если нужно различать несуществующий и пустой, используйте комбинацию -f и -s.
Как проверить доступность URL через внутреннюю подстановку (флаг -U)?
Флаг -U доступен только в Apache 2.4+. Он проверяет, что внутренний URI (после применения всех предыдущих RewriteRule) обрабатывается успешно (не возвращает 404). Пример - «красивые» URL с fallback на страницу ошибки, если контроллер неопределён.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?url=$1 [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteCond %{REQUEST_URI} -U
RewriteRule ^(.*)$ /custom-404.php [L]
Пояснение: Сначала несуществующие запросы передаются на index.php. Затем, если после внутреннего перенаправления (по флагу REDIRECT_STATUS) URI по-прежнему недоступен (-U), происходит редирект на кастомную 404 страницу.
Проблема: Флаг -U может снизить производительность, так как выполняет дополнительный внутренний запрос. Используйте его только при необходимости и следите за нагрузкой.
Расширенные примеры использования RewriteCond для PHP
Пример 1: Перенаправление с проверкой существования файла и папки, включая защиту от цикла
Код для .htaccess в корне сайта, который передаёт все запросы на index.php, кроме существующих файлов/папок и самого index.php.
RewriteEngine On
RewriteBase /
# Исключаем сам скрипт, чтобы избежать зацикливания
RewriteCond %{REQUEST_URI} !^/index\.php$
# Проверяем, что файл или папка не существуют
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Перенаправляем с сохранением строки запроса
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
Результат: Запрос /about обрабатывается как /index.php?/about, и PHP-скрипт может разобрать URL. Запрос /style.css (если файл есть) отдаётся напрямую.
Пример 2: Условное перенаправление на PHP-скрипт в зависимости от типа устройства (User-Agent)
Используется для мобильной версии: если файл не существует и User-Agent содержит «Mobile», запрос идёт на m.index.php, иначе на desktop версию.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_USER_AGENT} "Mobile|Android|iPhone" [NC]
RewriteRule ^(.*)$ m.index.php?route=$1 [L]
# Отдельное правило для остальных (десктоп)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?route=$1 [L]
Результат: Пользователь с мобильного браузера увидит мобильную версию, если файла не существует; иначе - стандартную.
Пример 3: Защита PHP-файлов с проверкой IP-адреса администратора
Доступ к /admin/ только для определённого IP; в противном случае - перенаправление на логин-скрипт.
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/admin/
RewriteCond %{REMOTE_ADDR} !^192\.168\.1\.100$
RewriteRule ^(.*)$ /login.php?redirect=$1 [L]
Результат: Если IP не совпадает с 192.168.1.100, пользователь перенаправляется на страницу входа.
Пример 4: Перенаправление старых URL на новые через PHP с сохранением 301 статуса
Используется внешний редирект (R=301) для SEO, при этом проверяется, что запрос соответствует старому шаблону.
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/old/(.*)\.html$
RewriteRule ^old/(.*)\.html$ /new.php?slug=$1 [R=301,L]
Результат: Запрос /old/article.html отправляет браузеру код 301 и перенаправляет на /new.php?slug=article.