Как стать автором
Обновить

Практика использования mod_rewrite

Время на прочтение6 мин
Количество просмотров19K
Статья предназначена тем, кто уже знаком с Apache Rewrite module и пусть не всегда, но использует его в своей нелегкой жизни. Вопрос рассматривается в контексте использования PHP как серверного скриптового языка.

Не найдя подходящей статьи на Хабре решил восполнить этот пробел и подробнее остановиться на таком замечательном инструменте, как mod_rewrite для Apache. Я не буду описывать всех премудростей построения красивых URL'иков и описывать процесс работы парсера POSIX-like регулярных выражений в Apache. В этой, я надеюсь, не последней статье по mod_rewrite я бы хотел подробнее остановиться на проблеме использования. Если в кратце — почему mod_rewrite и что он дает с небольшими примерами.

Проблемма


В своей деятельности я очень часто сталкивался с забавными моментами, когда многие программисты, то ли от незнания, то ли от нежелания использовать в полную силу данный им инструментарий начинали городить в своих исходниках околесицу. Как конкретный пример — практически в любом «мультиплатформенном многозадачном скрипте, будь то CMS или еще что-то из этого рода я в любом случае находил те или иные методы разбора приходящего URL'а на составляющие.

Но в любом, даже самом большом проекте количество URL'ов для перехода ограниченно каким-либо множеством. А если учесть, что большая часть из них содержит в себе повторяющиеся элементы (например — id или какой-либо другой его „заменитель“), которые могут быть прекрасно пропущены через регулярное выражение — получаем совсем небольшой набор „основополагающих“ URL'ов, на которых построен весь проект.

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

Решение


Вот здесь перед разработчиком отчетливо встает проблемма — либо изучать mod_rewrite, либо использовать/писать парсер URL на стороне скриптового языка.

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

1.Парсер URL

Сравните это правило:

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

И вот это:

RewriteRule ^/pages/([0-9A-z_]{1,64}).html$ index.php?mod=Pages&page_link=$1 [QSA,L]

Что явно бросается в глаза:
  1. в первом случае определением, куда и как идет наш конечный пользователь занимется скриптовая часть. Во втором все это возложено на плечи mod_rewrite и, как ни странно, он со своей задачей справляется замечательно.
  2. Дополнительным веским плюсом в сторону второго примера становится то, что мы, фактически, выбрасываем из своей скриптовой части полностью все элементы определения, какой модуль нам нужен, какая часть этого модуля будет работать и какие параметры этому модулю будут передаваться. У нас просто негде использовать парсер по разбору URL — за скриптовую часть это делает mod_rewrite. Я думаю, улучшение производительности будет ощутимо.

2.Фильтрация входящих значений

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

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

RewriteRule ^/products/([0-9]{1,8}).html$ index.php?mod=Products&product_id=$1 [QSA,L]
RewriteRule ^(.*)$ index.php?mod=Errors&error_id=404 [QSA,L]

ты мы, в итоге, получаем элементарнейший фильтр входящих в скрипт значений переменных. Разве это не замечательно? Таким образом мы значительно облегчаем себе жизнь, зная, что к нам, на сторону скриптовой части приложения, неправильные данные просто не могут прийти и их фильтрацией занимается Apache. Соответственно — значительная часть нашего головоломания будет направлена не на защиту от хакеров, а на что-то более продуктивное.

3. Окружение Веб-сервера

Да, mod_rewrite позволяет делать и это. С помощью правила

RewriteRule ^(.*)/(.*)/var=([^/]+)/ $1/$2 [E=VAR:$3]
мы установим переменную окружения Apache в соответствующее значение, пришедшее к нам из GET-запроса. Плюс в этом ко всему прочему в том, что мы получаем еще один механизм взаимодействия, обрабатывая не только входящие значения POST и GET запросов, но и переменные окружения самого веб-сервера.

Единственное „но“ в этом случае — нужно быть очень и очень осторожным.

Статьи

Для желающих более подробно познакомиться со всеми возможностями mod_rewrite стоит заглянують в первую очередь сюда:
  1. Apache Module mod_rewrite
  2. URL Rewriting Guide
  3. URL Rewriting Guide — Advanced topics

Так же замечательная статья на русском по использованию mod_rewrite была на phpclub.ru.

Резюме

Быть может сейчас я повторю уже заезженную фразу, но Apache mod_rewrite — действительно мощное и полезное средство в разработке любого Web-ориентированного проекта на Linux-Apache based платформе. И незнание и нежелание его использовать может очень навредить разработчику. Я надеюсь, что эта статья поможет сомневающимся начать более плотно изучать инструментарий этого модуля и в будущем его использование будет намного более продуктивным.

P.S.
1. Здесь я остановился на основных моментах, возможно в процессе статья будет дополнена некоторыми интересными примерами из личной практики. В большинстве же своем они описаны в Rewrite Guide. Прочитать эти гайды и понять их — очень полезно и познавательно.
2. Если эта тема кого-нибудь заинтересовала — в будущем я могу оформить небольшой цикл статей с разбором всего, что связано в mod_rewrite и подробным объяснением принципов его работы, которые когда-то объяснялись в рассылках и которые можно посмотреть в исходниках. Ну и конечно же — практика хорошей работы.
3. Буду благодарен за любые советы и отзывы. Практически первый топик — сильно не ругайтесь ^_^

UPDATE

Оценочное тестирование

В общем и целом я таки сравнил некоторые способы парсинга. Сразу оговорюсь, что это всего лишь тест и никакой мысленной нагрузки о правильности или неправильности пути парсинга он не несет. Простой пример и ничего более.

Test Cases:

1. PHP Native
.htaccess:
RewriteEngine On
Options +FollowSymlinks
RewriteBase /
RewriteRule ^(.*)$ index.php?params=$1 [QSA]

index.php:
<?php
$URI = $_GET['params'];
$params = array_values(array_filter(explode('/', $URI)));
print_r($params);


2. Apache mod_rewrite
.htaccess:
RewriteEngine On
Options +FollowSymlinks
RewriteBase /
RewriteRule ^([A-z0-9]{0,})/([A-z0-9]{0,})/([A-z0-9]{0,})/([A-z0-9]{0,})/([A-z0-9]{0,})/([A-z0-9]{0,})/([A-z0-9]{0,})/([A-z0-9]{0,})/$ index.php?0=$1&1=$2&2=$3&3=$4&4=$5&5=$6&6=$7&7=$8 [QSA,L]

index.php:
<?php
print_r($_GET);


3. PHP preg_match
htaccess:
RewriteEngine On
Options +FollowSymlinks
RewriteBase /
RewriteRule ^(.*)$ index.php?params=$1 [QSA]


index.php:
<?php
$URI = $_GET['params'];
preg_match ( "/([A-z0-9]{0,})\/([A-z0-9]{0,})\/([A-z0-9]{0,})\/([A-z0-9]{0,})\/([A-z0-9]{0,})\/([A-z0-9]{0,})\/([A-z0-9]{0,})\/([A-z0-9]{0,})\//" , $_GET['params'], $params);
print_r($params);


Метод тестирования:
Время отклика страницы. Тестировалось утилитой Apache Bench запросом вида:
ab -c 10 -n 100000 test.com/param/val/param1/val/param2/val/param3/val


Платформа тестирования:
Мой домашний лаптоп:

kasumi ~ # uname -a
Linux kasumi 2.6.24-tuxonice-r9 #1 SMP Sun Jul 13 02:57:59 Local time zone must be set--see zic i686 Intel(R) Pentium(R) M processor 1.60GHz GenuineIntel GNU/Linux

kasumi ~ # lshw
kasumi
description: Notebook
product: SX10P
vendor: Samsung Electronics
*-cpu
description: CPU
product: Intel(R) Pentium(R) M processor 1.60GHz
*-memory
description: System Memory
physical id: e
slot: System board or motherboard
size: 768MiB
*-disk
description: ATA Disk
product: HTS424040M9AT00
vendor: Hitachi
physical id: 0
bus info: ide@0.0
logical name: /dev/hda
version: MA2OA71A
serial: MPA241Q2DPTHJA
size: 37GiB (40GB)

kasumi ~ # apache2 -v
Server version: Apache/2.2.8 (Unix)
Server built: Jun 13 2008 20:05:00

kasumi ~ # php -v
PHP 5.2.6-pl7-gentoo (cli) (built: Oct 18 2008 13:21:57)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies


Результаты тестирования:

1. PHP Native:
Requests per second: 1570.26 [#/sec] (mean)
Time per request: 6.368 [ms] (mean)
Time per request: 0.637 [ms] (mean, across all concurrent requests)

2. Apache mod_rewrite:
Requests per second: 1579.41 [#/sec] (mean)
Time per request: 6.331 [ms] (mean)
Time per request: 0.633 [ms] (mean, across all concurrent requests)

3. PHP preg_match
Requests per second: 1528.33 [#/sec] (mean)
Time per request: 6.543 [ms] (mean)
Time per request: 0.654 [ms] (mean, across all concurrent requests)

chart

В общем и целом видно, что даже пусть прирост и мизерный, но mod_rewrite работает с регулярным выражением быстрее, чем PHP.
Теги:
Хабы:
+15
Комментарии153

Публикации

Изменить настройки темы

Истории

Ближайшие события

PG Bootcamp 2024
Дата16 апреля
Время09:30 – 21:00
Место
МинскОнлайн
EvaConf 2024
Дата16 апреля
Время11:00 – 16:00
Место
МоскваОнлайн
Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн