mod_rewrite – модуль веб-сервера Apache, предназначенный для преобразования URL. Работает «на лету», преобразуя запрошенный URL по заданным правилам с использованием регулярных выражений. При этом правила преобразований могут быть заданы как для веб-сервера в целом (в файле конфигурации httpd.conf или включаемых файлах), так и в контексте отдельной директории (в файле локальной конфигурации .htaccess). Кроме шаблонов правил, задаются также и условия их выполнения, в результате получается очень гибкий и мощный механизм преобразования. В условиях используются переменные окружения Apache, что позволяет управлять подменой не только URI, но и имени хоста, реагировать на браузер (или поискового бота), переадресовывать запрос в другой домен, обрабатывать ошибочные запросы и многое другое.
Применение модуля в практике сайтостроительства вполне соответствует широко известному «принципу 20×80»: 20% функций используются в 80% случаев, на остальные 80% функций приходится 20% использования. Это не значит, что в модуле много ненужного, это говорит о его широких возможностях. В основном модуль применяют для переадресации запросов и обработки псевдостатических ссылок, реже – для фильтрации и отсечения некорректных запросов.
Использование правил mod_rewrite для обработки псевдостатических ссылок стало фактическим стандартом в разработке «движков» сайта. Замена ссылки на скрипт с параметрами запроса ссылкой на статический файл (или директорию) требует обратной замены в момент обращения по этой ссылке. Модуль по заданным правилам разбирает URI и «реконструирует» подлинную ссылку на файл скрипта и параметры вызова. В результате скрипт (или набор скриптов) вызываются веб-сервером на обработку в естественном для скриптов формате, но в браузере посетителя никаких переадресаций и смены ссылки не происходит.
Например, скрипт галереи принимает в качестве параметров идентификатор раздела (строку символов латинского алфавита) — id и номер страницы в разделе — page. А в ссылках, которые он дает для навигации, значения параметров даны через дефис и добавлено расширение html. Ссылка на вторую страницу выставки чайников выглядит как /teapot-p2.html, а для получения этой страницы нужно вызвать скрипт index.php с параметрами id=teapot&page=2.
RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ([a-z]+)\-p([0-9]+)\.html$ index.php?id=$1&page=$2 [L]
Очень часто используется другой вариант разбора псевдостатики, когда ссылки разбирает «главный» скрипт движка. Но и в этом случае все равно требуется хотя бы одно правило для mod_rewrite, чтобы передать любой запрос в обработку именно этому скрипту.
RewriteEngine on RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteRule .* index.php [L]
По этому правилу любой запрос к несуществующему файлу передается скрипту index.php — а этот скрипт должен разобрать и обработать запрошенный URI.
Переадресация запросов (перенаправление) может быть реализована как внутри одного домена, так и между разными доменами. При этом код статуса HTTP можно задавать любой, в зависимости от целей перенаправления.
Для «склейки» доменов, например, может быть использован такой набор правил:
RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} !^new-domain\.com [NC] RewriteRule (.*) http://new-domain.com/$1 [R=301,L]
для HTTPS (SSL) будет так:
RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} !^new-domain\.com [NC] RewriteRule (.*) https://new-domain.com/$1 [R=301,L]
Этот вариант наиболее универсальный и в большинстве случаев лучше отдать ему предпочтение. Условие преобразования в этом случае означает «если имя запрошенного домена не начинается с new-domain.com». Тем самым набор правил привязан только к тому домену, в который будут перенаправляться все запросы. Сколько и каких доменов являются алиасами — совершенно неважно, все обращения к ним будут перенаправлены в один домен. Правило преобразования целиком подставляет «внутренний» URI, направляя клиента на тот же адрес внутри домена.
Другой вариант:
RewriteEngine on RewriteBase / RewriteCond %{HTTP_HOST} old-domain.com RewriteRule (.*) http://new-domain.com/$1 [R=301,L]
В этом примере проводится перенаправление запроса к old-domain.com в домен new-domain.com с сохранением внутреннего URI, то есть, фактически обрабатывается запрос к любой странице сайта с перенаправлением по тому же внутреннему адресу в другом домене. Это правила для случая «переезда» сайта в другой домен с сохранением всей структуры внутренних ссылок.
Строка RewriteCond задает условие преобразования: если обратились к хосту, имя которого содержит old-domain.com. Обратите внимание, здесь нет меток ^ («начинается с») и $ («оканчивается на»), поэтому условие истинно и для old-domain.com, и для www.old-domain.com.
Поскольку базой преобразования (RewriteBase) назначена корневая директория сайта, правило RewriteRule принимает как входной шаблон всю относительную ссылку (от корня сайта, исключая символ корня /). В этом качестве оно берет любую цепочку любых символов, которую содержит URI, и подставляет ее в выходной шаблон на место сочетания символов $1. После чего проводится переадресация запроса на сформированный адрес: Apache выдает посетителю в заголовке HTTP статус 301 («Moved Permanently»), и в поле Location: заголовка помещает сформированный адрес.
Таким образом, запрос http://www.old-domain.ru/anydir/anyfile.php?id=314 будет перенаправлен на адрес http://new-domain.ru/anydir/anyfile.php?id=314
Другой распространенный случай — использование переадресации для выбора канонической (основной) формы доменного имени (с www или без www). Например, для выбора домена www.domain.com нам нужен такой набор правил:
RewriteEngine on RewriteBase / RewriteCond %{HTTP_HOST} !^www RewriteRule (.*) http://www.domain.com/$1 [R=301,L]
В этом случае условие преобразования буквально означает «если имя хоста не начинается с www». При выполнении этого условия (например, запрошен http://domain.com/anyfile.html) сработает правило, которое подставит внутренний URI в шаблон и перенаправит по тому же адресу в домене с www — http://www.domain.com/anyfile.html.
Если вы хотите избавиться о www в адресе сайта, то можно применить в .htaccess такой код:
RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} !^domain\.com [NC] RewriteRule (.*) http://domain.com/$1 [R=301,L]
Где domain.com - домен вашего сайта. Данное условие получает переменную HTTP_HOST (имя домена), сравнивает с требуемым (!^domain\.com [NC]), если условие выполняется и HTTP_HOST не равно domain.com, то переадресовываем на наш домен domain.com.
Как сделать редирект названия каталога без слеша на название со слешем ( site.info/url ⇒ site.info/url/ )?
Всё просто:
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_URI} !(.*\..*|.*/)$ RewriteRule ^(.*)$ /$1/ [R=301,L]
Бывают такие случаи, когда требуется, чтобы не было слеша в конце url (хотя это не есть правильно), для этого необходимо сделать редирект такого плана site.info/url/ ⇒ site.info/url Все просто:
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} ^(.+)/$ RewriteRule ^(.+)/$ /$1 [R=301,L]
От поисковых роботов нам прятать нечего. Но, как известно, «любительских» и спамерских ботов становится всё больше. Многие из них не поддерживают стандарт исключений и даже не запрашивают файл robots.txt. Зато с гордостью предъявляют своё название (User-agent). Толку от такого робота нам никакого, только лишняя нагрузка на сервер. Мы можем закрыть доступ такому некорректному боту простым правилом:
RewriteEngine on RewriteBase / RewriteCond %{HTTP_USER_AGENT} Vasin-Robot RewriteRule (.*) - [F,L]
Условие проверяет наличие в переменной окружения HTTP_USER_AGENT строки Vasin-Robot. Если такая строка обнаружена, сработает правило преобразования. Оно очень простое: по любому запросу ничего не пеобразовывать, выдать HTTP-заголовок с кодом статуса «403 Forbidden». Васин робот получит этот заголовок вместо любого запрошенного документа, никакие другие действия выполняться не будут.
К сожалению, широкие возможности mod_rewrite порождают ошибочное представление о его «всемогуществе». Очень часто на форумах задают глупые вопросы вроде «как с помощью mod_rewrite отдавать 404 на ошибочные запросы?». Этот модуль ничего не «знает» о движке сайта, особенностях его работы, структуре данных – он умеет только работать с URI по заранее определенным правилам с применением регулярных выражений POSIX. Больше ничего. Чудес не бывает.
Настоятельно не рекомендуется брать какие попало правила и дописывать их к себе в .htaccess, если не понимаете:
Такой подход напоминает самолечение по принципу «если соседу эти таблетки помогли от головной боли, то может быть, и мой геморрой вылечат». Во многих случаях механическое повторение возможно только с тем же самым движком (и с теми же самыми настройками).
Это на первый взгляд не очевидно, но порядок следования правил для mod_rewrite очень важен. Условия и правила проверяются в том порядке, в каком они записаны. При первом же совпадении URL с условием и шаблоном правила будет запущена обработка запроса по этому правилу. Поэтому всю совокупность правил нужно рассматривать как единое целое и определять примерно такой порядок следования:
Если вы разместите правила для перенаправления ниже, чем правила преобразования URL, то во многих случаях до перенаправления просто «не дойдет ход». То же самое и с правилами для блокировки доступа.
Статья не претендует на полное раскрытие темы mod_rewrite — тем более, что тема давно раскрыта другими. И сделаны отличные переводы на русский язык. Изучать mod_rewrite рекомендуется не по «сборникам рецептов для .htaccess», собранных не всегда грамотными людьми, а по этим источникам: