RewriteMap

Описание:
Определяет функцию создания ассоциативного массива для поиска по ключу
Синтаксис:
RewriteMap MapName MapType:MapSource
Значение по умолчанию:
нет
Контекст:
server configvirtual host
Статус:
Расширение
Модуль:
mod_rewrite
Совместимость:
Выбор разных типов dbm доступен в Apache 2.0.41 и более поздних версиях

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

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

${ MapName : LookupKey }
${ MapName : LookupKey | DefaultValue }

Когда встречается подобная конструкция, происходит обращение к массиву MapName и поиск значения сопоставленного ключу LookupKey. Если найдено искомое значение ключа, происходит извлечение значения SubstValue с помощью соответствующей функции. Если ключ не найден тогда происходит подстановка DefaultValue или пустой строки если не указана DefaultValue.

Могут быть использованы следующие комбинации типа функции - MapType для вставки/извлечения элементов массива и MapSource - самого ассоциативного массива:

  • Простой текст
    MapType: txt, MapSource: Путь к существующему файлу в файловой системе Unix

    Это стандартная опция для создания ассоциативного массива где MapSource это простой текстовый ASCII файл содержащий либо пустый строчки, строчки комментариев (начинающиеся с символа '#') либо пары подобные следующим - одна в строчке:

    MatchingKey SubstValue

    Пример

    ##
    ##  map.txt -- массив преобразований
    ##
    
    Ralf.S.Engelschall  rse   # Bastard Operator From Hell
    Mr.Joe.Average  joe   # Mr. Average

    RewriteMap real-to-user txt:/path/to/file/map.txt

  • Произвольный простой текст
    MapType: rnd, MapSource: Путь к существующему файлу в файловой системе Unix

    Этот вариант идентичен варианту с простым текстом приведённом выше но со специальной особенностью пост-обработки: После нахождения какую-либо величину производится её анализ на предмет нахождения символов "|" которые имеют значение логического "или". Другими словами они означают набор альтернативных вариантов и выбор возвращаемой величины из них производится произвольно. Хотя это кажется безумием и абсолютно бесполезным, это в действительности используется для балансировки нагрузки в ситуациях с обратным прокси где происходит поиск имен серверов. Например:

    ##
    ##  map.txt -- массив преобразований
    ##
    
    static   www1|www2|www3|www4
    dynamic  www5|www6

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

  • Хэш файл
    MapType: dbm[=type], MapSource: Путь к существующему файлу в файловой системе Unix

    Здесь, источник - это двоичный файл DBM формата содержащий то же самое содержимое что и простой текстовый файл, однако в специальном виде, оптимизированном для действительно быстрого поиска. Этот тип может быть sdbm, gdbm, ndbm, или db в зависимости от настроек при компиляции. Если тип опущен, выбирается тип установленный по-умолчанию при компиляции. Вы можете создавать такой файл любой утилитой DBM или следующим Perl скриптом. Убедитесь что он настроен для создания требуемого типа DBM файла. Этот пример создает файл NDBM.

    #!/path/to/bin/perl
    ##
    ##  txt2dbm -- convert txt map to dbm format
    ##
    
    use NDBM_File;
    use Fcntl;
    
    ($txtmap, $dbmmap) = @ARGV;
    
    open(TXT, "<$txtmap") or die "Couldn't open $txtmap!\n";
    tie (%DB, 'NDBM_File', $dbmmap,O_RDWR|O_TRUNC|O_CREAT, 0644)
      or die "Couldn't create $dbmmap!\n";
    
    while (<TXT>) {
      next if (/^\s*#/ or /^\s*$/);
      $DB{$1} = $2 if (/^\s*(\S+)\s+(\S+)/);
    }
    
    untie %DB;
    close(TXT);

    $ txt2dbm map.txt map.db

  • Внутренняя функция
    MapType: int, MapSource: внутренняя функция Apache

    Здесь, источник - это какая-либо внутренняя функция Apache. В настоящее время вы не можете создавать свои собственные функции, однако уже существуют следующие функции:

    • toupper:
      Преобразует ключ поиска в верхний регистр.
    • tolower:
      Преобразует ключ поиска в нижний регистр.
    • escape:
      Транслирует специальные символы в ключе поиска в их числовые коды.
    • unescape:
      Транслирует числовые коды в ключе поиска обратно в специальные символы.
  • Внешняя программа преобразования
    MapType: prg, MapSource: Путь к существующему файлу в файловой системе Unix

    Здесь, источник - это программа, а не файл с ассоциативным массивом. Для её создания вы можете использовать любой выбранный язык, однако результат должен быть исполняемым файлом (т.е., либо объектным кодом либо скриптом с магической первой строчкой '#!/path/to/interpreter').

    Эта программа запускается один раз при запуске сервера Apache и затем взаимодействует с механизмом преобразований через файловые обработчики stdin(поток ввода) и stdout(поток вывода). Для каждого поиска в массиве, соответствующий ключ для поиска, будет получаться в виде строки, подаваемой на stdin и оканчивающейся символом перевода строки. Затем эта программа должна вернуть значение найденной величины в stdout в виде строки оканчивающейся символом перевода строки либо строкой из четырёх символов "NULL" если поиск неудачен (т.е., для соответствующего значения ключа не найдено никакого значения). Тривиальная программа реализующая массив 1:1 (т.е., ключ == значение) может выглядеть так:

    #!/usr/bin/perl 
    $| = 1; 
    while (<STDIN>) {
        # ...put here any transformations or lookups...
        print $_; 
    } 

    Однако будьте очень осторожны:

    1. "Keep it simple, stupid" (KISS) - делай это проще, дурачок, потому что если эта программа зависнет - это повесит сервер Apache когда встретится правило использующее этот массив (создаваемый внешней программой).
    2. Для избежания распространенной ошибки: никогда не делайте буферизованный ввод/вывод для stdout! Это вызовет бесконечное зацикливание! Отсюда "$|=1" в вышеприведенном примере...
    3. Используйте директиву RewriteLock для определения файла блокировок который mod_rewrite может использовать для синхронизации связи с этой программой. По-умолчанию такая синхронизация не производится.

Директива RewriteMap может встречаться более одного раза. Для каждого массива используйте одну RewriteMap директиву для объявления файла с массивом преобразований. В то время как вы не можете определять массив в контексте каталога, его использование в этом контексте конечно же возможно.

Замечание

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