Site Tools


mod_rewrite

Добро пожаловать в школу магии и волшебства

Ликбез

Подготавливаем стенд

В virtualHost указываем для дебага всех действий с реврайтами:

      RewriteLog "/var/www/rewrite.log"
      RewriteLogLevel 9

Если сам mod_rewrite не включен, то включаем:

/etc/apache2# cat mods-available/rewrite.load 
LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so

cp mods-available/rewrite.load mods-enabled/

в VirtualHost должно быть: AllowOverride all

Тест 1 - Передаем Get запросы

site.ru/?text=Hello
TO
site.ru/Hello

Создаем тестовый php файл:

<?php
echo $_GET["text"];
?>

Путь запроса site.ru/?text=Hello

Создаем правила в .htaccess:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php\?text=$1 [L]

И можем использоваться site.ru/Hello

  1. - Если уберем %{REQUEST_FILENAME} !-f, то получи 500 ошибку, потому что 4-ая строка создает новый запрос и будут бесконечные редиректы к index.php
  2. - Наш php скрипт будет вызван 2 раза с разными параметрами _только_потому_что_ браузер запрашивает favicon.ico, а мы не обрабатываем эту ситуацию отдельно.

Дебажим

    (3) [perdir /var/www/] strip per-dir prefix: /var/www/Hello -> Hello  #Сначался удалился префикс дирикторий и получили название файла к которому обращаемся
    (3) [perdir /var/www/] applying pattern '^(.*)$' to uri 'Hello' #Прошла проверка, что в RewriteRule, в первом значение разрешается использоваться url Hello
    (4) [perdir /var/www/] RewriteCond: input='/var/www/Hello' pattern='!-f' => matched  #Проверка на отсутствие файла - пройдена
    (4) [perdir /var/www/] RewriteCond: input='/var/www/Hello' pattern='!-d' => matched  #Проверка на отсутствие директории - пройдена
    (2) [perdir /var/www/] rewrite 'Hello' -> '/index.php?text=Hello'  #Применяется правило реврайта
    (3) split uri=/index.php?text=Hello -> uri=/index.php, args=text=Hello   #Парсится строка -> определяется файл и GET аргументы TODO:Кто просил?
    (1) [perdir /var/www/] internal redirect with /index.php [INTERNAL REDIRECT] #TODO: Указывается внутренний редирект. Почему? Из за парсинга? Или из за нового обращения в RewriteRule?
   
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.php -> index.php
    (3) [perdir /var/www/] applying pattern '^(.*)$' to uri 'index.php'
    (4) [perdir /var/www/] RewriteCond: input='/var/www/index.php' pattern='!-f' => not-matched #Парсится на придмет присутствия index.php, находит и более не редиректит. Если бы этого небыло, получили бы ошибку.
    (1) [perdir /var/www/] pass through /var/www/index.php

Тест 2 - Стандартный Rewrite WordPress

TO http://192.168.0.102/2013/07/hello-world/

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L] # не упустить символ "-" который обозначает преобразование к корню сайта
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Дебажим

В админ панели указано:
Month and name http://192.168.0.102/2013/07/sample-post/
Следовательно, все ссылки на сайте такого вида site.ru/2013/07/hello-world/ Запрос: http://192.168.0.102/2013/07/hello-world/

    (3) [perdir /var/www/] add path info postfix: /var/www/2013 -> /var/www/2013/07/hello-world/ #TODO: И зачем это действие?
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/2013/07/hello-world/ -> 2013/07/hello-world/ # убераем базу, оставляя только запрос
    (3) [perdir /var/www/] applying pattern '^index\.php$' to uri '2013/07/hello-world/'
    (3) [perdir /var/www/] add path info postfix: /var/www/2013 -> /var/www/2013/07/hello-world/
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/2013/07/hello-world/ -> 2013/07/hello-world/
    (3) [perdir /var/www/] applying pattern '.' to uri '2013/07/hello-world/'
    (4) [perdir /var/www/] RewriteCond: input='/var/www/2013' pattern='!-f' => matched
    (4) [perdir /var/www/] RewriteCond: input='/var/www/2013' pattern='!-d' => matched
    (2) [perdir /var/www/] rewrite '2013/07/hello-world/' -> '/index.php'
    (2) [perdir /var/www/] trying to replace prefix /var/www/ with /
    (1) [perdir /var/www/] internal redirect with /index.php [INTERNAL REDIRECT]
   
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.php -> index.php
    (3) [perdir /var/www/] applying pattern '^index\.php$' to uri 'index.php'
    (1) [perdir /var/www/] pass through /var/www/index.php

Запрос http://192.168.0.102/index.php

    (3) [perdir /var/www/] strip per-dir prefix: /var/www/ ->
    (3) [perdir /var/www/] applying pattern '^index\.php$' to uri ''
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/ ->
    (3) [perdir /var/www/] applying pattern '.' to uri ''
    (1) [perdir /var/www/] pass through /var/www/
   
    # В запросе выше, после прохождения правил создался запрос на корень сайта, а приоритетно идет index.html которого нет в корне сайта
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.html -> index.html
    (3) [perdir /var/www/] applying pattern '^index\.php$' to uri 'index.html'
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.html -> index.html
    (3) [perdir /var/www/] applying pattern '.' to uri 'index.html'
    (4) [perdir /var/www/] RewriteCond: input='/var/www/index.html' pattern='!-f' => matched
    (4) [perdir /var/www/] RewriteCond: input='/var/www/index.html' pattern='!-d' => matched
    (2) [perdir /var/www/] rewrite 'index.html' -> '/index.php'
    (2) [perdir /var/www/] trying to replace prefix /var/www/ with /
    (1) [perdir /var/www/] internal redirect with /index.php [INTERNAL REDIRECT]
   
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.cgi -> index.cgi
    (3) [perdir /var/www/] applying pattern '^index\.php$' to uri 'index.cgi'
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.cgi -> index.cgi
    (3) [perdir /var/www/] applying pattern '.' to uri 'index.cgi'
    (4) [perdir /var/www/] RewriteCond: input='/var/www/index.cgi' pattern='!-f' => matched
    (4) [perdir /var/www/] RewriteCond: input='/var/www/index.cgi' pattern='!-d' => matched
    (2) [perdir /var/www/] rewrite 'index.cgi' -> '/index.php'
    (2) [perdir /var/www/] trying to replace prefix /var/www/ with /
    (1) [perdir /var/www/] internal redirect with /index.php [INTERNAL REDIRECT]
   
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.pl -> index.pl
    (3) [perdir /var/www/] applying pattern '^index\.php$' to uri 'index.pl'
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.pl -> index.pl
    (3) [perdir /var/www/] applying pattern '.' to uri 'index.pl'
    (4) [perdir /var/www/] RewriteCond: input='/var/www/index.pl' pattern='!-f' => matched
    (4) [perdir /var/www/] RewriteCond: input='/var/www/index.pl' pattern='!-d' => matched
    (2) [perdir /var/www/] rewrite 'index.pl' -> '/index.php'
    (2) [perdir /var/www/] trying to replace prefix /var/www/ with /
    (1) [perdir /var/www/] internal redirect with /index.php [INTERNAL REDIRECT]
   
    (3) [perdir /var/www/] strip per-dir prefix: /var/www/index.php -> index.php
    (3) [perdir /var/www/] applying pattern '^index\.php$' to uri 'index.php'
    (1) [perdir /var/www/] pass through /var/www/index.php

Далее: http://habrahabr.ru/company/sprinthost/blog/129560/

Список директив

RewriteEngine on|off Включаем|Выключаем mod_rewrite

RewriteLog

Включаем логирование

RewriteLog "/usr/local/var/apache/logs/rewrite.log" # Указываем полный путь.
RewriteLog "logs/rewrite.log" # Указывыем относительный путь.
RewriteLogLevel Level

Уровень журналирования. Доступно от 0 до 9

RewriteLogLevel 3
RewriteBase

устанавливает конкретный, базовый URL для преобразований в контексте каталога. Пример:

RewriteEngine On
RewriteBase   /xyz
RewriteRule   ^oldstuff\.html$  newstuff.html

Запрос на /xyz/oldstuff.html приводит к /abc/def/newstuff.html
RewriteCond

Проверка условия (соответствие правой и левой части) после которого идет действия (Грубо говоря “IF”)
Поддерживает большое количество переменный и т.д.
Синтаксис:

RewriteCond [String] [String2] [NC,OR]

OR → Проверяет несколько правил для одного действия и если одно из них верно, выполняет действие.
NC → Не чувствительно к регистру

Примеры:

RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
RewriteRule  ^/$                 /homepage.max.html  [L]
RewriteCond  %{HTTP_USER_AGENT}  ^Lynx.*
RewriteRule  ^/$                 /homepage.min.html  [L]
RewriteRule  ^/$                 /homepage.std.html  [L]

Rewrite flags

[L]|last

Завершить обработку mod_rewrite

Цикл хоть и прекращается, но в оригинали описана опасность повторного входа в цикл. Подробнее в оригинале
Для полного завершения всех циклов, можно использовать [END]

[NC]|nocase

Не обращать внимание на регистр.

[NE]|noescape

Запрещаем преобразование спец символов в hexcode

RewriteRule ^/anchor/(.+) /bigpage.html#$1 [NE,R]

/anchor/xyz будет преобразовано в /bigpage.html#xyz
без [NE] это будет преобразовано в /bigpage.html%23xyz

[NS]|nosubreq

Запрещаем подзапросы.
Подзапросом являютяся:

  • Подключение страницы по SSI

Что не является подзапросом:

  • Запрос картинок, JS, CSS и т.д. так как отдельный HTTP запрос.
[PT]|passthrough

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

Обработка GET запросов

используется QUERY_STRING

RewriteCond %{REQUEST_URI} ^/test.php [NC]
RewriteCond %{QUERY_STRING} ^u=(.*)&id=(.*)&img=(.*)
RewriteRule (.*) http://app.foo.com/%2-%1-%3.test? [R=301,L]

Now it give me that link :
http://app.foo.com/12345-s1-12.test?u=s1&id=12345&img=12
Instead of :
http://app.foo.com/12345-s1-12.test

Принудительная завершения обработки

http://habrahabr.ru/post/75885/

RewriteCond %{ENV:REDIRECT_FINISH} !^$ // Проверка переменной 
RewriteRule ^ - [L]                    // Если переменная установлена, то изменить исходный на исходных url, тем самым завершив их обработку.

AddDefaultCharset utf-8
RewriteCond %{QUERY_STRING} ^p=(.*)$
RewriteRule .* - [R=404,L,E=FINISH:1] //Тут E=FINISH:1 установит переменную в следствии которой все завершится.

Только одна интерация для всего

RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule .* — [L]

Создание рандомных переменных $_SERVER и их замена

RewriteRule .* - [E=AWESOME_VAR:%{HTTP_USER_AGENT},L]
RewriteRule .* - [E=AWESOME_VAR:True,L]

Символ /

RewriteRule ^dir/file$ index.php [R=301]

Готовые решения

С www на 0
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.mshopping\.ru [NC]
RewriteRule ^(.*)$ http://mshopping.ru/$1 [L,R=301]
С 0 на www
RewriteEngine On
RewriteCond %{HTTP_HOST} ^volgo-rielt.ru
RewriteRule (.*) http://www.volgo-rielt.ru/$1 [R=301,L]
С http на https
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://site.ru/$1 [L,R=301]

Альтернатива: (не всегда работает)

RewriteEngine On
RewriteCond %{HTTP:SSL} !=on 
RewriteRule ^(.*)$ https://www.site.ru/$1 [R=301]
Редирект в случае отсутствия файла
RewriteBase   /
RewriteCond /home/u113509/conovaloffru/rewrite/%{REQUEST_FILENAME} !-f
RewriteRule ^(.+) http://ya.ru/
Реврайт для создания поддомена
RewriteEngine On
RewriteCond %{HTTP_HOST} ^test\.site\.ru [NC]
RewriteCond %{REQUEST_URI} !^/test/(.*)?$ [NC]
RewriteRule ^(.*)$ /test/$1 [L]
C index.html на главную
RewriteEngine On
RewriteBase /
RewriteRule index.html / [R=301,L]
c / на определенную странцу

Просят сделать с http://site.ru/ скрытый редирект на http://site.ru/index.php?post_type=tribe_events [L]

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/$ #Если нет обращений к файлам
RewriteCond %{QUERY_STRING} ^$ #Если не передаются GET параметры
RewriteRule ^(.*)$ /index.php?post_type=tribe_events [L]
Установка переменной PROTOCOL
RewriteRule ^(.*)$ - [E=PROTOCOL:http]
RewriteCond %{HTTPS} ^on$ [NC]
RewriteRule ^(.*)$ - [E=PROTOCOL:https]
RewriteCond %{HTTP_COOKIE} !login=mylogin [NC] #Если такой куки нет, то forbiden
RewriteRule .* - [F]
Блокировка по User-Agent
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "Mozilla/4\.0 \(Windows 98; US\) Opera 10\.00 \[en\]"
RewriteRule .* - [F,L]
не применять правила к директории pmma
RewriteRule ^pmma - [L] #В самом начале .htaccess
Пример реализации WildCard в mod_rewrite с переадресацией во внутренние директории

Пример использования

tester.site.ru ->
site.ru/users/tester

tester.site.ru/somedir/ ->
site.ru/users/tester/somedir/

paul.site.ru ->
site.ru/users/paul

Пример реализации

RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule .* - [L]

RewriteCond %{HTTP_HOST} !www\.site\.ru$ [NC]
RewriteCond %{HTTP_HOST} ^(www.)?([a-z0-9-]+).site\.ru [NC]
RewriteRule (.*) /users/%2/$1/ [L]

Discussion

Constantin Conovaloff, 2015/09/08 16:45

Пример бесконечного редиректа

You could leave a comment if you were logged in.
mod_rewrite.txt · Last modified: 2015/08/19 13:58 by conovaloff

Page Tools