Введение в использование mod_rewrite. Что вам нужно знать об.htaccess

12.07.2019

Почему то на просторах рунета информация о локальной настройки веб-сервера Apache посредством конфигурационного файла .htaccess приводится как то не полно и однобоко. В основном приводятся примеры (часто не рабочие) или сухой перевод англоязычной документации.

А как же быть, если нужно настроить несколько редиректов, и совсем нет времени познавать всю мощь .htaccess ? Единственный выход это брать готовые примеры, и наугад адаптировать под свои нужды. В этой статье я напишу краткое руководство по .htaccess , которое закроет большинство вопросов новичков. А также приведу ссылки на подробные инструкции. Эта статья будет дописываться по мере необходимости, начну с самого основного.

Редиректы

Редиректы осуществляются с помощью модуля mod_rewrite . Задаются правила преобразований в виде следующей конструкции:

Options +FollowSymLinks RewriteEngine On [СЮДА ПИШЕМ ПРАВИЛА]

Правила преобразования записываются в таком виде:

RewriteCond [СТРОКА ДЛЯ СРАВНЕНИЯ] [УСЛОВИЕ] [ФЛАГИ] RewriteCond [СТРОКА ДЛЯ СРАВНЕНИЯ] [УСЛОВИЕ] [ФЛАГИ] RewriteRule [ШАБЛОН] [СТРОКА ПОДСТАНОВКИ] [ФЛАГИ]

Строки RewriteCond - задают условия для срабатывания следующего за ними правила RewriteRule . Условий может быть несколько, они накладываются по правилу AND . Но можно изменить правило на OR с помощью флага OR .

В качестве [СТРОКИ ДЛЯ СРАВНЕНИЯ] могут использоваться различные переменные. Ссылка на полный список Я приведу только те, которые нужны чаще всего:

Подвыражения в регулярных выражениях (заключенные в скобки), доступны для вставки в [СТРОКУ ПОДСТАНОВКИ] , обращаться к подвыражениям нужно так: %N - для подвыражений в условиях (RewriteCond ) и $N - для подвыражений в правилах (RewriteRule ), где N - порядковый номер подвыражения.

RewriteRule - правило подстановки. Если запрос подходит под вышестоящие проверки и [ШАБЛОН] , то применяется правило подстановки. Здесь регулировать поведение также можно с помощью флагов. Флаги есть разные, приведу наиболее часто используемые:

Надеюсь после моего краткого ввода в теорию, вам будет проще понимать что же написано в вашем .htaccess . Привожу ссылку на очень хороший перевод про модуль mod_rewrite , там же можно найти другие хорошие переводы.

Внимание! Браузеры кешируют редиректы!!!

Причем обычные сочетания типа Ctrl+F5 или Ctrl+R не помагают. Я во время тестирования каждый раз открываю страницу в НОВОМ окне в режиме инкогнито. Причем старые страницы в режими инкогнито надо закрывать.

Примеры

Универсальный редирект с www на без www

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

RewriteCond %{HTTP_HOST} ^www\.(.*) RewriteRule ^(.*)$ http://%1/$1

Проверяем доменное имя, если оно начинается с www, то сработает правило: "все, на http://%1/$1 ". Здесь %1 это наш домен без www (взят из условия), а $1 это адрес (взят из самого правила).

Универсальный редирект с без www на www

RewriteCond %{HTTP_HOST} ^(.*)$ RewriteCond %{HTTP_HOST} !^www\. RewriteRule ^(.*)$ http://www.%1/$1

Тут маленько сложнее. Первое условие нужно для того чтобы получить домен (%1 ), оно всегда истина. Второе условие проверяет, что домен начинается не с www. Ну и само правило, аналогичное предыдущему примеру

Простой редирект

RewriteRule ^news/happy.* /news.html

Для простого редиректа условия задавать не обязательно, только правило.

Реврайт без редиректа

RewriteRule ^news/happy.* /news.html [L]

Иногда требуется, чтобы был редирект без смены адреса, т.е. реврайт без редиректа. Для этого просто не указываем флаг редирект (R ), и получаем желаемый результат, теперь по адресу news/happy получим news.html , а в адресной строке останется news/happy

Редирект от GET параметров

Например, нужно что бы со страницы /?action=page&id=15 был редирект на /page/15/ :

RewriteCond %{QUERY_STRING} action=page RewriteCond %{QUERY_STRING} id=(\d+) RewriteRule .* /page/%1/?

Поясню, первым условиям проверяем что есть get параметр action=page , вторым условием проверяем что id равно числу. Эти условия нельзя объединять, т.к. параметры могут идти и наоборот, т.е. index.php?action=page&id=15 и index.php?id=15&action=page должны быть равноценны. Но и наконец правило, там все обычно, кроме знака вопрос (? ) на конце. Он нам нужен, чтобы отсечь исходные GET параметры, иначе получим /page/15/?action=page&id=15

Редирект на мобильную версию сайта

Допустим, что мобильная версия расположена на поддомене m.site.ru . Будем переходить на мобильную версию только с главной страницы основного домена.

RewriteCond %{HTTP_USER_AGENT} (?i:midp|samsung|nokia|j2me|avant|docomo|novarra|palmos|palmsource|opwv|chtml|pda|mmp|blackberry|mib|symbian|wireless|nokia|hand|mobi|phone|cdm|upb|audio|SIE|SEC|samsung|HTC|mot-|mitsu|sagem|sony|alcatel|lg|eric|vx|NEC|philips|mmm|xx|panasonic|sharp|wap|sch|rover|pocket|benq|java|pt|pg|vox|amoi|bird|compal|kg|voda|sany|kdd|dbt|sendo|sgh|gradi|jb|dddi|moto|iphone|android) RewriteCond %{HTTP_HOST} site.ru RewriteRule ^$ http://m.site.com/

Первой строкой мы проверяем USER_AGENT, определяем что он относится к мобильникам. (эту строку я детально не проверял, взял на просторе интернета, возможно она не совсем корректная, или есть более универсальная строка. Но на моих мобильных устройствах этот пример работает)

Второй строкой проверяем что мы находимся на нужном домене (т.к. пример не универсальный)

Третьей строкой, мы проверяем, что находимся на главной страницы (без всяких параметров и прочего) и перенаправляем на поддомен.

Универсальная версия

Я люблю, чтобы все было универсально, чтобы один и тот же код работал на разных проектах без каких - либо правок. Для этого я переделал предыдущий пример:

RewriteCond %{HTTP_HOST} ^(.*)$ RewriteCond %{HTTP_USER_AGENT} (?i:midp|samsung|nokia|j2me|avant|docomo|novarra|palmos|palmsource|opwv|chtml|pda|mmp|blackberry|mib|symbian|wireless|nokia|hand|mobi|phone|cdm|upb|audio|SIE|SEC|samsung|HTC|mot-|mitsu|sagem|sony|alcatel|lg|eric|vx|NEC|philips|mmm|xx|panasonic|sharp|wap|sch|rover|pocket|benq|java|pt|pg|vox|amoi|bird|compal|kg|voda|sany|kdd|dbt|sendo|sgh|gradi|jb|dddi|moto|iphone|android) RewriteRule ^$ http://m.%1

Редирект с главной страницы

Речь идет про запрос типа site.ru (без site.ru/index.php)

Здесь оказалось не все так очевидно, я столкнулся с необъяснимым поведением.

Рабочий вариант :

RewriteRule ^index.php$ /about/ [L]

Редирект. НЕ рабочий вариант :

RewriteRule ^index.php$ /about/

Реврайт без редиректа (урл не меняется). НЕ рабочий вариант :

RewriteRule ^$ /about/ [L]

Редирект. Рабочий вариант :

RewriteRule ^$ /about/

Если мне кто - нибудь расскажет почему эти примеры работают крест накрест, а обратно не работают - буду очень рад.

8. Директива RewriteOptions, технические подробности, когда НЕ использовать mod_rewrite

В предыдущих частях мы изучили практически всю документацию по mod_rewrite . Остались директивы RewriteMap и RewriteOptions . RewriteMap также используется для перезаписи URL адресов, но применяется реже других; к ней мы вернёмся позже. Директива RewriteOptions также применяется нечасто. Особенностью RewriteMap является то, что её нельзя использовать в .htaccess . Её можно использовать только в контексте сервера, либо виртуальных хостов. По большому счёту, RewriteMap не добавляет новой функциональности - она только позволяет вынести большой массив данных, которые нецелесообразно или слишком сложно описывать при помощи регулярных выражений, в отдельные файлы. Получаются такие выделенные базы данных. Тем не менее, мы всё равно рассмотрим RewriteMap в одной из последующих частей.

Сейчас для закрепления изученной теории, мы перейдём к практическим примерам самых частых случаев использования mod_rewrite, включая подробное описание того, как они работаю. Если после знакомства с теорией и этими примерами у вас остались вопросы, то пишите их здесь в комментариях.

Обратите внимание, что во многих примерах используются конкретные файловые пути, значения запросов и прочее - эти примеры не будут работать у вас без изменений в вашей конфигурации сервера, поэтому важно, чтобы вы их понимали, а не просто копировали в вашу конфигурацию.

Проверка доступности mod_rewrite

Как включить RewriteEngine

О включении модуля mod_rewrite в конфигурационном файле Apache было рассказано в . Если модуль включен, то его необходимо активировать в файле .htaccess директивой :

RewriteEngine On

Это достаточно сделать один раз, даже если вы используете несколько правил перезаписи.

Для работы модуля также необходима активация опции FollowSymLinks . Эта опция может быть активирована в конфигурационном файле Apache (об этом также уже было сказано в первой части). Если эта опция отключена на уровне веб-сервера (или виртуального хоста), то её можно включить в файле.htaccess. Её нужно указать до директивы RewriteEngine :

Options +FollowSymLinks RewriteEngine On

Как проверить, включён ли mod_rewrite

Как проверить в PHP включён mod_rewrite или нет

Самым простым способом является использование функции phpinfo() . Если модуль включён, то в таблице apache2handler в колонке Loaded Modules будет указано mod_rewrite (а также все другие модули, которые включены).

Этот способ является самым универсальным: вы можете использовать его в любой системе, в том числе на совместном (shared) хостинге.

Как проверить в Windows включён ли mod_rewrite

Откройте командную строку (Win+x , затем выберите Windows PowerShell ). Перейдите в каталог, где размещены бинарные файлы Apache. Например, в моём случае это папка C:\Server\bin\Apache24\bin\:

Cd C:\Server\bin\Apache24\bin\

И выполните там команду:

./httpd.exe -M

Будет выведен полный список модулей.

Как проверить в Linux включён ли mod_rewrite

Чтобы вывести список всех загруженных веб-сервером Apache модулей, используется опция -M . Исполнимый файл веб-сервера может называться apache2ctl или httpd в зависимости от используемого дистрибутива.

Для Debian, Ubuntu, Kali Linux, Linux Mint и их производных команда для вывода списка модулей следующая:

Apache2ctl -M

Для Arch Linux, BlackArch и некоторых других дистрибутивов команда такая:

Httpd -M

Проверка включён ли mod_rewrite с помощью.htaccess

В файле .htaccess запишите директиву:

RewriteEngine on

И попробуйте открыть адрес папки, где вы сохранили.htaccess, если возникнет ошибка «500 Internal server error», значит модуль mod_rewrite не включён в конфигурационном файле Apache.

Как сделать так, чтобы правила перезаписи использовались только если mod_rewrite включен

Конструкция проверяет, включён ли модуль. Если модуль включён, то выполняются директивы, которые находятся в секции . Если модуль отключён, то эти директивы игнорируются. В результате, если модуль выключен, то неизвестные директивы не вызовут ошибку веб-сервера.

Синтаксис использования:

…… ……

Вместо многоточий запишите желаемые директивы mod_rewrite, пример:

RewriteEngine On RewriteCond %{HTTP_USER_AGENT} ^HTTrack RewriteCond %{HTTP_USER_AGENT} ^sqlmap RewriteCond %{HTTP_USER_AGENT} ^wpscan RewriteCond %{HTTP_USER_AGENT} ^text RewriteRule ^.* - [F]

Перед именем модуля можно поставить ! (восклицательных знак) и тогда то, что внутри IfModule будет выполнено только если проверяемый модуль НЕ включён.

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

Эту секцию следуют использовать только если вам нужен один конфигурационный файл, которые работает независимо от того, доступен ли определённый модуль. При обычной работе директивы не должны размещаться в секциях .

Использование mod_rewrite для перенаправления (редиректа) и переназначения URL

Страница поменяла адрес, как показать новую страницу по старому адресу без редиректа

Описание:

Предположим, мы недавно переименовали страницу foo.html в bar.html и теперь хотим, чтобы старый URL также работал для обратной совместимости. Однако мы хотим, чтобы пользователи старого URL-адреса даже не узнали, что страницы были переименованы, то есть мы не хотим, чтобы адрес изменялся в их браузере.

Мы с помощью RewriteRule делаем преобразования запроса, содержащего старый адрес, на новый, задав следующее правило:

RewriteEngine on RewriteRule "^/foo\.html$" "/bar.html"

В этом примере ^/foo\.html$ является регулярным выражением. Символы ^ и $ обозначают начало и конец строки соответственно. Перед точкой стоит слеш, чтобы символ трактовался буквально (как точка), а не как подстановочный символ (в качестве подстановочного символа точка означает любой один символ).

Страница поменяла адрес, как перенаправить на новую страницу при запросе старой (редирект)

Описание:

Предположим еще раз, что мы недавно переименовали страницу foo.html в bar.html и вновь хотим, чтобы старый URL работал для обратной совместимости. Но на этот раз мы хотим, чтобы пользователи старого URL-адреса получили намек на новый, т. е. поле адресной строки их веб-браузера должно измениться.

Мы принудительно перенаправляем HTTP на новый URL-адрес, что приводит к изменению адреса страницы в браузере и, следовательно, того, что показано пользователю:

RewriteEngine on RewriteRule "^/foo\.html$" "bar.html" [R]

Кстати, для простых случаев редиректа можно использовать директиву Redirect . Эта директива не смогла бы заменить первый пример, когда мы показываем содержимое другой страницы без смены адреса (без редиректа). С Redirect второй пример выглядел бы так:

Redirect "/foo.html" "/bar.html"

Переадресация при смене домена

Описание:

Если сайт сменил домен, но сохранил прежнюю структуру страниц. Вы хотите, чтобы старые URL адреса продолжали работать пока пользователи не обновят их закладки.

Вы можете использовать mod_rewrite для перенаправления этих URL на новый домен, но также рассмотрите вариант с использованием директив Redirect или RedirectMatch .

В последующих примерах замените example.com на адрес сайта, куда должен выполняться редирект.

# С mod_rewrite RewriteEngine on RewriteRule "^/docs/(.+)" "http://new.example.com/docs/$1"

Правило означает найти запросы, которые содержат строку, которая начинается с /docs/ (символ ^ означает начало строки, а /docs/ – это буквальная последовательность символов), за которой затем следует что угодно (точка означает любой символ, а знак плюс означает один или более раз). Скобки образуют обратную ссылку. Т.е. то, что совпадает с выражением в скобках, можно использовать в дальнейшем, сославшись на это с помощью $1 .

В строке перезаписи http://new.example.com/docs/ является буквальной частью, а $1 - это то, что совпало с частью выражения в скобках, т.е. обратная ссылка на (.+) .

Таким образом, если был сделан запрос http://another.com/docs/best, то будет сделана переадресация на адрес http://new.example.com/docs/best.

# С RedirectMatch RedirectMatch "^/docs/(.*)" "http://new.example.com/docs/$1" # С Redirect Redirect "/docs/" "http://new.example.com/docs/"

Директивы Redirect и RedirectMatch должы быть «легче» для сервера, но не всегда сложные случаи можно описать без использования mod_rewrite.

Простой редирект на новый сайт

Если сайт сменил домен и не сохранил структуру страниц, т.е. если вам нужно перенаправить все запросы на новый сайт (например, на его главную страницу), то это делается так:

RewriteEngine on RewriteRule ^ https://newsite.ru

В результате независимо от запрошенной страницы, все запросы будут переданы на главную страницу другого домена. Замените https://newsite.ru на тот сайт, куда вы перенаправляете запросы.

Как переправить все запросы из одной директории, в другую

Псевдоним для единичной директории:

RewriteEngine On RewriteRule ^source-directory/(.*) /target-directory/$1

Все обращения к содержимому директории source-directory будут переадресованы к содержимому директории target-directory.

Использовать URL адресов без расширения файлов.php

Этот снипет позволяет вам использовать URL без расширения PHP, например, example.com/users вместо example.com/users.php.

RewriteEngine On RewriteCond %{SCRIPT_FILENAME} !-d RewriteRule ^([^.]+)$ $1.php

Универсальный документ ошибки (Error Document) для не найденных ресурсов (ошибка 404 Not Found)

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

RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ /dir/error.php

Если это правило перезаписи вызовет ошибку сервера, то замените флаг на . Флаг подходит лучше, но поддерживается Apache 2.4 и не поддерживается версией Apache 2.2.

Вместо /dir/error.php нужно указать путь до файла, который вы хотите показывать в случае возникновения ошибки 404 (файл не найден).

Со статики на динамику

Описание:

Как мы можем трансформировать статичную страницу foo.html в динамичный вариант foo.cgi бесшовным образом, т.е. без уведомления браузера/пользователя.

Мы просто переписываем URL на CGI-скрипт и принуждаем обработчик быть cgi-скриптом так, что он выполняется как CGI программа. Таким образом, запрос /~quux/foo.html внутренне приводить к вызову /~quux/foo.cgi.

RewriteEngine on RewriteBase "/~quux/" RewriteRule "^foo\.html$" "foo.cgi"

Обратная совместимость для изменений расширения файла

Описание:

Как мы можем сделать обратную совместимость URL (виртуально ещё существующих) после миграции document.YYYY в document.XXXX, например, после перехода ряда.html файлов на.php?

Мы переписываем имя в его базовое имя и проверяем наличие файла с новым расширением. Если он существует, мы берем его, иначе URL используется в исходном состоянии.

# набор правил для обратной совместимости # для перезаписи document.html на document.php # только тогда, когда document.php существует RewriteEngine on RewriteBase "/var/www/htdocs" RewriteCond "$1.php" -f RewriteCond "$1.html" !-f RewriteRule "^(.*).html$" "$1.php"

Обсуждение

В этом примере используется часто забываемая возможность mod_rewrite, вытекающая из порядка выполнения набора правил. В частности, mod_rewrite оценивает левую сторону RewriteRule (Шаблон поиска), прежде чем оценивать директивы RewriteCond. Следовательно, $1 уже определён к тому времени, когда оцениваются директивы RewriteCond. Это позволяет нам проверять наличие исходного (document.html) и целевого (document.php) файла с использованием того же базового имени файла.

Этот набор правил предназначен для использования в контексте директорий (в блоке или в файле.htaccess), так что проверки -f смотрят в каталог по правильному пути. Возможно, вам потребуется установить директиву RewriteBase, чтобы указать базу каталогов, в которой вы работаете.

Замена на WebP изображения

Если поддерживаются WebP изображения, и изображение с файловым расширением.webp найдено в том же месте, где на сервере находится картинка jpg/png, то вместо неё будет отправлено изображение WebP.

RewriteEngine On RewriteCond %{HTTP_ACCEPT} image/webp RewriteCond %{DOCUMENT_ROOT}/$1.webp -f RewriteRule (.+)\.(jpe?g|png)$ $1.webp

Канонические имена хостов и URL. HTTPS

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

  • http://www.yoursite.com/
  • http://yoursite.com/
  • http://www.yoursite.com
  • http://yoursite.com
  • http://www.yoursite.com/index.php
  • http://yoursite.com/index.php
  • http://yoursite.com/?

Вариантов может быть даже больше, если сайт доступен и на HTTP, и на HTTPS. Также варианты могут возникнуть из-за различных ошибок составления ссылок, при которых страница продолжает открываться. Например:

  • http://www.yoursite.com//index.php

Хотя большинству людей понятно, что все эти URL являются одним и тем же, с технической точки зрения это не так. Для веб-сервера это различные URL. И если они открыты, поисковые системы их могут проиндексировать.

Поисковые системы стали значительно более продвинутыми, но не нужно рассчитывать только на них в вопросе борьбы с диблирующими страницами. К тому же, это может внести путаницу в аналитику (когда для каждого из перечисленного примера доход или посещаемостью считаются отдельно, хотя это одна и та же страница).

Поэтому веб-мастеру следует позаботиться о каноническом URL. На самом деле, нет никакой разницы, какую именно форму URL вы выберите в качестве канонической. Главное, выбрать что-то одно и придерживаться этого.

Как сделать редирект с HTTP на HTTPS

Помните, что для использования HTTPS протокола недостаточно просто сделать переадресацию, также должен быть настроен веб-сервер. То есть вы должны получить сертификаты и указать их в настройках хоста. Также веб-сервер должен быть настроен на прослушивание 443 порта. Если это всё готово, то для перенаправления на HTTPS, в файл .htaccess добавьте строки:

RewriteEngine on RewriteCond %{HTTPS} !on RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

В этом примере переменная %{HTTPS} содержит on , если сайт использует HTTPS и содержит off , если используется HTTP. Таким образом, адрес страницы переписывается только если к ней обращаются по HTTP.

В RewriteRule в качестве шаблона поиска используется ^ – символ начала строки. Т.е. под это условие подпадают все строки. Цель переадресации указывается с помощью буквальной строки https:// и двух переменных окружения %{HTTP_HOST} и %{REQUEST_URI} .

Strict-Transport-Security: max-age=31536000; includeSubDomains

Как сделать редирект на с HTTP на HTTPS всех страниц кроме некоторых

Предположим, что нам нужно перевести на HTTPS все страницы кроме тех, которые находятся в папке /.well-known/ , тогда используется следующая конструкция:

RewriteEngine on RewriteCond %{HTTPS} !on RewriteCond %{REQUEST_URI} !^/.well-known/ RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

Замените /.well-known/ на желаемую папку или адрес страницы.

Если нужно исключить несколько страниц или каталогов, то составьте регулярное выражение с альтернативным выбором, т.е. с использованием трубы (| ). Например, нужно включить переадресацию на HTTPS для всех страниц кроме находящихся в папке /.well-known/, в папке /test/, а также файла /stay-away.php:

RewriteEngine on RewriteCond %{HTTPS} !on RewriteCond %{REQUEST_URI} !^(/.well-known/|/test/|/stay-away.php) RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

Как сделать редирект на с HTTP на HTTPS только некоторых страниц

Если вам нужно перенаправить с HTTP на HTTPS только отдельные страницы, то подойдут показанные ранее примеры. Единственное необходимое в них изменение - убрать восклицательный знак (! ), который служит для отрицания совпадения.

Для настройки редиректа на HTTPS только для папки /.well-known/

RewriteEngine on RewriteCond %{HTTPS} !on RewriteCond %{REQUEST_URI} ^/.well-known/ RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

Для настройки редиректа на HTTPS только для папки /.well-known/, папки /test/, а также файла /stay-away.php:

RewriteEngine on RewriteCond %{HTTPS} !on RewriteCond %{REQUEST_URI} ^(/.well-known/|/test/|/stay-away.php) RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

Принудительное использование HTTPS за прокси

Полезно, если у вас есть прокси-сервер перед вашим сервером, отключающий TLS.

RewriteCond %{HTTP:X-Forwarded-Proto} !https RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Всегда использовать WWW перед именем домена

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

RewriteEngine on RewriteCond %{HTTP_HOST} ^example\.com RewriteRule ^(.*)$ http://www.example.com/$1

Обратите внимание, что example.com нужно заменить на домен вашего сайта, вместо протокола http:// может быть указано https:// , а в строке ^example\.com слеш перед точкой не случаен - эта строка является регулярным выражением, чтобы точка рассматривалась не как подстановочный символ, а как буквальная точка, используется слеш.

Всегда использовать WWW перед именем домена - универсальный вариант

Этот вариант подойдёт без изменений для любых сайтов: не нужно указывать имя хоста (доменное имя), а также не нужно указывать, используется ли протокол HTTP или HTTPS. Т.е. это более универсальный вариант.

RewriteEngine On RewriteCond %{HTTP_HOST} !="" RewriteCond %{HTTP_HOST} !^www\. RewriteCond %{HTTPS}s ^on(s)| RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI}

Первое условие проверяет, не является ли значение Host пустым (в случае HTTP/1.0). Второе проверяет, не начинается ли Host на www ..

Обратите внимание на RewriteCond %{HTTPS}s ^on(s)| . Здесь используется довольно хитрый приём. Как было сказано чуть выше, переменная окружения %{HTTPS} содержит on , если сайт использует протокол HTTPS , и содержит off , если используется HTTP . К переменной окружения добавлена буквальная буква s , в результате происходит проверка строки %{HTTPS}s , которая, в зависимости от того, включен ли HTTPS или нет, может сводиться к ons или offs . Эта строка сравнивается с регулярным выражением ^on(s)| , где ^ – это символ начала строки. Символ трубы (| ) говорит о том, что подойдёт любая альтернатива - стоящая перед этим символом или после. Перед этим символом стоит строка on(s) , а после - ничего. Пустая строка соответствует любой сравниваемой строке. Исходя из этого, результат RewriteCond всегда будет сводиться к истине. Но в зависимости от того, какая часть регулярного выражения совпала: on(s) или пустая строка, обратная ссылка будет иметь значение «s » или будет пустой строкой. Обратная ссылка задаётся скобками, в которых находится буква s .

В результате http%1 при RewriteRule будет сводиться к https или к http .

Таким образом, это правило подойдёт для любого сайта, в нём не нужно прописывать свой домен как это нужно делать в предыдущем. Также не нужно заботиться о протоколе сайта.

Никогда не использовать WWW перед именем домена

Если вам не нужно , чтобы перед доменом в строке браузера были буквы www , то используйте следующее правило:

RewriteEngine on RewriteCond %{HTTP_HOST} ^www\.example\.com RewriteRule ^(.*)$ http://example.com/$1

В нём замените http://example.com на имя вашего домена. Также обратите внимание на протокол. Во второй строке слеши используются для того, чтобы точки в регулярном выражении трактовались как буквальные символы (а не подстановочные).

Никогда не использовать WWW перед именем домена - универсальный вариант

Если вам нужно избавиться от www в адресной строке браузера, то следующее правило это сделает, переадресую запрос на аналогичный адрес, но без www :

RewriteEngine on RewriteCond %{HTTP_HOST} ^www\. RewriteCond %{HTTPS}s ^on(s)|off RewriteCond http%1://%{HTTP_HOST} ^(https?://)(www\.)?(.+)$ RewriteRule ^ %1%3%{REQUEST_URI}

В этом наборе условий и правила не нужно указывать свой домен - конструкция является универсальной для любого сайта, также подходит для сайтов на HTTP и HTTPS.

Принудительное использование канонического имени с HTTPS и www

Если ваш сайт работает через протокол HTTPS и в качестве канонического имени вы выбрали использовать www перед именем домена, то вам поможет любое из следующих правил. У них нет принципиальной разницы, если какоео-то из них не подошло для ваших условий, просто попробуйте другое.

Первый способ:

RewriteEngine On RewriteCond %{HTTPS} off RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} RewriteCond %{HTTP_HOST} !^www\. RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI}

В этом примере имеются два правила перезаписи. Первое перенаправляет на HTTPS. Второе правило перезаписывает любой запрос с неверным доменом на использование www. Флаг означает совпадение независимо от регистра.

Второй способ:

RewriteEngine On RewriteCond %{HTTP_HOST} (?!^www\.)^(.+)$ RewriteCond %{HTTPS} off RewriteRule ^ https://www.%1%{REQUEST_URI}

Третий способ:

RewriteEngine on RewriteCond %{HTTP_HOST} !^$ RewriteCond %{HTTP_HOST} !^www\. RewriteCond %{HTTPS}s ^on(s)| RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

Четвёртый способ (замените domain.ru на свой домен):

RewriteEngine On RewriteCond %{HTTP_HOST} !^www\.domain\.ru RewriteRule ^(.*)$ https://www.domain.ru/$1 RewriteCond %{SERVER_PORT} 80 RewriteRule ^(.*)$ https://www.domain.ru/$1

Канонический вид с HTTPS и без www

Если ваш сайт работает на HTTPS, но вы не хотите видеть www в адресной строке браузера перед именем домена, то используйте:

RewriteEngine on RewriteCond %{HTTPS} !on RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} RewriteCond %{HTTP_HOST} ^www\. RewriteCond %{HTTPS}s ^on(s)|off RewriteCond http%1://%{HTTP_HOST} ^(https?://)(www\.)?(.+)$ RewriteRule ^ %1%3%{REQUEST_URI}

Принудительное SSL и www для главного домена, принудительное SSL без www для всех поддоменов (кроме локальных)

RewriteEngine On # для поддоменов: принудительно ssl и без www RewriteCond %{HTTP_HOST} !\.local$ RewriteCond %{HTTPS} !=on RewriteCond %{HTTP_HOST} !^(www\.)?domain\.ru$ RewriteCond %{HTTP_HOST} ^(?:www\.|)(.*)$ RewriteRule ^.*$ https://%1%{REQUEST_URI} # для главных доменов: принудительно ssl без www RewriteCond %{HTTP_HOST} !\.local$ RewriteCond %{HTTPS} !=on RewriteCond %{HTTP_HOST} ^domain\.ru$ RewriteRule ^.*$ https://www.domain.ru%{REQUEST_URI}

Замените domain.ru на имя вашего домена.

Принудительное добавление конечного слеша к адресу сайта

Если вам нужно добавить к URL конечный слеш (в том случае, если он отсутствует), то воспользуйтесь этим правилом перезаписи:

RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*[^/])$ /$1/

Удаление конечного слеша

Этот сниппет перенаправит пути, заканчивающиеся на слеши, на аналогичные, но без конечного слеша (кроме действительных директорий), к примеру http://www.example.com/blog/ на http://www.example.com/blog. Это важно для SEO, поскольку рекомендуется иметь канонический URL для каждой страницы.

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

RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1

Удаление конечных слешей из произвольных путей

Удаление конечных слешей из URL для веб-сайтов, размещённых в директории (как example.org/blog/):

RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} (.+)/$ RewriteRule ^ %1

Удаление лишних слешей в адресе URL

Например, страница /catalog///stranica.html доступна и открывается. Чтобы избежать такой ситуации и не плодить бесконечное число дублей следует записать следующий редирект:

RewriteEngine on RewriteBase / RewriteCond %{HTTP_HOST} !="" RewriteCond %{THE_REQUEST} ^+\s//+(.*)\sHTTP/+$ RewriteCond %{THE_REQUEST} ^+\s(.*)//+\sHTTP/+$ RewriteRule .* http://%{HTTP_HOST}/%1 RewriteCond %{REQUEST_URI} ^(.*)//(.*)$ RewriteRule . %1/%2

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

Основы и особенности mod_rewrite, примеры использования mod_rewrite, переменные сервера, флаги (RewriteRule Flags ), перенаправление, запрет доступа по времени суток или агенту пользователя, запрет доступа по рефереру или при его отсутствии.

Мир Вам Братья и Сёстры! По просьбам трудящихся сегодня я здесь типа обучающая программа, которую зовут Олег, и, сегодня мы с Вами попробуем объяснить, самим себе в первую очередь, основные принципы работы чудо-модуля mod_rewrite дабы иметь отчётливое понимание как работают условия и правила, а не просто тупо их копировать/вставлять. Итак, начнём...

Модуль Apache mod_rewrite является очень мощным, но в то же время сложным, инструментом для манипуляции с URL перенаправлениями/преобразованиями/запретами. С помощью этого чудо-модуля можно выполнять практически любые URL преобразования/манипуляции на стороне сервера.

Обратите внимание, что для некоторых манипуляций с URL не требуется такой мощный и сложный (особо для начинающих) модуль как mod_rewrite. Для простых задач можно использовать mod_alias. Под словом "мощный" имеется ввиду не только широкие возможности по преобразованию URL-ов, но и повышенный расход ресурсов сервера в сравнении с другими модулями.

Регулярные выражения mod_rewrite

mod_rewrite использует Perl Compatible Regular Expression (PCRE - Perl совместимые регулярные выражения ). В этой статье, мы не будем подробно описывать использование регулярных выражений имхо этой теме посвящены целые тома книг и в одной статье нельзя охватить данную тематику.

  • Секреты регулярных выражений (regular expressions): Часть 1. Диалекты и возможности. Составление регулярных выражений

Главное, что нужно помнить, - это то, что в регулярных выражениях используются специальные символы (метасимволы ) и обычные символы (литералы ). Основными метасимволами являются \ / ^ $ . | ? * + () { } . Метасимволы всегда нужно экранировать обратным слэшем "\", - это относится к пробелу ("\ "), а также тому же обратному слэшу ("\\").

Нужно помнить, что mod_rewrite использует оригинальный PCRE (Perl совместимые регулярные выражения ), но с некоторыми дополнениями:

  • "!Условие " (несоответствие условию)
  • "<Условие " (лексически меньше условия)
  • ">Условие " (лексически больше условия)
  • "=Условие " (лексически равно условию)
  • "-d " (является ли каталогом)
  • "-f " (является ли обычным файлом)
  • "-s " (является ли обычным файлом с ненулевым размером)
  • "-l " (является ли символической ссылкой)
  • "-F " (проверка существования файла через подзапрос)
  • "-U " (проверка существования URL через подзапрос)

Порядок обработки правил mod_rewrite

Порядок обработки правил mod_rewrite является далеко не очевидным. Правила mod_rewrite составляются примерно в таком порядке:

RewriteEngine on RewriteBase / # uncomment this line if web-base dir not root # RewriteBase /you-web-base-dir RewriteCond %{что_сравнивать} с_чем_сравнивать [флаги] RewriteRule исходный_url целевой_url [флаги]

Теперь чуть подробнее:

  • RewriteEngine - должна быть одна;
  • RewriteBase - может пригодится при использовании в правилах относительных ссылок, но если относительные ссылки относятся к корню каталога, то данная директива может не использоваться, теоретически может использоваться многократно перед каждым из правил;
  • RewriteCond - условие, которое должно быть соблюдено перед выполнением правила, условий может быть несколько;
  • RewriteRule - собственно само правило, которое выполняется при соблюдении условия.

Порядок размещения правил.htaccess важен потому что механизм преобразований обрабатывает их в специальном порядке. Строчка за строчкой сначала просматриваются RewriteRule директивы и при соответствии URL шаблону (Pattern, исходный_url ) конкретного правила проверяются условия (RewriteCond директивы ) относящиеся к этому правилу. Условия (RewriteCond ) всегда должны быть перед правилами (RewriteRule )! На рис. ниже показан порядок обработки правил mod_rewrite.

Как видно, Текущий URL сначала сравнивается с Шаблон правила и при совпадении с шаблоном проверяет условия, если Текущий URL удовлетворяет условиям, то к нему применяется правило и Преобраз. URL идёт дальше на обработку если не указан флаг [L] (last ).

Флаг [L] нужно использовать для каждого правила, разумеется если дальнейшая трансформация URL не требуется.

Переменные mod_rewrite

В условиях (RewriteCond) и в правилах (RewriteRule) можно использовать переменные сервера.

1. HTTP headers (RqH - Request Header):

  • HTTP_USER_AGENT - содержит полную строку заголовка "User-Agent:";
  • HTTP_REFERER - адрес с которого пришел пользователь;
  • HTTP_COOKIE - доступ к списку COOKIE браузера;
  • HTTP_FORWARDED - содержит IP-адрес прокси-сервера или сервера балансировки нагрузки;
  • HTTP_HOST - адрес хоста/сервера, который запросил пользователь, например, example.com;
  • HTTP_PROXY_CONNECTION - содержит лексему соединения (connection-token ) "close" или "Keep-Alive", предназначен для согласования постоянных соединений между клиентом и сервером (аналог заголовка Connection);
  • HTTP_ACCEPT - заголовок согласования содержимого, которое поддерживает браузер/клиент пользователя, например " text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 " ("тип/подтип", через запятую, где тип – это тип содержимого, а подтип – это уточнение типа.). Если заголовок Accept содержит " Accept: */* " (*/*), то это означает, что клиент готов принять содержимое любого типа.

2. connection & request (соединение & запрос):

  • REMOTE_ADDR - IP-адрес клиента;
  • REMOTE_HOST - ДНС-имя IP-адреса клиента;
  • REMOTE_PORT - номер текущего порта клиента;
  • REMOTE_USER - содержит имя авторизированного (средствами сервера) пользователя;
  • REMOTE_IDENT - переменная будет установлена только если подключен модуль mod_ident и IdentityCheck установлено в "on", предназначена для работы с Ident протоколом https://ru.wikipedia.org/wiki/Ident;
  • REQUEST_METHOD - метод, которым был сделан запрос, GET|GET|HEAD и т.д.;
  • SCRIPT_FILENAME - полный путь к запрошенному файлу, например /var/www/public_html/script_name.php;
  • PATH_INFO - Содержит предоставленный пользователем путь, который содержится после имени скрипта, но до строки запроса (?). Например, если скрипт был запрошен по URL http://www.example.com/php/path_info.php/some/stuff?foo=bar, то переменная $_SERVER["PATH_INFO"] будет содержать /some/stuff.
  • QUERY_STRING - строка GET запроса, если запрошен адрес http://example.com/index.php?var=1&var=2, то QUERY_STRING будет содержать var=1&var=2;AUTH_TYPE - тип аутентификации, если выполнена HTTP-аутентификация, может быть Basic или Digest.

3. server internals (внутренние сервера):

  • DOCUMENT_ROOT - полный путь к домашнему каталогу пользователя, например /var/www/public_html/
  • SERVER_ADMIN - данные администратора сервера/виртуального_хоста, обычно адрес электронной почты;
  • SERVER_NAME - имя сервера, обычно из директивы ServerName;
  • SERVER_ADDR - IP-адрес сервера;
  • SERVER_PORT - порт сервера;
  • SERVER_PROTOCOL - версия используемого протокола, например HTTP/1.0 или HTTP/1.1;
  • SERVER_SOFTWARE - название/версия сервера.

4. date and time (системные, дата и время):

  • TIME_YEAR - год, 2014
  • TIME_MON - месяц, 05
  • TIME_DAY - день, 07
  • TIME_HOUR - час, 04 (24)
  • TIME_MIN - минуты, 38
  • TIME_SEC - секунды, 55
  • TIME_WDAY - день недели, 3 (среда)
  • TIME - в формате год-мес-день-час-мин-сек, например 20140514234534

5. specials (специальные):

  • API_VERSION - в формате "20051115:33"
  • THE_REQUEST - подробности GET/POST запроса, например "GET /index.html HTTP/1.1"
  • REQUEST_URI - относительный УРЛ запроса "/index.html"
  • REQUEST_FILENAME - полный локальный путь к файлу или скрипту в файловой системе, соответствующего запроса
  • IS_SUBREQ - если выполняется подзапрос, то переменная содержит true, в противном случае false
  • HTTPS - on/off, если используется/неиспользуется HTTPS

6. переменные результата выполнения:

  • $1 - $1, $2 и т.д. образуются при совпадении (шаблона1.*) (шаблона2.*) из RewriteRule
  • %1 - %1, %2 и т.д. образуются при совпадении (шаблона1.*) (шаблона2.*) из RewriteCond
  • Подробнее о HTTP заголовках можно почитать в спецификации rfc2616 Hypertext Transfer Protocol -- HTTP/1.1

Флаги mod_rewrite

Для управления поведением условий (RewriteCond ) и правил (RewriteRule ) в mod_rewrite используются флаги [флаги] .

  • [B] (escape backreferences ) - заставляет экранировать (кодировать) спец-символы, например взять правило " RewriteRule ^search/(.*)$ /search.php?term=$1 " в котором есть строка поиска, которая может содержать к примеру " x & y/z " и в результате будет возвращена строка " search.php?term=x & y/z ", что неявляется допустимым УРЛ и будет преобразовано браузером в " search.php?term=x%20&y%2Fz= ". С флагом [B] строка будет преобразована в " /search.php?term=x%20%26%20y%2Fz ". Для работы этого примера понадобится установить AllowEncodedSlashes в On ибо httpd по-умолчанию не позволяет кодировать слэши в УРЛ
  • [C] chain - объединить несколько правил в цепочку. Если первое правило цепочки не удовлетворяет условиям, тогда вся цепочка будет проигнорирована
  • cookie - устанавливает cookie в формате , параметры для secure и httponly устанавливаются как true|false
  • discardpathinfo - отбрасывает PATH_INFO в преобразованной ссылке, полезно использовать в случаях, когда PATH_INFO уже был добавлен в предыдущем преобразовании
  • [E] env - установить переменную или удалить её
  • [F] forbidden - возвращает ошибку 403
  • [G] gone - возвращает ошибку 410
  • [H] handler - принудительно устанавливает обработчик для определённых типов файлов, например правило " RewriteRule !\. - " заставит пропустить через PHP все файлы без расширения
  • [L] last - указывает, что правило является последним и процесс дальнейшего преобразования прекращается
  • [N] next - начинает процесс преобразования с первого по порядку правила, используйте этот флаг с осторожностью ибо он может привести к замкнутому циклу (т.н. петля)
  • nocase - отключает проверку регистра символов
  • noescape - mod_rewrite обычно применяет правила экранирования URI к результату преобразования. Спецсимволы (такие как "%", "$", ";", и так далее) будут экранированы их шестнадцатеричными (hexcode ) подстановками ("%25", "%24", и "%3B", соответственно). Этот флаг запрещает делать это
  • nosubreq - игнорировать подзапросы, выполнять правило только для настоящих/прямых запросов
  • [P] proxy - Apache выполняет подзапрос к указанной странице с использованием программного модуля mod_proxy, при этом клиент об этом подзапросе ничего не узнает. Произойдет ошибка если модуль mod_proxy не подключен
  • passthrough - остановить преобразование и передать полученную новую ссылку дальше
  • qsappend - добавляет исходные параметры запроса (query string ) к замене. Если в подстановку не включаются новые параметры запроса, то исходные параметры запроса будут добавлены автоматически. Если же новые параметры включаются в подстановку, то исходные параметры запроса будут утеряны если не указать флаг QSA
  • [R] redirect - возвращает браузеру команду на перенаправление (по-умолчанию код 302 - MOVED TEMPORARY ), код редиректа можно указать самостоятельно, например R=301 (код 301 - MOVED PERMANENTLY ), но в границах 300-399, в противном случае правило не будет обработано
  • [S] skip - пропускает следующее правило, если данное правило сработало. Можно указать количество правил, например: S=2
  • [T] type - принудительно устанавливает MIME-тип целевого файла. К примеру, " RewriteRule \.pl$ - ", это правило отобразит Perl скрипты в текстовом формате, а значит код скрипта будет выдан в браузер.

Более подробно о флагах читаем в оригинале:

Протоколы разрешённые в mod_rewrite

mod_rewrite будет определять подстановочный УРЛ как внешний если указаны один из протоколов:

  • ajp:// - Apache JServ Protocol
  • balancer:// - Apache Load Balancer
  • ftp:// - File Transfer Protocol
  • gopher:// - Gopher (protocol)
  • http:// - Hypertext Transfer Protocol
  • https:// - Hypertext Transfer Protocol Secure
  • ldap:// - Lightweight Directory Access Protocol
  • nntp:// - Network News Transfer Protocol
  • ldap: - Lightweight Directory Access Protocol
  • mailto: - The mailto URI scheme
  • news: - News Protocol

.htaccess и порядок размещения правил

В файле.htaccess, теоретически, директивы можно указывать как попало, за исключением директив относящихся к rewrite_module. Тем не менее лучше соблюдать некую последовательность:

  1. CORE директивы;
  2. Конфигурация модулей.

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

Примеры mod_rewrite правил

Запрет доступа с помощью mod_rewrite

RewriteCond %{TIME_HOUR}%{TIME_MIN} >2000 RewriteCond %{TIME_HOUR}%{TIME_MIN} <0700 RewriteRule .* - [ F ] # OR RewriteCond %{TIME_HOUR} >=20 RewriteCond %{TIME_HOUR} <07 RewriteRule .* - [ F ]

Это правило закроет доступ с 8-и вечера и до 7-и утра. Приведённый выше пример специально для любителей копи/пасты содержит преднамеренную ошибку в синтаксисе, HTTP 500 (ошибка сервера ), которая повлечёт запись в логе ошибок RewriteRule: bad flag delimiters . Переводится, как плохой разделитель флагов, - вместо [ F ] нужно использовать [F] , т.е. избегать пробелов и прочих разделителей, кроме запятой!

2. Наглухо запрещаем боту WBSearchBot трогать наш сайт:

RewriteCond %{USER_AGENT} WBSearchBot RewriteRule .* - [F] # Ещё как вариант, вместо ошибки 403 (FORBIDDEN), отдаём ошибку 404 (NOT FOUND) RewriteCond %{USER_AGENT} WBSearchBot RewriteRule .* -

Хотя, немного подправив правило, можно т.с. перевести стрелы на кого-то ещё, так сказать натравить бота на другой сайт, мол...ты что, офонарел!? Иди тренируйся, вон, на нём... :)) (из Х/Ф Операция «Ы» и другие приключения Шурика):

RewriteRule .* http://kremlin.ru

WBSearchBot (Mozilla/5.0 (compatible; WBSearchBot/1.1; +http://www.warebay.com/bot.html) ) довольно агрессивный бот и от него можно смело избавляться.

# BLOCK POST REQUEST FOR OLD HTTP PROTOCOL... RewriteCond %{THE_REQUEST} ^POST RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.|www1\.)?example.com RewriteCond %{THE_REQUEST} POST(.*)HTTP/(0 \.9|1 \.0) RewriteCond %{HTTP_USER_AGENT} ^$ RewriteRule .* -

В предыдущем примере код ответа 303 See Other указан не случайно, - дело в том, что если метод перенаправления (обычно GET ) отличается от метода запроса (например POST ), то в случае возврата кодов ответа 301-302 вместо автоматического редиректа в браузер будет выдана страница со ссылкой для ручного перехода по ней! В случае же с ответом 303 See Other перенаправление выполняется автоматически методом GET независимо от метода запроса.

4. Hotlink protection - запрещаем отображение наших изображений с других сайтов:

# # HOTLINK PROTECT... # http://www.htaccesstools.com/hotlink-protection/ RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.|www1\.)?сайт RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yandex.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?subscribe.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?feedburner.com RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?mail.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?poisk.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?rambler.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?nigma.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?ask.com RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?qip.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?ukr.net RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?conduit.com RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?tut.by RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?bing.com RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?webalta.ru RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yahoo.com RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?conduit.com RewriteRule \.(jpg|jpeg|png|gif) https://dl.dropboxusercontent.com/u/52572427 / \ images/wrs-hotlink-deny .jpg

  • RewriteRule ^ - RewriteCond %{HTTPS} on RewriteRule ^ - # To redirect all users to access the site WITH the "www." prefix, # (http://example.com/... will be redirected to http://www.example.com/...) # uncomment the following: RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} !^www\. RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} # OR # REDIRECT FOR /DOCS Redirect permanent /docs http://docs.example.com

    2. Перенаправляем наши RSS/ATOM ленты на FeedBurner

    # REDIRECT blog RSS/ATOM to FeedBurner... RewriteCond %{HTTP_USER_AGENT} !^.*(FeedBurner|FeedValidator) RewriteCond %{QUERY_STRING} ^option=com_content&view=featured&Itemid=()+&format=feed RewriteRule index.php http://feeds.feedburner.com/remote-shaman-blog? # # REDIRECT forum RSS/ATOM to FeedBurner... # if HTTP_USER_AGENT not FeedBurner or FeedValidator RewriteCond %{HTTP_USER_AGENT} !^.*(FeedBurner|FeedValidator) # forum/topics/mode-topics?format=feed # forum/topics/mode-latest?format=feed # forum/topics/posts?format=feed # forum/recent?format=feed RewriteCond %{QUERY_STRING} ^format=feed$ RewriteRule forum/(*/)?()+ http://feeds.feedburner.com/remote-shaman-forum?

    Обратите внимание, что в конце каждой ссылки в правилах (RewriteRule ) стоит символ "?", - он требуется для того, чтобы в конец ссылки, по которой будет перенаправлен запрос, не добавлялись параметры QUERY_STRING! если не указать символ "?", то в итоге перенаправление будет по адресу http://feeds.feedburner.com/remote-shaman-blog?option=com_content&view=featured&Itemid=... и http://feeds.feedburner.com/remote-shaman-forum?format=feed соответственно.

    Итоги

    mod_rewrite является мощным инструментом и с его помощью можно творить чудеса, - это факт! В этой статье не так много примеров, но их валом в сети, а вот материала о том, что к чем и почему в стиле как для полных идиотов практически не встретить. Возможно папизже позднее на эту страницу будут добавлены ещё примеры использования mod_rewrite.

    В этой статье я постарался максимально доходчиво изложить (надеюсь мне это удалось) базовые принципы работы чудо-модуля mod_rewrite, в стиле как для полных идиотов (в хорошем смысле слова;), имхо на собственном опыте знаю как оно иногда тяжко осваивать что-то с ноля и когда маны и принципы этого что-то описаны общими туманными фразами и глубоко техническими терминами.

    При написании данного материала использовались только оригинальные маны с сайта httpd.apache.org (никакой копи/пасты). Если я что-то пропустил аль где-то протупил, тогда обязательно напишите об этом в комментариях.

Что такое mod_rewrite mod_rewrite — это модуль веб сервера Apache , использующийся для преобразования URL адресов. Под преобразованием следует понимать фактически любые действия с URL. Это очень мощное и в то же время гибкое средство, имеющее очень широкие возможности. Модуль позволяет производить практически любые типы преобразований. С помощью mod_rewrite можно настраивать редиректы, изменять URL адреса, блокировать доступ и т.д. Он поддерживает неограниченное количество правил преобразования, регулярные выражения , обратные связи с группированными частями шаблона, разные источники информации для преобразований (переменные сервера, HTTP заголовки, время и т.д.). За счет такого набора возможностей, достигается высокая функциональность и гибкость. По умолчанию этот модуль выключен, для того что бы его включить, в.htaccess необходимо добавить следующие директивы:

RewriteEngine On
RewriteBase /

RewriteEngine On — директива включает модуль.
RewriteBase — указывает путь от корня сайта до файла.htaccess. Если.htaccess лежит в корне, то указывать этот параметр нужно как в примере, если во внутреннем каталоге, то указываем путь к этому каталогу, например /images.

Принцип работы модуля mod_rewrite

Работа модуля основана на наборе правил и условий, согласно которым производится преобразование. При получении запроса, Apache передает в mod_rewrite путь к файлу начиная от того места, где находится файл.htaccess, остальная часть пути обрезается. Если поступил запрос http://some-url.com/cat/cat2/file.html, а.htaccess лежит в корне, то в mod_rewrite попадет cat/cat2/file.html (без слеша в начале). Если.htaccess лежите в директории /cat, то в mod_rewrite попадет cat2/file.html. Далее mod_rewrite анализирует правила в.htaccess и действует согласно этих правил. Стоит знать, что mod_rewrite работает не со ссылками и не с URL адресами, а с обычными строками. То есть адрес, который нужно преобразовать, передается mod_rewrite как обычная строка, и эту строку можно преобразовать как угодно. Для построения правил используются две директивы, RewriteCond и RewriteRule (более детально эти директивы описаны ниже).​
RewriteCond — в этой директиве определяются условия, при которых сработает правило преобразования RewriteRule. Если условие в RewriteCond выполнено, выполняем правило в RewriteRule. Таких условий перед правилом RewriteRule может быть неограниченное количество. RewriteCond не является обязательной директивой для создания правила преобразования и может отсутствовать.
RewriteRule — здесь уже указывается само правило для преобразования, которое для конкретного преобразования должно быть единственным.
Пример, как это выглядит в.htaccess:

RewriteCond %{REQUEST_URI} !.(ico|css|js|txt)$
RewriteCond %{REQUEST_FILENAME} !^/admin

Несмотря на то, что директива RewriteCond стоит выше, чем правило RewriteRule, mod_rewrite сначала проверяет строку на соответствие с шаблоном в RewriteRule, и если строка совпадает с шаблоном, он смотрит на указанные выше условия в RewriteCond. Если условия тоже совпадают, происходит преобразование согласно правилу RewriteRule. Рассмотрим подробней синтаксис и предназначение директив RewriteCond и RewriteRule.

RewriteCond

Как уже писалось выше, в этой директиве указываются условия, при которых правило в директиве RewriteRule будет выполнено. Эта директива выглядит так:

RewriteCond [строка_для_сравнения] [условие] [флаг]
RewriteCond %{REQUEST_URI} !.(ico|css|js|txt)$

В этом примере правило условие будет выполнено, если запрос пользователя не содержит расширение ​ico,css,js или txt.
Строка для сравнения — кроме обычного текста может содержать регулярное выражение, обратные RewriteCond и RewriteRule связи и переменные сервера. На практике здесь используются переменные сервера и иногда регулярные выражения.
Условие — собственно это то, с чем сравнивается строка для сравнения. Может содержать текст, регулярные выражения и специальные символы:

  • "-d" — проверяет правильность пути (его существование) и является ли этот путь, путем к каталогу.
  • "-f" — проверяет правильность пути (его существование) и является ли этот путь, путем к обычному файлу.
  • "-s" — то ж, что и -f, но дополнительно проверяет, что размер файла больше 0 (ноля).
  • "-l" — проверяет правильность пути (его существование) и является ли этот путь символической ссылкой.
  • "-F" — проверяет через внутренний подзапрос, является ли сравниваемая строка реально существующим файлом, при этом используются все существующие списки контроля доступа сервера. Это негативно сказывается на производительности, стоит использовать осторожно.
  • "-U" — проверяет через внутренний подзапрос, является ли сравниваемая строка реально URL адресом, при этом используются все существующие списки контроля доступа сервера. Это негативно сказывается на производительности, стоит использовать осторожно.
Дополнительно, перед условием, допускается использование логических символов:
  • "!" — инвертирование значения, указывает на то, что сравниваемая строка должна не соответствовать шаблону условия.
  • "<" — лексически меньше. Например символ "a" лексически меньше символа "b", "a" < "b".
  • ">" — лексически больше.
  • "=" — равенство, используется по умолчанию.

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

  • — регистронезависимый, то есть регистр (A-Z или a-z) в строке для сравнения или в условии не имеет значения.
  • — логическое ИЛИ. Используется, когда перед директивой RewriteRule находится несколько директив RewriteCond и правило в RewriteRule должно быть выполнено при совпадении одного из RewriteCond.​ Если флаг OR не указан, RewriteRule сработает только при соответствии всех директив RewriteCond.

RewriteRule

​В RewriteRule указывается правило для преобразования, то, как мы хотим изменить URL. По факту эта директива также содержит условие, при совпадении которого, будет произведено преобразование. Это шаблон, с которым сверяется полученная mod_rewrite строка. Стоит отметить, что если ничего подставлять не нужно, а такие случаи иногда происходят, в новом значении необходимо указать прочерк "-" . Схематически правило RewriteRule выглядит следующим образом:

RewriteRule [шаблон] [новое_значение] [флаг]
RewriteRule ^(.*)$ /index.php [L]

Шаблон — то, с чем будет сравниваться исходная строка. Исходная строка необязательно является той, которую запросил пользователь. Она могла быть ранее изменена другими правилами RewriteRule. Может содержать обычный текст, регулярные выражение и обратные RewriteCond и RewriteRule связи. Исходная строка, это путь от файла.htaccess до файла, доменного имени там нет.
Новое значение — это значение, на которое будет изменена исходная строка после преобразования. Может содержать обычный текст, регулярные выражение, обратные RewriteCond и RewriteRule связи и переменные сервера.
Флаг — ​необязательный параметр, в котором указываются дополнительные опции, (через запятую, если их несколько). Указывается в конце правила в квадратных скобках .

  • — редирект. code — это код ответа браузеру, по умолчанию используется 302 (временно перемещен), поэтому для постоянного редиректа используйте код 301.
  • [F] — запрет доступа к URL, Forbidden . Сервер возвращает браузеру ошибку с кодом 403.
  • [G] — возвращает ошибку 410, URL не существует.
  • [P] — Apache выполняет подзапрос к указанному адресу с использование другого модуля Apache mod_proxy.
  • [L] — последнее правило. Говорит о том, что на этом месте следует остановить преобразование URL.
  • [N] — процесс преобразований будет запущен опять, начиная с самого первого правила. Будет использована уже модифицированная ранее строка.
  • [C] — связь со следующим правилом, создается цепочка правил. Если правило не соответствует, все последующие правила в цепочке пропускаются.
  • — срабатывают правила только для запросов, подзапросы игнорируются.
  • [T] — принудительно указать MIME-тип файла.
  • — не учитывать регистр символов.
  • — дополнять строку запроса, а не заменять ее. Флаг стоит использовать при работе с GET параметрами в переменной %{QUERY_STRING}, что бы их не терять. Если это флаг не указан, данные в %{QUERY_STRING} будут полностью заменены параметрами из RewriteRule. Если флаг указан, новые параметры будут добавлены в начало %{QUERY_STRING}.
  • — запрещает преобразование специальных символов в их hex эквиваленты.
  • — останавливает преобразование и передает строку дальше для обработки другими директивами (Alias, ScriptAlias, Redirect и т.д.).
  • [S] — пропустить следующее правило. Есть возможность указать несколько правил в формате S=N, где N это количество правил.
  • — установить переменную окружения, где VAR это имя переменной, а VAL ее значение.Значение может быть обратной RewriteCond и RewriteRule связью или текстом.
  • — установить cookie в браузер. NAME — имя куки, VAL — значение, domain — имя домена, lifetime — время жизни (опционально), path — путь, для которого эта кука валидна, по умолчанию равна "/", secure — если установлено 1 или true, куки будут действительны только при https (безопасном) соединении, httponly — если установлено 1 или true, куки будут доступны для JavaScript.

Обратные связи RewriteCond и RewriteRule

Обратные связи, это возможность использования группы символов (заключенные в скобки "()" ) для их последующей подстановки. Например в скобках можно указать определенное регулярное выражение и таким образом охватить большое количество адресов.
$N — позволяет использовать группу символов из шаблона директивы RewriteRule.
%N — позволяет использовать группу символов из шаблона директивы RewriteCond.
Вместо символ "N" в обоих случаях используется число от 1 до 9.
На практике это выглядит следующим образом. Рассмотрим простой пример.
Есть адрес с определенной вложенность, http://some-url.com/cat1/cat2/cat3/cat4/page.html. Есть желание сделать страницу http://some-url.com/cat1/cat2/cat3/cat4/page.html доступной по адресу http://some-url.com/page.html, но кроме page.html, там есть куча других файлов с расширением html, которые также должны быть доступны по новому адресу. Это решается очень просто:

RewriteRule ^cat1/cat2/cat3/cat4/(.*).html$ $1.html

Теперь, при обращении к по адресу http://some-url.com/page.html, будет отображаться информация с адреса http://some-url.com/cat1/cat2/cat3/cat4/page.html и так со всеми адресами вида http://some-url.com/*.html. Точно также, с использованием "%N", можно подставлять группы символов из шаблона для RewriteCond. В данном примере, вместо $1 подставляется группа символов в скобках из шаблона.

Переменные сервера

​Переменные сервера могут содержать много полезной информации, которую можно и нужно использовать для построения правил. Ниже приведен список этих переменных:
HTTP_USER_AGENT — дает информацию о браузере и ОС пользователя. При посещении сайта пользователь, передается User Agent, по факту это обозначает ПО, с помощью которого производится доступ к сайту.
HTTP_REFERER — адрес страницы, с которой был осуществлен переход на сайт.
HTTP_COOKIE — список cookie, которые передает браузер.
HTTP_FORWARDED — адрес страницы, с который был переход. Большой разницы с HTTP_REFERER я не заметил.
HTTP_HOST — адрес сервера (сайта).
HTTP_ACCEPT — это пожелания клиента, по типу документа, который он хочет получить. На деле это выглядит так, браузер отправляет на сервер в http заголовке типы файлов, которые он хочет получить (обычно это относится к изображениям и другим медиа файлам), то есть сообщает, какой тип файла он может обработать.
REMOTE_ADDR — IP адрес посетителя.
REMOTE_HOST — адрес (хост) пользователя, который отдается командой "host" по IP адресу.
REMOTE_IDENT — имя пользователя в формате имя.хост.
REMOTE_USER — то же самое что и REMOTE_IDENT, но не содержит хост пользователя.
​REQUEST_METHOD — тип запроса к сайту (GET, POST, HEAD).
SCRIPT_FILENAME — полный путь к запрошенному файлу или адресу.
PATH_INFO — данные, которые передавались в скрипт.
QUERY_STRING — строка, переданная как запрос в CGI скрипт, GET параметры.
AUTH_TYPE — тип идентификации пользователя.
DOCUMENT_ROOT — путь к корневой директории сервера.
SERVER_ADMIN — email администратора сервера.
SERVER_NAME — адрес (имя) сервера, отдаваемый командой host.
SERVER_ADDR — IP вашего сайта.
SERVER_PORT — порт, га котором работает Apache.
SERVER_PROTOCOL — версия http протокола.
SERVER_SOFTWARE — используемая версия Apache.
TIME_YEAR, TIME_MON, TIME_DAY, TIME_HOUR, TIME_MIN, TIME_SEC, TIME_WDAY, TIME — время.
API_VERSION —версия API модуля Apache.
THE_REQUEST — строка содержит весь http запрос, отправленный браузером на сервер (GET /index.html HTTP/1.1). Здесь не включены дополнительные заголовки.
REQUEST_URI — адрес, запрошенный в http заголовке.
REQUEST_FILENAME — полный путь к запрошенному файлу, по факту содержит те же данные, что и SCRIPT_FILENAME.
IS_SUBREQ — проверка на подзапрос. Если да — ответ true, если нет — ответ false.
Список переменных вашего сервера, вы можете легко узнать поместив в корень сайта php файл с кодом:

Набрав адрес этого файла в браузере, внизу страницы вы получите информацию о переменных сервера.

Htaccess - это дополнительный конфигурационный файл Apache, который позволяет настраивать работу веб-сервера для каждой отдельной директории, не влияя на глобальные настройки Apache. Локальная аналогия httpd.conf . Обычно он отвечает за редиректы и управление доступом к директориям.

Название начинается с точки. Можно сказать, это файл без названия с расширением htaccess.

Настройки.htaccess действуют на каталог, в котором он расположен, и на все дочерние каталоги. Создайте файл и поместите в нужную вам директорию. Например, в корень проекта.

Теперь нужно его наполнить. Посмотрим, что вообще умеет.htaccess, но для начала изучим пример простейшего редиректа.

mod_rewrite и редиректы

Убедитесь, что в конфигурационном файле Apache httpd.conf активирован mod_rewrite . То есть, раскомментирована соответствующая строка:

LoadModule rewrite_module modules/mod_rewrite.so

Или, если не хотите открывать в текстовом редакторе файл, можно воспользоваться командой в терминале:

Sudo a2enmod rewrite

mod_rewrite - это модуль Apache, предназначенный для преобразования URL-ов. Рассмотрим на примере, как он работает. Допустим, пользователь вводит следующий адрес:

C помощью mod_rewrite можно отправить содержание с другого URL, например такого:

Http://www.example.com/public/src/view/page.html

Зачем это нам? Легко догадаться, что писать полный путь до страницы долго и просто неудобно. Посетителям сайта не нужно думать о внутренней структуре сайта - им важно максимально быстро попасть на искомую страницу.

В адресной строке пользователь будет всё также видеть введенное им:

Http://www.example.com/page.html

Это пример самого простого редиректа.

Сразу к практике

Разберем конфигурационный файл, используемый в одном из наших проектов. Так мы будем понимать, какую строчку править в случае возникновения проблем.

Php_value short_open_tag 1 php_value upload_max_filesize 10M php_value post_max_size 10M RewriteEngine On RewriteBase / RewriteRule ^(application|modules|system) - RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule .* index.php/$0

  • php_value установка строковых и числовых значений
  • php_flag устанавливает логические значения (да/нет)

Общий синтаксис директив

Php_value/php_flag имя_директивы_php flag/value

Директива short_open_tag разрешает использование короткого синтаксиса для оформления PHP-кода:

Php_value short_open_tag 1

upload_max_filesize определяет максимальный размер загружаемого файла.

Php_value upload_max_filesize 10M

А post_max_size устанавливает максимально допустимый размер данных, отправляемых методом POST.

Php_value post_max_size 10M

RewriteEngine

Включает/выключает механизм mod_rewrite .

RewriteEngine On

RewriteRule

RewriteRule просто преобразовывает строку в соответствии с регулярными выражениями.

Синтаксис: RewriteRule regular_expression

# На входе RewriteRule "index.php" RewriteRule ^index.php main.php [R] # На выходе: "index.php" -> "main.php"

Мы преобразовали index.php в main.php и выполнили редирект.

Важно : RewriteRule обычно принимает два аргумента: что нужно заменить и на что нужно заменить. Если нам не нужно выполнять замену то можно записать в виде:

Символ «-» означает «не преобразовывать»

RewriteBase

После всех RewriteRule, в силу вступает RewriteBase. Если получившийся после преобразований запрос является относительным и отличается от исходного, RewriteBase восстановит его, сделав абсолютным. RewriteBase просто допишет себя к запросу слева. Потому что значение RewriteBase - путь от корня сайта до.htaccess. В нашем случае.htaccess лежит прямо в корне, поэтому:

Синтаксис : RewriteBase URL-path-from-.htaccess-file-to-site-root

Например:

# .htaccess находится в /dir/ # Путь от корня сайта до.htaccess /dir/ RewriteBase /dir/ # Запрос http://example.com/dir/logo.gif # На вход RewriteRule попадает "logo.gif" RewriteRule ^logo.gif$ logo-orange.gif # После RewriteRule: "logo.gif" -> "logo-orange.gif" # После RewriteBase: "logo-orange.gif" -> "/dir/logo-orange.gif"

Regular expressions

Регулярные выражения, которые вам могут встретиться в.htaccess.

Символ Значение Пример
. Один любой символ c.t это cat , cot , cut , и т. д.
+ Один или несколько одинаковых символов a+ это a , aa , aaa , и т. д.
* Ноль или несколько одинаковых символов a* работает также как и a+ но в случае a* условию удовлетворит и пустая строка
? Совпадение опционально colou?r подойдет как color , так и colour .
^ Символ, с которого начинается строка ^a соответствует строка, которая начинается с a
$ Символ, которым заканчивается строка a$ соответствует строка, которая заканчивается a .
() Находит и запоминает соответствие группы символов.

Также может быть использовано для Back-Reference (смотри пример)

(ab)+ удовлетворит ababab

Back-Reference example:

RewriteRule ^/(+) /(.*) $ /home?page=$1 &id=$2

/album/123 → /home?page=album &id=123

Один из возможных символов ct подойдет cut , cot или cat .

Больше regular expressions

Флаги

Синтаксис : RewriteRule regular_expression [флаг1,флаг2,флаг3]

Флаг Описание
[F] Forbidden - возвращает ошибку 403 Forbidden (запрещено).
[L] Last - остановить процесс преобразования на этом месте и не применять больше никаких правил преобразований.
Query String Append - этот флаг указывает механизму преобразований на добавление, а не замену , строки запроса из URL к существующей, в строке подстановки.
PassThrough - останавливает процесс преобразования и передает полученную новую ссылку дальше по цепочке.
[R] Redirect - останавливает процесс преобразования и возвращает результат браузеру клиента как редирект на новую страницу.
[S] Skip - пропускает следующее правило, если текущее правило сработало. Можно указать количество последующих игнорируемых правил .
Похожие статьи