Модуль Apache mod_rewrite
Резюме
«Главное преимущество даваемое Вам mod_rewrite это все возможности по изменению конфигурации и гибкость присутствующие в Sendmail. Обратная сторона mod_rewrite это все возможности по изменению конфигурации и гибкость присутствующие в Sendmail.»
— Brian Behlendorf
Apache Group
«Несмотря на тонны примеров и документацию, mod_rewrite это Вуду. Чертовски клёвый Вуду, но все-таки Вуду.»
Этот модуль использует механизм основанный на правилах (синтаксический анализатор основанный на регулярных выражениях) для преобразований запрошенных URL на лету. Он поддерживает неограниченное количество правил и неограниченное количество связанных с правилом условий для реализации действительно гибкого и мощного механизма для URL преобразований. URL преобоазования могут зависеть от разных критериев, например переменных сервера, переменных окружения, HTTP заголовков, времени и даже запросы к внешним базам данных в разных форматах могут быть использованы для достижения действительно точного соответствия преобразованных URL вашим ожиданиям.
Однако вся эта функциональность и гибкость имеет свой недостаток: сложность. Поэтому не ожидайте что вы поймете весь этот модуль за один день.
Этот модуль был придуман и написан в апреле 1996 и эксклюзивно подарен The Apache Group в июле 1997
Директивы
Внутренние процессы
Внутренние процессы в этом модуле очень сложны однако их нужно объяснить хотя бы один раз даже обычному пользователю во избежание общих ошибок и позволить вам использовать всю его функциональность.
Фазы API
Поэтому, после поступления запроса и определения Apache’ем соответствующего сервера (или виртуального сервера) механизм преобрахований начинает обработку всех директив mod_rewrite из конфигурационного файла сервера в фазе трансляции из URL в имя файла. Несколько шагов спустя когда находятся каталоги с конечными данными, the конфигурационные директивы mod_rewrite запускаются в фазе Fixup. В обоих этих ситуациях mod_rewrite переделывает URL либо на новые URL либо в имена файлов, хотя между ними нет объективных различий. При создании API не предполагалось его использование таким образом, однако что касается Apache 1.x это единственный возможный способ работы mod_rewrite. Чтобы внести больше ясности запомните 2 вещи:
И снова mod_rewrite упорно пытается сделать этот сложный шаг полностью прозрачным для пользователя, однако здесь вам следует запомнить: в то время как манипуляции с URL контексте сервера действительно быстры и эффективны, манипуляции в контексте каталога медленны и неэффективны из-за проблемы курицы и яйца. Однако с другой стороны это единственный возможный путь работы mod_rewrite (локально ограниченный) для URL преобразований, доступный обычному пользователю.
Не забывайте 2 эти вещи!
Обработка наборов правил
Теперь когда в этих двух фазах API запускается mod_rewrite, он считывает конфигурационные наборы правил из своей конфигурационной структуры (которая либо создается сама при запуске сервера для контекста сервера, либо ядром Apache при обходе каталогов для контекста каталога). Затем запускается механизм манипуляций с URL с имеющимся набором правил (одно или несколько правил вместе со своими условиями). Функционирование самого механизма преобразований в точности одинаково для обоих контекстов конфигурации. Различаются только конечные результы обработки.
Порядок правил в наборе важен потому что механизм преобразований обрабатывает их в специальном (и не очень очевидном) порядке. Вот это правило: Механизм преобразований просматривает весь набор правил строчка за строчкой ( RewriteRule директивы) и когда находится соответствие конкретному правилу производится просмотр соответствующих этому правилу условий ( RewriteCond директивы). По историческим причинам условия находятся перед правилами, и поэтому последовательность выполнения команд немного более длинная. См. рис. 1 для более подробной информации.

Рисунок 1:Последовательность выполнения комад при обработке набора правил
Как вы можете видеть, сначала URL проверяется на соответствие Pattern(шаблону) каждого из правил. При неудаче mod_rewrite сразу же останавливает обработку этого правила и продолжает используя следующее. Если Pattern(шаблон) совпадает, mod_rewrite ищет соответствующие этому правилу условия. Если их нет, он просто заменяет URL новой величиной полученной из строки Substitution(подстановка) и продолжает дальше обрабатывать правила. Однако если существуют условия, запускается внутренний цикл для их обработки в том порядке в котором они перечислены. Для условий эта логика другая: мы не сравниваем URL на соответствие какому-либо шаблону. Вместо этого мы сначала создаем строку TestString дополняя её переменными, обратными ссылками, запросами к карте, и т.д. и затем пытаемся проверять на соответствие с CondPattern. Если шаблон не соответствует, весь набор условий и соответствующих правил считается несоответствующим условию. Если есть соответствие шаблону, в этом случае производится обработка следующего условия до тех пор пока они будут не исчерпаны. Если все условия совпадают, процесс обработки продолжается с использованием для URL подстановки из Substitution (подстановка).
Экранирование специальных символов
Что касается Apache 1.3.20, специальные символы в TestString и Substitution строках могут быть экранированы (имеется ввиду, отношение к ним как к нормальным символам без их обычного специального значения) путем предшествующего им символа слеша (‘\’). Другими словами, вы можете включать символ доллара в строку Substitution используя ‘ \$ ‘; это не позволит mod_rewrite относиться к нему как к обратной ссылке.
Наличие обратных связей в регулярных выражениях

Рисунок 2: Движение обратных ссылок в правиле.
Мы знаем что это был тяжелый курс по внутренним механизмам mod_rewrite, однако вы получите выгоду из этих знаний при чтении последующей документации о доступных директивах.
Переменные окружения
Замечание: эти переменные содержат URI/URL в том виде, в котором они были первоначально запрошены, т.е., перед тем как были сделаные какие-либо преобразования. Это важно потому что процесс преобразования в первую очередь используется для преобразования логических URL в физические пути к конкретным файлам.
Практические решения
У нас также есть Руководство по преобразованиям URL, в котором приведена коллекция практических решений для проблем основанных на URL. Там вы можете найти наборы правил взятые из реальной жизни и дополнительную информацию о mod_rewrite.
RewriteBase Директива
| Описание: | Устанавливает базовый URL для преобразований в контексте каталога |
|---|---|
| Синтаксис: | RewriteBase URL-path |
| Значение по умолчанию: | Смотри использование для более подробной информации. |
| Контекст: | directory.htaccess |
| Разрешение: | FileInfo |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
Когда, для какого-нибудь нового URL происходит подстановка(преобразование), этот модуль должен заново вовлечь этот URL в обработку. Для того чтобы иметь возможность сделать это, нужно знать какие у него префикс или база URL. По-умолчанию этот префикс равен самому пути. Однако на большинстве сайтов URL’ы НЕ прямо соответствуют физическим путям, поэтому это допущение обычно окажется неверным! В этом случае вы должны использовать директиву RewriteBase для указания правильного префикса URL.
Например, предположим следующий конфигурационный файл каталога:
Для Apache хакеров
Следующий список дает подробную информацию об этапах внутренней обработки:
Это кажется очень сложным однако это корректная внутренняя работа Apache, из-за того что преобразования в контексте каталога происходят слишком поздно в этом процессе. Поэтому, когда это происходит (преобразование) запрос должен быть обратно возвращен ядру Apache! ОДНАКО: В то время как это кажется серъёзным накладным расходом, в действительности это не так, потому что этот возврат происходит целиком внутри сервера Apache и та же самая процедура используется многими другими операциями внутри Apache. Поэтому, вы можете быть уверены что дизайн и и реализация правильные.
RewriteCond Директива
| Описание: | Определяет условие при котором происходит преобразование |
|---|---|
| Синтаксис: | RewriteCond TestString CondPattern |
| Значение по умолчанию: | None |
| Контекст: | server configvirtual host directory.htaccess |
| Разрешение: | FileInfo |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
TestString строка которая может содержать следующие дополнительные конструкции в дополении к простому тексту:
%< NAME_OF_VARIABLE >
где NAME_OF_VARIABLE может быть строкой взятой из следующего списка:
|
IS_SUBREQ Будет содержать текст «true» если запрос выполняется в текущий момент как подзапрос, «false» в другом случае. Подзапросы могут быть сгенерированны модулями которым нужно иметь дело с дополнительными файлами или URI для того чтобы выполнить собственные задачи. API_VERSION Это версия API модуля Apache (внутренний интерфейс между сервером и модулем) в текущей сборке сервера, что определено в include/ap_mmn.h. API версия модуля соответствует используемой версии Apache (для версии Apache 1.3.14, к примеру это 19990320:10), однако это в основном интересно авторам модулей. THE_REQUEST Полная строка HTTP запроса отправленная браузером серверу (т.е., « GET /index.html HTTP/1.1 »). Она не включает какие-либо дополнительные заголовки отправляемые браузером. REQUEST_URI Ресурс, запрошенный в строке HTTP запроса. (В примере выше, это было бы «/index.html».) REQUEST_FILENAME Полный путь в файловой системе сервера к файлу или скрипту соответствующим этому запросу.
CondPattern это шаблон условия, т.е., какое-либо регулярное выражение применяемое к текущему экземпляру TestString, т.е., TestString просматривается на поиск соответствия CondPattern.
Помните: CondPattern это perl совместимое регулярное выражение с некоторыми дополнениями:
Замечание
Дополнительно вы можете устанавливать специальные флаги для CondPattern добавляя
[ flags ]
Пример:
Для выдачи главной страницы какого-либо сайта согласно « User-Agent: » заголовку запроса, вы можете использовать следующие директивы:
Интерпретация: Если у вас Netscape Navigator (который идентифицируется как ‘Mozilla’), вы выдаете максимально навороченную страницу, с фреймами, и т.д. Если у вас Lynx (текстовый браузер), вы выдаете наименее навороченную страницу, без рисунков, таблиц и т.д. Если любой другой браузер, выдаете стандартную страницу.
RewriteEngine Директива
| Описание: | Включает или выключает работу механизма преобразования |
|---|---|
| Синтаксис: | RewriteEngine on|off |
| Значение по умолчанию: | RewriteEngine off |
| Контекст: | server configvirtual host directory.htaccess |
| Разрешение: | FileInfo |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
Отметьте, что по-умолчанию, настройки преобразований не наследуются. Это означает что вы должны иметь RewriteEngine on директиву для каждого виртуального хоста в котором вы хотите использовать этот модуль.
RewriteLock Директива
| Описание: | Устанавливает имя файла используемого для RewriteMap синхронизации |
|---|---|
| Синтаксис: | RewriteLock file-path |
| Значение по умолчанию: | None |
| Контекст: | server config |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
Эта директива устанавливает имя файла файла синхронизации который нужен mod_rewrite для связи с RewriteMap программами. Сделайте этот файл локальным (размещенным не на NFS-смонтированном ресурсе) когда вы хотите использовать программу для создания ассоциативного массива преобразований. Это не является обязательным для других типов таких массивов.
RewriteLog Директива
| Описание: | Устанавливает имя файла используемое для ведения журнала механизма преобразования |
|---|---|
| Синтаксис: | RewriteLog file-path |
| Контекст: | server configvirtual host |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
Директива RewriteLog устанавливает имя файла а котором сервер ведет журнал любых происходящих действий по преобразованиям URL. Если это имя не начинается со слэша (‘ / ‘) в этом случае путь считается от Server Root. В конфигурационном файле сервера эта директива должна встерчаться только один раз.
Безопасность
RewriteLogLevel Директива
| Описание: | Устанавливает уровень детализации при журнализации действий механизма преобразований |
|---|---|
| Синтаксис: | RewriteLogLevel Level |
| Значение по умолчанию: | RewriteLogLevel 0 |
| Контекст: | server configvirtual host |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
Директива RewriteLogLevel устанавливает уровень детализации журнала механизма преобразований. По-умолчанию уровень 0 означающий что журнализация не ведется, в то время как 9 или более означает что записываются практически все действия.
Для отключения журнализации действий механизма преобразований просто установите уровень на 0. Это отключает ведение журнала для всех действий по преобразованиям.
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 — самого ассоциативного массива:
Это стандартная опция для создания ассоциативного массива где MapSource это простой текстовый ASCII файл содержащий либо пустый строчки, строчки комментариев (начинающиеся с символа ‘#’) либо пары подобные следующим — одна в строчке:
MatchingKey SubstValue
Этот вариант идентичен варианту с простым текстом приведённом выше но со специальной особенностью пост-обработки: После нахождения какую-либо величину производится её анализ на предмет нахождения символов « | » которые имеют значение логического «или». Другими словами они означают набор альтернативных вариантов и выбор возвращаемой величины из них производится произвольно. Хотя это кажется безумием и абсалютно бесполезным, это в действительности используется для балансировки нагрузки в ситуациях с обратным прокси где происходит поиск имен серверов. Например:
Здесь, источник — это двоичный файл DBM формата содержащий то же самое содержимое что и простой текстовый файл, однако в специальном виде, оптимизированном для действительно быстрого поиска. Этот тип может быть sdbm, gdbm, ndbm, или db в зависимости от настроек при компиляции. Если тип опущен, выбирается тип установленный по-умолчанию при компиляции. Вы можете создавать такой файл любой утилитой DBM или следующим Perl скриптом. Убедитесь что он настроен для создания требуемого типа DBM файла. Этот пример создает файл NDBM.
Здесь, источник — это какая-либо внутренняя функция Apache. В настоящее время вы не можете создавать свои собственные функции, однако уже существуют следующие функции:
Здесь, источник — это программа, а не файл с ассоциативным массивом. Для её создания вы можете использовать любой выбранный язык, однако результат должен быть исполняемым файлом (т.е., либо объектным кодом либо скриптом с магической первой строчкой ‘ #!/path/to/interpreter ‘).
Эта программа запускается один раз при запуске сервера Apache и затем взаимодействует с механизмом преобразований через файловые обработчики stdin (поток ввода) и stdout (поток вывода). Для каждого поиска в массиве, соответствующий ключ для поиска, будет получаться в виде строки, подаваемой на stdin и оканчивающейся символом перевода строки. Затем эта программа должна вернуть значение найденной величины в stdout в виде строки оканчивающейся символом перевода строки либо строкой из четырёх символов « NULL » если поиск неудачен (т.е., для соответствующего значения ключа не найдено никакого значения). Тривиальная программа реализующая массив 1:1 (т.е., ключ == значение) может выглядеть так:
Однако будьте очень осторожны:
Директива RewriteMap может встречаться более одного раза. Для каждого массива используйте одну RewriteMap директиву для объявления файла с массивом преобразований. В то время как вы не можете определять массив в контексте каталога, его использование в этом контексте конечно же возможно.
Замечание
RewriteOptions Директива
| Описание: | Устанавливает кое-какие специальные опции для механизма преобразований |
|---|---|
| Синтаксис: | RewriteOptions Options |
| Значение по умолчанию: | None |
| Контекст: | server configvirtual host directory.htaccess |
| Разрешение: | FileInfo |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
Директива RewriteOptions устанавливает некоторые специальные опции для текущей конфигурации в контексте сервера или каталога. Строки Option могут иметь следующий вид:
RewriteRule Директива
| Описание: | Определяет правила для механизма преобразований |
|---|---|
| Синтаксис: | RewriteRule Шаблон Подстановка |
| Значение по умолчанию: | None |
| Контекст: | server configvirtual host directory.htaccess |
| Разрешение: | FileInfo |
| Статус: | Расширение |
| Модуль: | mod_rewrite |
| Совместимость: | Флаг cookie доступен в Apache 2.0.40 и более поздних. |
Директива RewriteRule и есть настоящая рабочая лошадка преобразований. Эта директива может встречаться более одного раза. Каждая директива, в этом случае, определяет одно правило преобразования. Порядок определений этих правил важен, потому что этот порядок используется при обработке правил во время работы.
Некоторые указания по синтаксису регулярных выражений:
Более подробную информацию о регулярных выражениях смотрите в документации по регулярным выражениям для perl («perldoc perlre»). Если вы заинтересованы в ещё более детальной информации о регулярных выражениях и их диалектах (POSIX и т.д.) смотрите следующую, специально написанную по этой теме книгу:
Mastering Regular Expressions
Jeffrey E.F. Friedl
Nutshell Handbook Series
O’Reilly & Associates, Inc. 1997
ISBN 1-56592-257-3
Примечание
Как уже было упомянуто выше, все правила преобразований применяются с использованием Подстановки (в порядке, в котором они определены в конфигурационном файле). URL полностью заменяется Подстановкой и процесс преобразования идет до тех пор, пока не останется больше никаких правил, если только он не прерван специально, с помощью флага L — см. ниже.
Ещё одно замечание: Вы даже можете создавать URL, содержащие строку запроса, в строке подстановки. Просто используйте вопросительный знак внутри строки подстановки для указания того, следующее за ним содержимое должно быть преобразовано в QUERY_STRING (строку запроса). Когда вы хотите убрать существующую строку запроса, завершайте строку подстановки просто вопросительным знаком.
Примечание
Помните
В подстановке вы можете использовать, в том числе, и специальные флаги путем добавления следующей конструкции:
[ флаги ]
» в « /u/ » или всегда добавлять слэш к /u/ user, и т.д.
Use the following rule for your decision: whenever you prefix some URLs with CGI-scripts to force them to be processed by the CGI-script, the chance is high that you will run into problems (or even overhead) on sub-requests. In these cases, use this flag.
For Apache hackers
There is one exception: If a substitution string starts with « http:// » then the directory prefix will not be added and an external redirect or proxy throughput (if flag P is used!) is forced!
Here are all possible substitution combinations and their meanings:
Настройка mod_rewrite
Что такое mod_rewrite?
Вспомните последнее посещение интернет-магазина. Найдя нужный товар, вы, вероятно, увидели примерно такой URL:
Это происходит не потому, что разработчики этого сайта потратили уйму времени, чтобы настроить отдельные директории для разных категорий товара, а благодаря удобному модулю по имени mod_rewrite. Данный модуль позволяет создавать пользовательские и упрощенные URL-адреса. На самом деле URL выглядит примерно так:
Требования
Для выполнения данного руководства понадобятся привилегии root (чтобы получить более подробную информацию, читайте статью «Начальная настройка сервера Ubuntu»).
Кроме того, нужно предварительно установить apache. Для быстрой установки этого веб-сервера в Ubuntu используйте команду:
sudo apt-get install apache2
1: Включение mod_rewrite
Для начала нужно включить mod_rewrite, это очень просто:
sudo a2enmod rewrite
Данная команда включит модуль или же выведет сообщение «Module rewrite already enabled» в случае если модуль уже включен.
sudo nano /var/www/example.com/.htaccess
Примечание: для этого понадобятся расширенные привилегии sudo.
sudo nano /etc/apache2/sites-available/default
В этом файле найдите следующий раздел и измените значение строки AllowOverride (замените None на All). В результате раздел будет иметь такой вид:
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
sudo service apache2 restart
Теперь все готово для переписывания URL-адресов сайта.
3: Переписывание URL-адресов
RewriteRule Pattern Substitution [OptionalFlags]
Опции, использованные в данной команде:
Примеры перезаписи URL-адреса
Пример 1: открываете страницу А – попадаете на страницу Б
Это наиболее простой пример перезаписи URL: посетитель сайта вводит в браузер один URL, но перенаправляется на другой. Чтобы настроить такое поведение, следуйте инструкциям этого раздела.



