Полное руководство по mod_rewrite (часть 7): Директива RewriteMap

Оглавление. Полное руководство по mod_rewrite

1. Как включить и как работает mod_rewrite

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

3. Флаги RewriteRule

4. Директива RewriteCond

5. Частые случаи и примеры использования mod_rewrite

6. Продвинутые техники

7. Директива RewriteMap

7.1 Что такое RewriteMap, как использовать RewriteMap

7.2 Контекст директорий и .htaccess

7.3 Типы карты RewriteMap

7.3.1 int: Внутренняя функция

7.3.2 txt: Простые текстовые карты

7.3.3 rnd: Рандомизированный обычный текст

7.3.4 dbm: хеш файл DBH

7.3.5 prg: Внешняя программа перезаписи

7.3.6 dbd или fastdbd: SQL Query

7.4 Резюме

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


Что такое RewriteMap, как использовать RewriteMap

Директива RewriteMap определяет карту перезаписи (Rewriting Map), которая может использоваться внутри строк подстановки в правилах перезаписи с помощью функций определения соответствия для вставки/замены полей с помощью поиска по ключу. Источник этого поиска может быть разных типов.

Т.е. объёмную информацию о преобразовании полученных данных можно вынести в отдельный файл, так называемую «карту». С помощью описанных далее конструкций можно обращаться к этой карте как к базе данных и в соответствии с полученным «картой» ключом, она будет выдавать соответствующие значения.

Синтаксис:

RewriteMap ИмяКарты ТипКарты:ИсточникКарты [ОпцииТипаКарты]

ИмяКарты – это имя карты, которое также будет использоваться для определения функции определения соответствия (mapping-function) для строк подстановки в правиле перезаписи через одну из следующих конструкций:

${ ИмяКарты : КлючЗапроса }
${ ИмяКарты : КлючЗапроса | ДефолтноеЗначение }

Когда встречается такая конструкция, опрашивается карта с именем ИмяКарты и производиться поиск по ключу КлючЗапроса. Если ключ найден, то конструкция функция определения соответствия заменяется на ЗначениеПодстановки (берётся из карты). Если ключ не найден, тогда она заменяется на ДефолтноеЗначение или пустой строкой, если ДефолтноеЗначение не указано. Пустые значения ведут себя так, как если бы ключ отсутствовал, поэтому невозможно различать ключи с пустыми значениями и отсутствующие ключи.

Например, вы можете определить RewriteMap так:

RewriteMap examplemap "txt:/путь/до/файла/карты.txt"

Тогда вы сможете использовать эту карту в RewriteRule следующим образом:

RewriteRule "^/ex/(.*)" "${examplemap:$1}"

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

RewriteRule "^/ex/(.*)" "${examplemap:$1|/not_found.html}"

В первой конструкции, мы определили имя карты, которая называется examplemap, а также её тип (txt) и путь в файловой системе, где находится файл с картой (/путь/до/файла/карты.txt). После этого с помощью RewriteRule мы ищем в запросе строки, которые соответствуют регулярному выражению ^/ex/(.*) (оно означает, что строка начинается с /ex/, а затем следует что угодно). Поскольку используются круглые скобки, то в регулярном выражении имеется обратная ссылка – она обозначена в Подстановке как $1. Значение из первоначального запроса (что угодно после /ex/), передаётся в подстановку, где указано имя карты – examplemap. Также через двоеточие указано условное обозначение первой обратной ссылки. Именно это значение и передаётся в карту и там оно используется для поиска в качестве КлючаЗапроса.

Контекст директорий и .htaccess

Директива RewriteMap не может использоваться в секциях <Directory> или файлах .htaccess. Вы должны объявить карту в контексте сервера или виртуального хоста. После создания карты, вы можете использовать RewriteRule и RewriteCond в том числе в контексте директорий и файле .htaccess. В них вы только не можете объявлять карту.

Значение ОпцииТипаКарты зависит от конкретного ТипаКарты. Подробности далее.

Типы карты RewriteMap

Могут использоваться следующие комбинации ТипаКарты и ИсточникаКарты:

txt

Файл с простым текстом, содержащий разделённые пробелом пары ключзначение, по одной паре на каждую строку.

rnd

Случайно выбираемые записи из простого текстового файла.

dbm

Ищет записи в файле dbm, содержащем пары имя, значение. Хеш построен из формата простого текстового файла, с использованием утилиты httxt2dbm.

int

Одна из четырёх внутренних функций, предоставляемых RewriteMap: toupper, tolower, escape или unescape.

prg

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

dbd или fastdbd

SQL SELECT выражение для выполнения поиска цели перезаписи.

Далее более подробно описываются различные ТипыКарты, которые могут использоваться с RewriteMap, и для каждого типа даны примеры использования.

int: Внутренняя функция

Когда используется ТипКарты int, ИсточникКарты является одной из доступных внутренних функций RewriteMap. Авторы модуля могут предоставить дополнительные внутренние функции, зарегистрировав их с помощью API ap_register_rewrite_mapfunc. Функции, которые предоставляются по умолчанию:

  • toupper:

Преобразует весь ключ в верхний регистр (становится написан большими буквами).

  • tolower:

Преобразует весь ключ в нижний регистр (становится написан м буквами).

  • escape:

Переводит специальные символы в ключе в шестнадцатеричные кодировки.

  • unescape:

Переводит шестнадцатеричные кодировки в ключе в специальные символы.

Чтобы использовать одну из этих функций, создайте RewriteMap, ссылаясь на функцию int, а затем используйте ее в RewriteRule:

Перенаправить URI на свою версию, написанную строчными буквами:

RewriteMap lc int:tolower
RewriteRule "(.*)" "${lc:$1}" [R]

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

txt: Простые текстовые карты

Когда используется ТипыКарты txt, ИсточникКарты представляет собой путь в файловой системе к файлу сопоставления в виде обычного текста, содержащему одну пару ключ/значения, разделенных пробелом, на каждую строку. Опционально строка может содержать комментарий, начинающийся с символа '#'.

Правильно сформированный текстовый файл перезаписи будет иметь следующий синтаксис:

# Строка комментария
MatchingKey SubstValue
MatchingKey SubstValue # комментарий

Когда вызывается RewriteMap, аргумент ищется в первом аргументе строки, и, если найден, возвращается значение подстановки.

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

Настройка преобразования «продукт к ID»

RewriteMap product2id "txt:/etc/apache2/productmap.txt"
RewriteRule "^/product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]

Мы предполагаем, что скрипт prods.php знает, что делать, когда он получил аргумент id=NOTFOUND в случае если продукт не найден на карте поиска.

Файл /etc/apache2/productmap.txt содержит следующее:

Карта «продукт к ID»
##
## productmap.txt – Файл преобразования продукта к ID
##

television 993
stereo 198
fishingrod 043
basketball 418
telephone 328

Таким образом, когда запрашивается http://example.com/product/television, применяется RewriteRule, и запрос внутренне сопоставляется с /prods.php?id=993.

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

RewriteRule "^product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]

Кэшированные запросы: Запрошенные ключи кэшируются в httpd до тех пор, пока не изменится mtime (время модификации) файла карты или сервер httpd не будет перезапущен. Это обеспечивает лучшую производительность на картах, к которым обращается множество запросов.

rnd: Рандомизированный обычный текст

Когда используется ТипыКарты rnd, ИсточникКарты представляет собой путь в файловой системе к файлу сопоставления с обычным текстом, каждая строка которого содержит ключ и одно или несколько значений, разделенных символом |. Если совпал ключ, то будет произвольно выбрано одно из этих значений.

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

Файл карты Rewrite

##
## map.txt – карта перезаписи
##

static www1|www2|www3|www4
dynamic www5|www6

Конфигурационные директивы

RewriteMap servers "rnd:/path/to/file/map.txt"

RewriteRule "^/(.*\.(png|gif|jpg))" "http://${servers:static}/$1"  [NC,P,L]
RewriteRule "^/(.*)"                "http://${servers:dynamic}/$1" [P,L]

Таким образом, когда изображение запрашивается и выполняется первое из этих правил, RewriteMap ищет строку static в файле карты, которая возвращает одно из указанных имен хостов в случайном порядке, которое затем используется в целевом RewriteRule.

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

static www1|www1|www2|www3|www4

dbm: хеш файл DBH

Когда используется ТипыКарты dbm, ИсточникКарты представляет собой путь в файловой системе к файлу базы данных DBM, содержащему пары ключ/значение, которые должны использоваться в сопоставлении. Это работает точно так же, как и txt-карта, но намного быстрее, потому что DBM индексируется, а текстовый файл – нет. Это позволяет более быстрый доступ к нужному ключу.

Вы можете указать конкретный тип dbm:

RewriteMap examplemap "dbm=sdbm:/etc/apache/mapfile.dbm"

Тип может быть sdbm, gdbm, ndbm или db. Однако рекомендуется использовать только утилиту httxt2dbm, поставляемую с сервером Apache HTTP, так как она будет использовать правильную библиотеку DBM, соответствующую той, которая была использована при создании самого httpd.

Чтобы создать файл dbm, сначала создайте текстовый файл карты, как описано в разделе txt. Затем запустите httxt2dbm:

httxt2dbm -i mapfile.txt -o mapfile.map

Затем вы можете ссылаться на полученный файл в директиве RewriteMap:

RewriteMap mapname "dbm:/etc/apache/mapfile.map"

Обратите внимание, что с некоторыми типами dbm создается более одного файла с общим базовым именем. Например, у вас могут быть два файла с именем mapfile.map.dir и mapfiile.map.pag. Это нормально, и вам нужно использовать базовое имя mapfile.map в вашей директиве RewriteMap.

Кэшированные запросы: Запрошенные ключи кэшируются в httpd до тех пор, пока не изменится mtime (время модификации) файла карты или сервер httpd не будет перезапущен. Это обеспечивает лучшую производительность на картах, к которым обращается множество запросов.

prg: Внешняя программа перезаписи

Когда используется ТипыКарты prg, ИсточникКарты представляет собой путь в файловой системе к исполняемой программе, которая будет обеспечивать поведение сопоставления. Это может быть скомпилированный двоичный файл или программа на интерпретируемом языке, например Perl или Python.

Эта программа запускается один раз, когда запускается HTTP-сервер Apache, а затем общается с механизмом перезаписи через STDIN и STDOUT. То есть для каждого запроса поиска по карте он ожидает один аргумент через STDIN и должен возвращать одну строку ответа с терминирующим символом new-line в ​​STDOUT. Если по запросу ничего не найдено, программа сопоставления должна вернуть четырёхсимвольную строку «NULL», чтобы указать это.

Внешние программы перезаписи не запускаются, если они определены в контексте, в котором не настроен RewriteEngine.

По умолчанию внешние программы перезаписи запускаются как пользователь:группа, которые запустили httpd. Это можно изменить в системах UNIX, передав имя пользователя и имя группы в качестве третьего аргумента RewriteMap в формате имя_пользователя:имя_группы.

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

Здесь показан простой пример, который заменит все дефисы символами подчеркивания в URI запросе.

Настройка перезаписи

RewriteMap d2u "prg:/www/bin/dash2under.pl" apache:apache
RewriteRule "-" "${d2u:%{REQUEST_URI}}"

dash2under.pl

#!/usr/bin/perl
$| = 1; # Turn off I/O buffering
while (<STDIN>) {
    s/-/_/g; # Replace dashes with underscores
    print $_;
}

Внимание!

  • Делайте свою программу перезаписи как можно более простой. Если программа зависает, это заставит httpd ждать бесконечно ответа с карты, что, в свою очередь, приведет к тому, что httpd перестанет отвечать на запросы.
  • Обязательно отключите буферизацию в своей программе. В Perl это делается второй строкой в приведённом примере скрипта: $| = 1; Это, конечно, будет отличаться на других языках. Буферизованный ввод-вывод заставит httpd ждать выхода, и поэтому он будет висеть.
  • Помните, что только одна копия программы запускается при запуске сервера. Все запросы должны пройти через это узкое место. Это может привести к значительным замедлениям, если много запросов должны пройти этот процесс или если сам скрипт очень медленный.

dbd или fastdbd: SQL Query

Когда используется ТипыКарты dbd или fastdbd, ИсточникКарты представляет собой инструкцию SQL SELECT, которая принимает один аргумент и возвращает одно значение.

Необходимо настроить mod_dbd для указания нужной базы данных для выполнения этого оператора.

Существуют две формы этого ТипыКарты. Использование ТипыКарты dbd заставляет запрос выполняться с каждым запросом карты, а использование fastdbd кэширует внутри результаты поиска по базе данных. Таким образом, хотя fastdbd более эффективен и, следовательно, быстрее, он не будет знать об изменениях в базе данных до перезапуска сервера.

Если запрос возвращает более одной строки, используется случайная строка из результирующего набора.

Пример

RewriteMap myquery "fastdbd:SELECT destination FROM rewrite WHERE source = %s"

Примечание: Имя запроса передается драйверу базы данных в качестве метки для подготовленного SQL оператора и поэтому необходимо будет соблюдать любые правила (например, чувствительность к регистру), необходимые для вашей базы данных.

Резюме

Директива RewriteMap может появляться несколько раз. Для каждой функции сопоставления используйте одну директиву RewriteMap для объявления её перезаписывающего файла карты.

Хотя вы не можете объявить карту в контексте директории (файлы .htaccess или блоки <Directory>), эту карту можно использовать в контексте директорий.

Продолжение: «Полное руководство по mod_rewrite (часть 8): Директива RewriteOptions, технические подробности, когда НЕ использовать mod_rewrite».

Рекомендуемые статьи:

Добавить комментарий

Ваш e-mail не будет опубликован.