Синтаксис htaccess, полное руководство

Дмитрий Лео 18:00 -- 01.12.2015
синтаксис htaccess примеры редиректов

Метасимволы

Пример:

RewriteRule ^old(.*)$ /new.php [L,R=301]

Используются для задания групп символов или «меток» в шаблоне. Например, метки начала или конца строки.

\ «Экранирующий» слеш. Следующий символ после него считается обычным, а не спецсимволом. Символ \ ставится перед спецсимволами, если они нужны в своем первозданном виде. Например, выражению "jpe\+g" соответствует только одна строка "jpe+g".
^ Символ ^ обозначает начало строки.
$ Символ $ обозначает конец строки.
! Символ отрицания.
. Символ . обозначает любой символ (кроме символа конца строки).
.* Заменяет абсолютно любой набор символов
".*" Найдёт все подстроки между кавычками
| Символ | обозначает альтернативу. Например, выражения "A|B" и "(ABC|DEF)" означают "A или B" и "ABC или DEF" соответственно.
() Круглые скобки () используются для выделения групп символов.
[...] Квадратные скобки [] используются для перечисления допустимых символов. Например, выражение "[abc]" равносильно выражению "a|b|c", но вариант с квадратными скобками обычно является более оптимальным по быстродействию. Внутри скобок можно использовать диапазоны: например, выражение "[0-9]" равносильно выражению "[0123456789]".
[^...] Инвертированный класс символов. Если символы внутри квадратных скобок начинаются с символа ^, это означает любой символ, кроме перечисленных в скобках. Например, выражение "[^0-9]+" означает строку из любых символов, кроме цифр.
[...]* Например, [abc]* — команда найдёт идущие подряд символы из заданного набора. [^abc]* — с точностью до наоборот.
\w Буква, цифра или подчёркивание _.
\d Заменяет любую цифру.
\D Заменяет любой символ, но не цифру.
[0-9] Заменяет любую цифру.
[a-z] Любая буква от a до z (весь латинский набор символов) в нижнем регистре.
[A-Z] Любая буква от A до Z в ВЕРХНЕМ регистре.
[a-zA-Z] Любая буква от a до Z в любом регистре. [a-Z] — то же самое.

Дополнение. Все, что расположено после символа '#', считается комментарием.

Модификаторы

Пример:

RewriteRule (.*) $1? [R=301,L]

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

? Символ повторяется 0 или 1 раз. Символ ? ставится после символа (или группы символов), который может как присутствовать, так и отсутствовать. Например, выражению "jpe?g" подойдет и строка "jpg", и строка "jpeg".
* Повторяется от 0 до 65536 раз. Символ * ставится после символа (или группы символов), который может отсутствовать или присутствовать неограниченное число раз подряд. Например, выражению "jpe*g" подойдут строки "jpg", "jpeg" и "jpeeeeeeg".
+ Повторяется от 1 до 65536 раз. Символ + действует аналогично символу * с той лишь разницей, что предшествующий ему символ обязательно должен присутствовать хотя бы один раз. Например, выражению "jpe+g" подойдут строки "jpeg" и "jpeeeeg", но не "jpg".
{n} Точно n раз.
{n,} От n до 65536 раз включительно.
{n,m} От n до m раз включительно.

Примеры использования:

^stena

Любые строки, начинающиеся со слова stena. Строка, начинающаяся со слова dom-stena не удовлетворит критерию.

stena$

Любые строки, заканчивающиеся набором символов stena. Строка, заканчивающаяся на stena-dom под выбор не попадёт.

.*

Любой символ повторяется любое количество раз. Под критерий попадут все строки.

^(.*)$

Выбрать любую строку и сохранить её как переменную $1 для дальнейшего использования.

[0-9]{1,6}$

Выбрать все строки, оканчивающиеся от 1 до 6 цифами из диапазона от 0 до 9.

^(.+)/(.+)$

Разбить строку на две части: до слэша и после, части строки будут доступны по переменным $1 и $2.

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

Пример использования:

RewriteRule ^(.+)/(.+)$ /?a=$1&b=$2 [R=301,L]

http://www.site.com/1/2/3/4/5 →
http://www.site.com/?a=1/2/3/4&b=5

Флаги

Пример:

RewriteRule ^htaccess-fake$ - [G]
RewriteRule (.*) page.php\?%1 [L]

Флаги - дополнительные опции. Перечисляются в квадратных скобках через запятую, скажем [NC] или [R=301,L].

R (redirect) останавливает процесс преобразования и возвращает результат браузеру клиента как редирект на данную страницу (302, MOVED TEMPORARY). С данным флагом можно указать другой код результата, например "R=301" возвратит редирект с кодом 301 (MOVED PERMANENTLY).
F (forbidden) возвращает ошибку 403 (FORBIDDEN).
G (gone) возвращает ошибку 410 (GONE).
P (proxy) - по этому флагу Apache выполняет подзапрос (sub-request) к указанной странице с использованием программного модуля mod_proxy, при этом пользователь ничего не узнает об этом подзапросе. Если модуль mod_proxy не входит в состав вашей сборки Apache, то применение данного флага вызовет ошибку.
L (last) останавливает процесс преобразования, и текущая ссылка считается окончательной.
N (next) запускает процесс преобразования с первого по порядку правила.
C (chain) объединяет несколько правил в цепочку. Если первое правило цепочки «не срабатывает», то вся цепочка игнорируется.
NS (nosubreq) разрешает «срабатывание» правила только для настоящих запросов, игнорируя подзапросы (подзапрос может быть вызван, например, включением файла при помощи директивы SSI).
NC (nocase) отключает проверку регистра символов при срабатывании правила.
QSA (qsappend) добавляет исходные параметры запроса (query string) к замене. Если замена не включает в себя новые параметры запроса, то исходные параметры запроса добавляются автоматически. Если же включает, то без флага QSA исходные параметры запроса будут утеряны.
PT (passthrough) останавливает процесс преобразования и передает полученную новую ссылку дальше «по цепочке», чтобы над ней могли «поработать» директивы Alias, ScriptAlias, Redirect и им подобные (тогда как при флаге L новая ссылка считается окончательной и не подлежит дальнейшей обработке).
S (skip) пропускает следующее правило, если данное правило «сработало». Можно пропускать несколько правил, если указать их количество, например: «S=3».
E (env) устанавливает переменную окружения, например: «E=переменная:значение».

Проверки

Пример:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.php

В условиях могут быть использованы следующие проверки:

1. Вы можете предварить шаблон символом '!', чтобы обозначить несоответствие шаблону.

2. Можно выполнить лексикографическое сравнение строк:

Лексикографически меньше
Лексикографически больше
Равенство
Лексикографически меньше или равно
Лексикографически больше или равно

3. Сравнение, как целых чисел:

Численно равно
Численно больше или равно
Численно больше
Численно меньше или равно. Во избежание путаницы с заглавной буквой -l используйте -L
Численно меньше. Во избежание путаницы с заглавной буквой -l используйте -L

4. Тест на различные атрибуты файлов:

Является ли директорией.
Является ли обычным файлом.
Существует ли файл.
Является ли символической ссылкой.
Является ли символической ссылкой. Аналог флага -l.
Является ли обычным файлом ненулевого размера
Существует ли заданный URL
Является ли файл исполняемым.

5. Все эти проверки также могут быть предварены префиксом восклицательный знак ('!') для инвертирования их значения.

Переменные

Пример:

RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
HTTP_USER_AGENT Содержит информацию о типе и версии браузера и операционной системы посетителя.
HTTP_REFERER Приводится адрес страницы, с которой посетитель пришёл на данную страницу.
HTTP_COOKIE Список COOKIE передаваемых браузером
HTTP_FORWARDED Страница непосредственно с которой перешел пользователь
HTTP_HOST Адрес сервера, например host.com
HTTP_ACCEPT Описываются предпочтения клиента относительно типа документа.
REMOTE_ADDR IP-адрес посетителя.
REMOTE_HOST Адрес посетителя в нормальной форме — например, rt99.net.com
REMOTE_IDENT Имя удаленного пользователя. Имеет формат имя.хост, например, kondr.www.rtt99.net.com
REMOTE_USER То-же, что и REMOTE_IDENT, но содержит только имя. Пример: kondr
REQUEST_METHOD Позволяет определить тип запроса (GET или POST). Должен обязательно анализироваться, т.к. определяет дальнейший способ обработки информации
SCRIPT_FILENAME Полный путь к вебстранице на сервере.
PATH_INFO Содержит в себе все, что передавалось в скрипт.
QUERY_STRING Содержит строчку, переданную в качестве запроса при вызове CGI скрипта.
AUTH_TYPE Используется для идентификации пользователя
DOCUMENT_ROOT Cодержит путь к корневой директории сервера.
SERVER_ADMIN Почтовый адрес владельца сервера, указанный при установке.
SERVER_NAME Адрес сервера, типа kondr.host.com
SERVER_ADDR IP-адрес вашего сайта.
SERVER_PORT Порт на котором работает Apache.
 SERVER_PROTOCOL  Версия HTTP протокола.
 SERVER_SOFTWARE  Название сервера, например, Apache/1.3.2 (Unix)
TIME_YEAR
TIME_MON
TIME_DAY
TIME_HOUR
TIME_MIN
TIME_SEC
TIME_WDAY
TIME
Переменные предназначены для работы со временем в разных форматах.
API_VERSION Это версия API модуля Apache (внутренний интерфейс между сервером и модулем) в текущей сборке сервера, что определено в include/ap_mmn.h.
THE_REQUEST Полная строка HTTP запроса отправленная браузером серверу (т.е., «GET /index.html HTTP/1.1»). Она не включает какие-либо дополнительные заголовки отправляемые браузером.
REQUEST_URI Ресурс, запрошенный в строке HTTP запроса.
REQUEST_FILENAME Полный путь в файловой системе сервера к файлу или скрипту соответствующим этому запросу.
IS_SUBREQ Будет содержать текст «true» если запрос выполняется в текущий момент как подзапрос, «false» в другом случае. Подзапросы могут быть сгенерированы модулями которым нужно иметь дело с дополнительными файлами или URI для того чтобы выполнить собственные задачи.

Логика исполнения правила (RewriteRule)

Исполнение же правила подразумевает следующие действия: первым делом механизм преобразования выполняет поиск дополнительных условий для этого правила (RewriteCond директивы). Помним, что по историческим причинам дополнительные условия находятся перед правилами(RewriteRule). Если дополнительные условия для этого правила отсутствуют, то механизм преобразований тупо выполняет указанное в правиле преобразование текущего URL и переходит к следующему правилу. Однако если для исполняемого правила (RewriteRule) существуют дополнительные условия, указанные ПЕРЕД НИМ в директивах RewriteCond, то запускается внутренний цикл для обработки этих дополнительных условий в том порядке, в котором они перечислены, сверху вниз.

Если из имеющихся для правила дополнительных условий хотя бы одно условие НЕ выполняется это приводит к остановке запущенного процесса исполнения правила, и преобразование над URL, заданное в правиле, НЕ выполняется. Что бы запущенное на исполнение правило выполнилось до конца и изменило URL, необходимо, что бы выполнились ВСЕ дополнительные условия, указанные в директивах RewriteCond перед этим правилом!

Тут нужно дополнительно пояснить, что директивы RewriteCond по умолчанию объединены между собой оператором AND в одно составное условие. Просто этот оператор(AND) не записывается по умолчанию. От сюда и такая логика, что нужно, что бы все дополнительные условия были истинными (т.к. они объедены через AND) для удачного завершения преобразования URL. Однако директивы RewriteCond можно объединить условием OR при помощи флагов (см. синтаксис директивы). Про это нужно помнить, при задании дополнительных условий.

Синтаксис директивы RewriteRule:

RewriteRule Шаблон Подстановка [Флаги]

Пример:

RewriteRule ^(.*)$ index.php?/$1 [L,QSA]

Где:

1.    RewriteRule  – это название директивы – правила.
2.    Шаблон - это как раз то условие, выполнение которого запускает исполнение правила. Это условие - Шаблон представляет собой perl совместимое регулярное выражение, которое применяется к текущему URL.
3.    Подстановка – это как раз тот алгоритм изменения URL, т.е. правило изменения(преобразования) URL.
4.    [Флаги] подстановки - Третий аргумент директивы RewriteRule. Флаги - это разделённый запятыми, заглавные спец символы, заключенные в квадратные скобки. Флаги дополняют преобразование URL.

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

Теперь давайте разберем пример правила RewriteRule:

RewriteRule ^(.*)$ index.php?/$1 [L,QSA]

1.    ^(.*)$ - это Шаблон, регулярное выражение которое применится к текущему URL. Кто знаком с регулярными выражении, сможет прочитать его так: искать в текущей строке URL от начала строки(знак ^) до конца строки(знак $) любой символ (знак .) в количестве от нуля до бесконечности (знак *). Так как в этом РВ есть скобки(), то та часть URL которая будет соответствовать условию в скобках будет захвачена в переменную подстановки $1, которую мы потом сможем использовать в Подстановке или в СравниваемаяСтрока(это в директиве RewriteCond, о ней ниже).
2.     index.php?/$1 - Подстановка – это собственно и есть правило преобразования URL. Запись index.php?/$1 означает, что строка нового, преобразованного URL должна быть составлена из двух частей, где первая часть строки это постоянное значениеindex.php?/ а вторая часть строки это значение из переменной подстановки $1. Тут мы вспоминаем что в $1 храниться та часть URL которая соответствовала РВ в скобах из параметра Шаблон. В итоге мы получаем преобразованный URL вида index.php?/URL_по которому обратились. По другому сказать так, что для всех запросов выполняется внутренне перенаправление на файл index.php.
3.    [L,QSA] – флаги, где 'last|L' - последнее правило что означает - остановить процесс преобразования на этом месте и не применять больше никаких следующих правил преобразований для URL. 'qsappend|QSA' - добавлять строку запроса - Этот флаг указывает механизму преобразований на добавление, а не замену, строки запроса из URL к существующей, в строке Подстановка. Используйте это когда вы хотите добавлять дополнительные данные в строку запроса с помощью директив преобразований.

Шпаргалки

Шпаргалка по mod_rewrite

Шпаргалка по mod_rewrite содержит список флагов для директив RewriteRule и RewriteCond, список серверных переменных, руководство по регулярным выражениям и несколько примеров общих правил.

Шпаргалка по регулярным выражениям

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

Заключение

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

Также не забывайте оборачивать весь блок правил для  mod_rewrite в тег: <IfModule mod_rewrite.c></IfModule>

Не пишите излишне много директив для mod_rewrite, пишите только те правила преобразования, которые вам действительно необходимы. Особенно нужно быть аккуратным с внешними ридиректами - это такие ридиректы, которые выполняются путем отправки клиенту серверного заголовка с кодом НЕ 200 (отдача полноценной страницы), а с другим кодом (чаше всего 301 и 302) и которые приводят к перенаправлению в браузере клиента на другой URL т.е. к совершению нового запроса на клиенте.

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

X