Припустимо, у вас є працюючий веб-сайт, що складається з великої кількості статичних html-сторінок . Все йде добре, але раптом у якийсь момент ви вирішуєте удосконалити роботу веб-сайту і додаєте динамічні скрипти: в результаті сторіночка новин тепер доступна по посиланнюhttp://www.site.com/cgi-bin/news. cgiзамість колишньоїhttp://www.site.com/news.html, а каталог, в якому зберігалися сторінки з описом російських регіонів, повністю перекочував у динаміку, і наш гаряче улюблений 77 -й регіон тепер доступний за неестетично виглядає посиланнюhttp://site.ru/cgi-bin/regions.pl?region=77&mode=briefзамість легко запам'ятовуєтьсяhttp://site.ru/regions/77.html.

Подібні зміни потребують заміни відповідних посилань на всіх сторінках вашого веб-сайту, які посилаються на новини та регіони, але це ще квіточки. Основна проблема полягає в тому, що на ці сторінки можуть посилатися інші веб-сайти, про існування яких ви навіть не підозрюєте. Та й відвідувачі вашого веб-сайту могли створити відповідні закладки в своїх браузерах, і тому вони будуть неприємно здивовані, коли замість сторіночки новин отримають помилку "сторінка не знайдена".

Модуль mod_rewrite веб-сервера Apache - це надзвичайна засіб перетворення http -ссилокАналіз проблеми наводить на думку про те, як добре було б мати можливість звертатися до одних і тих же сторінкам за різними http-посиланнях, причому для сторінок зі схожими посиланнями було б дуже зручно описати одне загальне для них правило замість того, щоб для кожної сторінки виписувати всі можливі варіанти провідних на неї http-посилань. Якщо ваш веб-сайт працює під управлінням вельми популярного в даний час веб-сервера * Apache (швидше за все, це саме так), то у вашому розпорядженні є надзвичайна засіб перетворення http-посилань, яке реалізується спеціальним програмним модулемmod_rewrite. Деякі директиви даного модуля можуть використовуватися тільки в конфігураційному файлі самого веб-сервера, інші ж - в спеціальних файлах. Htaccess, які можна розташовувати в підкаталогах ієрархії вашого веб-сайту. Саме ці директиви з. Htaccessі виробляють основну роботу по перетворенню http-посилань, тому їх ми опишемо більш докладно.

Для перестраховки можна уточнити у служби технічної підтримки вашого хостера, чи включений модульmod_rewriteдо складу веб-сервера, обслуговуючого ваш веб-сайт, і чи допускається використання його директив в файлах. htaccess. Оскільки даний модуль широко використовується в багатьох проектах, кожен поважаючий себе хостер на обидва ваших питання відповість: "Так, звичайно". Якщо ж ви отримали негативну відповідь, це гарний привід задуматися про зміну хостинг-провайдера на іншого, надає більш якісні послуги.

Перш ніж заглибитися в опис можливостей модуляmod_rewrite, наведемо приклад рішення двох описаних вище проблем :

# Включення перетворення посилань
RewriteEngine on
# Новинна сторінка
RewriteRule ^ news.html $/cgi-bin/news.cgi
# Сторінки з описами регіонів
RewriteRule ^ regions/([0-9] +) \. html $/cgi-bin/regions.pl? region = $ 1 & mode = brief

Директива RewriteEngine включає або вимикає перетворення http-посилань ДирективаRewriteEngineвключає або вимикає перетворення http-посилань (відповідно "RewriteEngine on" або "RewriteEngine off"). Дія директиви поширюється на поточний каталог і на всі його підкаталоги, у яких немає своїх файлів. Htaccessз даної директиви.

Правила перетворення посилань успадковуються трохи складніше. Найчастіше перетворення за замовчуванням вимкнено в основному конфігураційному файлі веб-сервера. Припустимо, що ви записали в. Htaccessякогось каталогу директиву "RewriteEngine on" і деяка кількість правил перетворення. Перейдемо тепер в один з підкаталогів.

  • Якщо тут немає файлу. Htaccess, або в ньому немає жодної директиви модуляmod_rewrite, то всі правила перетворення успадковуються від батьківського каталогу.
  • Якщо у файлі. htaccessє хоча б одна директива модуляmod_rewrite, то не успадковується нічого, а стан за замовчуванням виставляється таким же, як в головному конфігураційному файлі веб-сервера (за замовчуванням "off"). Тому, якщо ви бажаєте мати в цьому каталозі свій набір правил перетворення, не забудьте додати директиву "RewriteEngine on".
  • Є і третій варіант. Припустимо, ви бажаєте успадкувати всі правила з батьківського каталогу та додати до них кілька нових - для цього вам знадобиться директиваRewriteOptions, яка допускає тільки один фіксований аргумент. Таким чином, у файл. Htaccessви повинні записати ваші нові правила і дві директиви: "RewriteEngine on" і "RewriteOptions inherit".

А тепер перейдемо безпосередньо до опису правил . Перетворення описуються за допомогою директивиRewriteRule. Правил може бути кілька, при цьому всі вони застосовуються в порядку їх опису. Коли правила закінчуються, вони знову починають застосовуватися з самого початку, і цей цикл продовжується до тих пір, поки "спрацьовує" хоча б одне з правил. У деяких випадках це може призводити до зациклення, тому при описі правил потрібно бути гранично уважним. Існує кілька спеціальних прапорів, які надають можливість перервати цей процес на певному правилі або пропустити кілька правил (про це буде розказано нижче). Синтаксис директивиRewriteRuleвиглядає наступним чином:

RewriteRule "вихідний шлях" "заміна" "прапори"

Директиви RewriteRule описують правила перетворення посиланьВихідний шлях- це частина вихідної посилання, від якої відрізані ім'я сервера, шлях до поточного каталогу і параметри запиту. Припустимо, що ваш веб-сайтwww.site.comрозташований в каталозі/home/site/www. Тоді для посиланняhttp://www.site.com/test/list.html?mode=0вихідним шляхом в каталозі/home/site/wwwбудеtest/list.html, а в каталозі/home/site/www/test-list.html. Вихідний шлях задається регулярним виразом (синтаксис регулярних виразів Apache докладно описаний у статті "Маленькі налаштування великого веб-сервера"). Символ!перед вихідним шляхом означає, що правило "спрацьовує" понеспівпадінняпосилання із заданим регулярним виразом.

Заміна- це те, на що буде замінена вихідна посилання в разі "спрацьовування" правила. Заміна може бути відносною (якщо вона не починається з символу/) і абсолютної (якщо вона починається з символу/або являє собою повне посилання, що починається зhttp://абоhttps://). В заміну можна використовувати певні частини вихідного шляху, позначені круглими дужками. При цьому макрос$ 1позначає ту частину вихідного шляху, яка розташована всередині першої пари дужок,$ 2- всередині другої пари і так далі.

Прапори- це додаткові опції для даного правила, які перераховуються в квадратних дужках через кому.

  • R(redirect) зупиняє процес перетворення і повертає результат браузеру клієнта як редирект на дану сторінку (302,MOVED TEMPORARY). З даним прапором можна вказати інший код результату, наприклад "R = 301" поверне редирект з кодом301(MOVED PERMANENTLY).
  • F(forbidden) повертає помилку403(FORBIDDEN).
  • G(gone) повертає помилку410(GONE).
  • P(proxy) - по цьому прапоруApacheвиконує підзапит (sub-request) до зазначеної сторінки з використанням програмного модуляmod_proxy, при цьому користувач нічого не дізнається про це підзапитів. Якщо модульmod_proxyне входить до складу вашої збіркиApache, то застосування даного прапора викличе помилку.
  • L(last) зупиняє процес перетворення, і поточна посилання вважається остаточною.
  • N(next) запускає процес перетворення з першого по порядку правила .
  • C(chain) об'єднує кілька правил в ланцюжок. Якщо перше правило ланцюжка "не спрацьовує", то весь ланцюжок ігнорується.
  • NS(nosubreq) дозволяє "спрацьовування" правила тільки для справжніх запитів, ігноруючи підзапити (підзапит може бути викликаний, наприклад, включенням файлу за допомогою директивиSSI*).
  • NC(nocase) відключає перевірку регістру символів.
  • QSA(qsappend) додає вихідні параметри запиту (query string) дозаміні. Якщо заміна не включає в себе нові параметри запиту, то вихідні параметри запиту додаються автоматично. Якщо ж включає, то без прапораQSAвихідні параметри запиту будуть загублені.
  • PT(passthrough) зупиняє процес перетворення і передає отриману нове посилання далі "по ланцюжку", щоб над нею могли "попрацювати" директивиAlias ??,ScriptAlias ??,Redirectі їм подібні (тоді як при прапоріLнова посилання вважається остаточною і не підлягає подальшій обробці).
  • S(skip) пропускає наступне правило, якщо дане правило "спрацювало".

    Можна пропускати кілька правил, якщо вказати їх кількість, наприклад: "S = 3".
  • E(env) встановлює змінну оточення, наприклад: "E = змінна: значення".

Приклади (у всіх випадках показано вміст файлу. htaccess, розташованого в кореневому каталозі веб-сайту):

# Приклад 1. Каталоги проектів project1 і project2 веб-сайту www.site.com раніше містили статичні html-сторінки, тепер же ці сторінки розташовані на двох окремих веб-сайтах project1.ru і project2.ru (в тій же ієрархії)
# Перший спосіб вимагає наявності модуля mod_proxy і створює додаткове навантаження на веб-сервер, але зате відвідувач веб-сайту не знає, звідки в дійсності вибираються веб-сторінки
# Символи/даються з питальними знаками, щоб правильно обробити посилання виду http://www .site.com/project1 і http://www.site.com/project1/
RewriteRule ^ project1/? (. *) http://project1.ru/$ 1 [P]
RewriteRule ^ project2/? (. *) http://project2.ru/$ 1 [P]
# Другий спосіб повертає зовнішні редиректи, так що відвідувач побачить в адресному рядку свого браузера, що сторінки реально розташовані на інших веб-сайтах
RewriteRule ^ project1/? (. *) http://project1.ru/$ 1 [R]
RewriteRule ^ project2/? (. *) http://project2.ru/$ 1 [R]
# Припустимо, що в редирект ми бажаємо передати в запиті якісь додаткові параметри. Застосування прапора QSA дозволить нам зберегти параметри оригінального запиту, так що посилання http://site.com/project1/news.pl?mode=daily буде перетворена в http://project1.ru/news.pl?came_from=site.com&mode = daily
RewriteRule ^ project1/? (. *) http://project1.ru/$ 1? came_from = site.com [R, QSA]
RewriteRule ^ project2/? (. *) http://project2.ru/$ 1? came_from = site.com [R, QSA]
# Приклад 2. Електронна книга віддається динамічним скриптом в той час як нам бажано мати "красиву" ієрархію виду "http://lib.ru/book1/chapter3.html". До речі, розширення. Html допомагає нам приховувати динамічну природу нашого веб-сайту
RewriteRule ^ ([a-z0-9] +)/([a-z0-9] +) \. Html $/cgi-bin/view_chapter . cgi? book = $ 1 & chapter = $ 2 [NC]
# Приклад 3. Нам бажано приховати від користувача використовувану на веб-сайті технологію, для чого ми не будемо користуватися розширеннями в наших http-посиланнях. Без прапора L дане правило зациклиться
RewriteRule (. +) $ 1.html [L]
# В той же час відвідувач може ввести посилання з розширенням по одному йому зрозумілих причин. Правильно обробити таку ситуацію допоможе наступне правило:
RewriteRule ^ ([^.] +) $ 1.html [L]
# Приклад 4. На веб-сайті є статичні посилання з розширенням. Html і динамічні посилання з розширенням. Pl. Припустимо, що динамічні посилання залишилися колишніми, а статичні повинні оброблятися cgi-скриптом
# Перший варіант гранично простий:
RewriteRule (. +) \. Html $/cgi-bin/new_script.cgi? Page = $ 1 [L ]
# Другий варіант більш загальний. Наприклад, якщо нам потрібно перетворити масу різних посилань крім однієї-двох, можна скористатися спеціальною "заміною без зміни" (позначається символом -):
RewriteRule \. Pl $ - [L]
RewriteRule (. *)/cgi-bin/new_script.cgi? page = $ 1 [L]
# Приклад 5. Є один особливий випадок, коли робиться зовнішній редирект на відносне посилання. Припустимо, ми знаходимося в каталозі/home/site.com/www/test веб-сайту site.com. Каталог доступний за посиланням http://site.com/test/. Нам потрібен зовнішній редірект з файлів *. Html на *. Shtml. Наведені директиви записуються в файл/home/site.com/www/test/.htaccess
# Рішення тривіально, якщо використовувати абсолютну заміну, але в цьому випадку нам доводиться жорстко прописувати назву каталогу, що не зовсім добре:
RewriteRule (. +) \. html/test/$ 1.shtml [R]
# Якщо написати заміну як відносне посилання (див. нижче), то результат буде не таким, яким ми його очікуємо побачити (це обумовлено особливостями перетворення посилань на рівні каталогів): наприклад, посилання http://site.com/test/aaa.html буде перетворена в http://site.com/home/site.com/www/test/aaa.shtml
RewriteRule (. +) \. html $ 1.shtml [R]
# За отриманим посиланням видно, що там підставлений повний реальний шлях до потрібного файлу. Вирішити проблему можна за допомогою директиви RewriteBase, параметром якої є префікс для всіх відносних замін, що знаходяться в цьому файлі. Htaccess
RewriteBase/test
# Приклад 6. Завдання змінних оточення застосовується дуже рідко, але тим не менше наведемо два приклади, не потребують поясненні
# Зберігає в оточенні розширення вихідного файлу
RewriteRule ^ ([^.] +) \. ([Az] +) $/cgi-bin/new_script.cgi? page = $ 1 [L, E = EXT: $ 2]
# Зберігає в оточенні вміст http-заголовка X-Forwarded-For
RewriteRule \. (cgi | pl) $ & mdash ; [L, E =% {HTTP: X-Forwarded-For}]

Директиви RewriteCond призначені для перевірки деяких додаткових параметровНесмотря на такий достаток, перетворення посилань не обмежується тільки директивоюRewriteRule. Є ще одна директива, яка використовується не менш часто - це директиваRewriteCond. Дана директива призначена для перевірки деяких додаткових параметрів і завжди ставиться безпосередньо перед директивоюRewriteRule. Якщо директиваRewriteCond"спрацьовує", то перевіряється наступна за нею директиваRewriteRule, якщо ж "не спрацьовує", то директиваRewriteRuleігнорується.

# Якщо поспіль записано декілька директив RewriteCond, то наступна за ними директива RewriteRule перевіряється тільки в тому випадку, коли "спрацювали" всі директиви RewriteCond:
RewriteCond условіе1
RewriteCond условіе2
RewriteRule преобразованіе1
RewriteRule преобразованіе2
# Слід звернути увагу, що в наведеному вище прикладі Друга директива RewriteRule перевіряється в будь-якому випадку, так як всі директиви RewriteCond відносяться тільки до першої директиві RewriteRule. Якщо ж ви бажаєте, щоб умови ставилися до обох директивам RewriteRule, то вам доведеться повторити їх ще раз:
RewriteCond условіе1
RewriteCond условіе2
RewriteRule преобразованіе1
RewriteCond условіе1
RewriteCond условіе2
RewriteRule преобразованіе2
# Застосування прапора OR дозволяє об'єднувати умови не по І (як це робиться за замовчуванням), а по АБО. У наступному прикладі директива RewriteRule перевіряється, якщо виконується будь-яка з двох попередніх умов:
RewriteCond условіе1 [OR]
RewriteCond условіе2
RewriteRule перетворення

Синтаксис директивиRewriteCondвиглядає наступним чином:

RewriteCond "перевіряється вираз" "умова" "прапори"

перевіряє вираз- це рядок, який може складатися із звичайних символів, макросів і змінних. Макроси$ 1,$ 2і так далі посилаються на відповідні вирази в дужках з наступної по порядку директивиRewriteRule. Макроси% 1,% 2і так далі посилаються на вирази в дужках з попередньою по порядку директивиRewriteCond. До речі, макроси% *можуть також використовуватися і в директивахRewriteRuleдля посилання на попередню директивуRewriteCond.

Змінні записуються у вигляді% {ім'я_змінної}. Найбільш часто використовуються наступні змінні:QUERY_STRING(параметри запиту),REMOTE_ADDR(IP-адреса * відвідувача),REMOTE_HOST(ім'я хоста відвідувача),REMOTE_USER(ім'я користувача, якщо він пройшов до файлу веб-сторінки),HTTP_USER_AGENT(вміст http-заголовкаUser-Agent),HTTP_REFERER(вміст http-заголовкаReferer),HTTP_COOKIE(вміст http-заголовкаCookie),HTTP_HOST(ім'я хоста веб-сайту),TIME_YEAR(всі змінніTIME_ *зберігають розбиті на частини поточні дату і запиту без імені хоста і параметрів запиту),REQUEST_FILENAME(ім'я файлу зREQUEST_URI),THE_REQUEST(повний рядок запиту в тому вигляді, в якому її надсилає браузер відвідувача). Крім стандартних змінних можна перевіряти вміст будь-якого http-заголовка:% {HTTP: Назва-Заголовка}.

Умова- це звичайне регулярний вираз. Крім регулярних виразів існує ще кілька видів умов (умові може передувати символ!, який трактується як заперечення):

  • = ABC- значення змінної повинно бути лексично одно рядкуABC
  • >ABC- значення змінної повинно бути лексично більше рядкиABC
  • - значення змінної повинно бути лексично менше рядкаABC
  • -d- повинен існувати каталог, ім'я якого збігається зі значенням змінної
  • -f- повинен існувати файл, ім'я якого збігається зі значенням змінної
  • -s- повинен існувати файлненульовий довжини, ім'я якого збігається зі значенням змінної
  • -l- повинен існувати сімлінк, ім'я якого збігається зі значенням змінної
  • -F- повинен існувати файл, ім'я якого збігається зі значенням змінної, і цей файл повинен бутидоступний по зовнішньому посиланнюна даний веб-сайт
  • -U- повинна бути доступна http-посилання, ім'я якої збігається зі значенням змінної

Прапорівможе бути лише два:OR(об'єднання директивRewriteCondпоАБО, як було написано вище) іNC(відключення перевірки регістра аналогічно однойменним прапору для директиви Детальніше »