Модуль Apache mod_rewrite для перенаправления запросов.

12.02.2017

Про то как работает модуль mod_rewrite очень хорошо написано на Хабре.

С помощью модуля mod_rewrite можно организовать перенаправление с одной страницу на другую, а использование регулярных выражений позволяет сделать перенаправление массовым, а не делать персонально для каждой странице.

Раньше у меня на сайте страницы выбирались на основании параметра p в строке запроса. В какое то время страницы стали не актуальными, и я решил их переместить в папку "/archive". Но чтобы посетитель, пришедший по внешним ссылкам на старые страницы, не получал страницу 404, мне нужно организовать перенаправление на новое место расположение. В этом мне поможет модуль rewrite и .htaccess

Итак, мне нужно перенаправить запрос вида "http://site.com/?p=foo" или "http://site.com/index.php?p=foo" на страницу "http://site.com/archive/foo.html"

В файле .htaccess делаю следующую запись

RewriteEngine On RewriteBase / RewriteCond %{QUERY_STRING} ^p=([\w]+) [NC] RewriteRule ^(index\.php){0,1}$ /archive/%1.html? [R=301,L]

RewriteCond задает условие срабатывания. Оно задается регулярным выражением, и оно выполняется если в строке запроса присутствует параметр p с каким то значением. Символ "^" означает начало строки, поэтому запрос "/?p=foo" сработает, а "/?map=foo" нет. Без этого символа сработал бы также и второй вариант.

Маска регулярного выражения ([\w]+), а не (.*) была выбрана по следующим соображениям. Значения параметра p всегда состояло только их цифр и символов. Но как то однажды порывшись в логах сервера, я обнаружил весьма странные запросы, в которых этот p был нашпигован чем то странным. Кто это был (или что), хакеры, роботы, я не знаю, но просто учел этот факт, и выбрал именно такую маску чтобы отсечь из значения параметра все символы, которых там не должно быть.

Флаг NC (флаги задаются в конце, в квадратных скобках) означает не чувствительность к регистру символов.

RewriteRule задает правило обработки относительного пути в запросе. Это правило выбирает только index.php или пустой путь. Символ "^" означает начало строки, символ "$" означает конец стоки, между ними выражение в скобках может встречать 0 или 1 раз. Символ "." экранирован слешем чтобы обозначить что это именно ".". Просто "." в регулярном выражении означает любой символ. Итак, index.php замещается /archive/%1.html, где %1 - это было поймано ([\w]+) в RewriteCond. Завершается запрос символом "?". Это нужно для того чтобы отсечь все параметры исходного запроса. В противном случае они приклеются к новому запросу, а мне это не нужно.

Флаг L означает прекращение дальнейшей обработки запроса модулем mod_rewrite, а R=301 означает что сервер отправит пустой документ с кодом ошибки "301 Moved Permanently" и с заголовком "Location: http://site.com/archive/%1.html". Т.е. на этом этапе дело даже не доходит до обработки документов и PHP.

Если вы хотите чтобы все запросы были адресованы исключительно на домен с www (www.domain.com), то сделайте редирект следующим образом:

# Rewrite domain.com -> www.domain.com RewriteCond %{HTTP_HOST} (.*) RewriteCond %{HTTP_HOST} !^www\.(.*) [NC] RewriteRule (.*) http://www.%1/$1 [R=301,L]

Если хотите сделать наоборот, чтобы все запросы были адресованы исключительно на домен без www (domain.com), то сделайте редирект следующим образом:

# Rewrite www.domain.com -> domain.com RewriteCond %{HTTP_HOST} ^www\.(.*) [NC] RewriteRule (.*) http://%1/$1 [R=301,L]

В последнее время увеличивается количество сайтов работающих с использованием защищенного соединения по протоколу https. Это вполне естественно, расширяется коммерческая деятельность, и владельцы сайтов уделяют должное внимание безопасности передаваемой персональной информации своих клиентов. И поисковая система Google уже оказывает давление на переход к протоколу https путем понижения рейтинга и повышения уровня опасности для сайтов работающих на небезопасном (обычном) протоколе http. Если у вас на сервере все готово для перехода на https, и нужно перенаправлять все обычные запросы на https, то достаточно сделать запись в .htaccess:

# Rewrite http://domain.com -> https://domain.com RewriteCond %{HTTP_HOST} (.*) RewriteCond %{SERVER_PORT} !^443 RewriteRule (.*) https://%1/$1 [R=301,L]