mod_rewrite — просто о сложном

    Что это такое?


    mod_rewrite — это модуль для веб-сервера Apache, предназначенный для преобразования URL-ов. Модуль использует в своей работе правила, которые могут быть описаны как в конфигурации сервера (httpd.conf), так и в файлах .htaccess непосредственно в файловой структуре Вашего сайта. Правила описываются в виде регулярных выражений PCRE

    Hello world


    Простейший пример. Допустим, Вы захотели, чтобы никто не знал, что Ваш сайт написан на PHP и решили замаскировать расширения файлов. Можно, конечно, внести соответствующую директиву в конфигурацию Apache и тогда все файлы с расширением ".msl" («My Super Language») будут обрабатываться интерпретатором PHP. Но можно поступить проще:
    создаем в корне нашего сайта файл .htaccess со следующим содержимым
    RewriteEngine On
    RewriteBase /
    RewriteRule ^(.*)\.msl$ $1.php [QSA,L]


    Первая директива включает механизм mod_rewrite в текущей папке и во всех ее подпапках. Вторая указывает модулю mod_rewrite, что текущая папка в файловой системе соответствует корню сайта. Третья — непосредственно правило преобразования URL.

    Прочесть его можно так:
    Если сразу после начала строки ("^") идет произвольное количество любых символов ( "(.*)" ), причем мы хотим запомнить, что именно это за символы, окружая их скобками, затем идет точка ("\.") (экранируем точку, потому что одиночная точка — это просто любой символ), затем символы «msl» и на этом строка заканчивается ("$"), то заменим исходный URL на следующий: возьмем первую запомненную подстроку в скобках из правила, прибавим к ней ".php", добавим все дополнительные параметры адреса, которые могли быть "[QSA]" и на этом закончим, не будем применять дальнейшие преобразования, если они есть "[L]"

    Все, теперь Вы можете смело менять все ссылки, заканчивающиеся на ".php" на ".msl" и писать в своем блоге, что изобрели новый скриптовый язык. Apache, встретив ссылку на «index.msl» с помощью mod_rewrite на лету преобразует ее в «index.php» и вызовет нужный скрипт.

    А что еще умеет mod_rewrite?


    О, этот модуль умеет многое. Лично я жду, когда же кто-нибудь достаточно продвинутый в магии и PCRE напишет «Морской бой» на mod_rewrite.

    Но пока этого не случилось, покажу еще несколько вариантов использования этого замечательного модуля.

    Предположим, что Вы решили написать движок для блогов. Каждый пользователь будет иметь возможность создать свой блог, выбрать для него имя, писать в свой блог и читать чужие записи.

    Первичная фильтрация данных

    Предположим, что адреса пользовательских блогов будут иметь вид "/blogs/ABC/", а скрипт, который будет показывать ленту записей определенного блога, будет называться «viewblog.php».
    Несложное правило mod_rewirte позволит нам отсеять некорректные имена блогов, которые могут использовать злоумышленники:
    RewriteRule blogs/([a-z0-9_-]+)([\/]{0,1})$ viewblog.php?blogname=$1 [L]
    RewriteRule viewblog.php - [F]


    В квадратных скобках, в соответствии с синтаксисом PCRE, мы задаем класс символов, включая в него цифры, буквы латинского алфавита, минус и знак подчеркивания. Все адреса, в которых будут какие-то другие символы, не пройдут проверку этим правилом и приведут к ошибке 404. Флаг [L] необходим, чтобы движок mod_rewrite, успешно сделав преобразование, не пошел далее, на второе правило. Этот флаг аналогичен оператору break внутри цикла.

    Второе правило не задает напрямую преобразование адреса (символ "-"), а запрещает прямой доступ к скрипту viewblog.php (флаг "[F]"), тем самым закрывая злодеям возможность передать в параметрах что-то вредоносное.

    Кстати:
    Хорошим тоном будет начинать Ваши правила со строчки
    RewriteRule .htaccess - [F]
    Это запретит доступ к файлу .htaccess в случае дурно настроенного хостинга.


    Использование для кэширования в ФС

    Предположим, что Ваш проект растет. Хостинг перестает справляться с нагрузками — сотни блоггеров, десятки тысяч просмотров их блогов, да еще и комментарии…

    И тут mod_rewrite может придти на помощь, если по каким-то причинам Вы не хотите переходить на свой сервер.

    Во-первых, модифицируйте свой скрипт viewblog.php таким образом, чтобы при обращении к нему он не только выдавал сформированную страницу в браузер, но и записывал ее в файловую систему по адресу /blogs/ABC.html

    Проще всего это сделать, использовав функции управления буферизацией. Предположим, что исходный код скрипта viewblog.php выглядит у Вас примерно так:
    <?php
    $blogname = $_GET['blogname'];
    if ( !Blogs::exists($blogname) )
    die("No blog!");

    Blogs::display($blogname);
    ?>


    Применим буферизацию вывода и запишем вывод в файл.
    <?php
    $blogname = $_GET['blogname'];
    if ( !Blogs::exists($blogname) )
    die("No blog!");

    ob_start();
    Blogs::display($blogname);
    $content = ob_get_contents();
    ob_end_flush();

    $f = fopen(_YOUR_SITE_ROOT . "/blogs/" . $blogname . ".html", "w");
    fwrite($f, $content);
    fclose($f);
    ?>


    Теперь остается только немного модифицировать Ваши правила в .htaccess, чтобы получить полноценную систему кэширования контента:

    RewriteRule blogs\/([a-z0-9_-]+)([\/]{0,1})$ blogs\/$1\.html

    RewriteCond %{REQUEST_FILENAME} blogs\/([a-z0-9_-]+)\.html$
    RewriteCond %{REQUEST_FILENAME} !-s
    RewriteRule (.*) viewblog.php?blogname=%1


    В первой строке мы преобразуем URL вида blogs/ABC/ в blogs/ABC.html, таким образом перенаправляя Apache на сгенерированный нами файл кэша страницы.
    Следующие три строки представляют собой одно большое правило. Если идет запрос на blogs/ABC.html и при этом в файловой системе нет такого файла — запрос перенаправляется на скрипт viewblog.php

    Таким образом нам остается только предусмотреть систему своевременной очистки кэша и задача решена.

    Другие применения


    Лично я использую модуль mod_rewrite аналогично последнему примеру для генерации и хранения в ФС превью изображений.

    Очень легко с помощью mod_rewrite делается отображение поддоменов на папки, например forum.localhost.localdomain физически будет находиться в localhost.localdomain/forum, что часто бывает проще для разработчика приложения.

    Незаменим mod_rewrite для ограничения скачивания файлов на файловом хостинге или в магазине цифровых товаров (придется задействовать механизм символических ссылок) или для запрета хотлинкинга (через проверку реферера).

    А вообще — это Вуду :)
    Чертовски интересное Вуду, позволяющее каждый день открывать новые стороны и применения.

    Что еще почитать?


    httpd.apache.org/docs/2.2/mod/mod_rewrite.html
    www.codenet.ru/webmast/php/mod_rewrite.php
    www.egoroff.spb.ru/portfolio/apache/mod_rewrite.html
    regexp.ru
    Поделиться публикацией
    Похожие публикации
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 12
      0
      я понимаю, что это всего лишь пример, но все таки:
      по поводу кэширования, имхо, правильнее кэшировать блог после добавления записи(комментария), нежели при каждом просмотре?
        +2
        Не при каждом, а при первом. Это во-первых. То есть кэш создается тогда, когда он нужен.
        А во-вторых при изменении содержания правильнее сбрасывать кэш, а не создавать его.
          +1
          понял, осознал, буду думать =)
        +2
        Ухнал много нового, спасибо :)
          +1
          >писать в своем блоге, что изобрели новый скриптовый язык
          а это идея!
            0
            Еще можно ссылочку добавить
            http://htaccess.net.ru/
            Нормальный ресурс с доходчивым объяснением.
              0
              Спасибо большое! Я только сейчас понял, что это за страшные ^(.*) и знаки долларов!
              Ещё бы немножко про правила и их совмещение, если переменных несколько, и как их совмещать.
              Ну а так, отличный мануал!
                0
                Читайте внимательно ru2.php.net/manual/en/reference.pcre.pattern.syntax.php и пребудет с Вами сила!

                А что такое «совмещать переменные» я, честно говоря, не понял.
                  0
                  Тяжело мне разбираться в англоязычных статьях, да и думаю не только мне.
                  Совмещать, что-то вроде index.php?lang=ru&page=home и т.д. Хотя сейчас уже разобрался.
                    0
                    ну а кому сейчас легко, если бы профессора в 20 веке так же говорили бы, когда прокалывали дырочки на перфокартах, мы бы не за компьютерами щас сидели, а за счётами.
                0
                Ахриненно, спасибо, сам не решался разобраться в этих кракозябрах, но терпения не хватало :) а тут
                  0
                  Посоветую защищать файл .htaccess через

                  [Files .ht*]
                  Order Allow,Deny
                  Deny from All
                  [/Files]

                  Т.к. если mod_rewrite выключен, то файлы .ht* будут светиться.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое