HOWTO: .htaccess + mod_rewrite + RewriteCond + RewriteRule + regex

Аватар пользователя ˛ ˛ 15 октября 2006 в 2:30

см.начало обсуждения

поясню пример:
RewriteRule [^/.]/feed urllist.txt
мы имеем регулярное выражение в левой части: [^/.]/feed
и выражение замены url в правой: urllist.txt

В квадратных скобках стоит character set, т.е. набор символов.
Набор (сам по себе) обозначает один единственный символ.
Символы внутри набора задают правило, которому должен соответствовать символ.
Крышка, поставленная вначале набора означает, что набор соответсвует любому символу, кроме перечисленных в наборе после крышки.
Т.е., в данном примере, это любой символ кроме слэша или точки.
Следовательно перенаправление на urllist.txt будет всякий раз когда на конце встречается /feed, за исключением двух случаев:
когда на конце //feed (например http://feed)
и когда на конце ./feed (например ../feed)

А теперь рассмотрим стандарное дрюпаловское RewriteRule:

<IfModule mod_rewrite.c>#если включен mod_rewrite
  RewriteEngine on      #включить движок Rewrite
  RewriteCond %{REQUEST_FILENAME} !-f #применять RewriteRule, только если запрашиваемое имя файла не совпадает с именем какого-нибудь реального файла на сервере
  RewriteCond %{REQUEST_FILENAME} !-d #и не совпадает с именем какой-нибудь реальной директории
  RewriteRule ^(.*)$ index.php?q=$1 [L,QSA] #а вот это правило рассмотрим подробнее ниже
</IfModule>



Левая часть: ^(.*)$
Крышка вначале означает начало строки.
Бакс в конце означает конец строки.
Точка в скобочках означает любой символ.
Звездочка после точки означает, что любых символов может быть от одного до бесконечности.
Скобочки означают группу. Т.к. она первая (и единственная), то эта группа идет под номером 1.

Правая часть: index.php?q=$1
означает, что мы перезаписываем url на index.php?q= и к этому добавляем первую группу $1, т.е. имя запрашиваемого файла.

Немного о точках и крышках.
В первом примере точка обозначала точку, потому что она была внутри набора символов.
Во втором примере точка обозначала любой символ, потому что она была вне набора символов.
В первом примере крышка играла роль оператора исключения.
Во втором примере крышка обозначала начало строки.

Флаги [L,QSA]
цитата с http://www.egoroff.spb.ru/portfolio/apache/mode_rewrite.html, которую порекомендовал Alex:
'last|L' (последнее правило)
Остановить процесс преобразования на этом месте и не применять больше никаких правил преобразований. Это соответствует оператору last в Perl или оператору break в  языке C. Используйте этот флаг для того, чтобы не преобразовывать текущий URL другими, следующими за этим, правилами преобразований.

'qsappend|QSA' (query string append - добавлять строку запроса)
Приплюсовать то, что идет после знака вопроса. Например, если урла была такая, http://mysite.com/node/1?size=_original, то в броузере останется такой-же, но скрипту пойдет в таком виде: http://mysite.com/index.php?q=/node/1?size=_original

Кстати, Алекс советовал менять урлы не в .htacess, а через conf_url_rewrite(), правда в v.4.7.* этой функции нет, поэтому лучший способ - прислушаться к совету Гарамонда и подправить модуль pathauto, который в пятой версии друпала будет в стандартом дистре.

А теперь, что касается поставленных задач:
1. добавить .html ко всем ссылкам
Ответ: если это сделать через .htaccess+mod_rewrite, то ссылки дрюпал всё-равно будет выдавать без .html, хотя открытые странички будут красоваться с .html в конце адреса. Это называется внешний редирект (о котором узнает броузер).
Поэтому лучше использовать pathauto, как посоветовал garamond.

2. изменить node на что-нибудь другое (интересно, а зачем Вам это нужно?). Собственно почти ни чем объективно не отличается от первой задачи, за исключением одной важной мелочи.
Но давайте поупражняемся с RewriteRule. Заменим node на girl.

<IfModule mod_rewrite.c>
  RewriteEngine on
 
  RewriteRule ^girl/(.*)$ node/$1
 
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
</IfModule>



набираем в броузере http://mysite.com/girl/1 и любуемся - нам отобразился 1-й узел!

но толку от этого мало, ведь все ссылки в друпале остались вида node/1 и если мы щелкнем по одной из них, то опять увидим node/1 в строке адреса.
Как же сделать, чтобы отображалось girl/1 ?
Переписать из node в girl с флагом [R] (внешний редирект)

RewriteRule ^node(.*)$ /girl$1 [R,L]

Собственно с таким рулем пути типа http://mysite.com/node/1 будут переделвываться в http://mysite.com/girl/1.

Но при этом мы не увидим 1-й узел, вместо него мы увидим главную страницу. Это потому что дрюпал не получил поле 'q'.

Следовательно надо добавить директиву RewriteRule, которая будет переделывать из girl/1 в ?q=node/1, но это не должно отобразиться в броузере:

<IfModule mod_rewrite.c>
  RewriteEngine on
 
  RewriteCond %{REQUEST_FILENAME} node.*
  RewriteRule ^node(.*)$ /girl$1 [R]
 
  RewriteCond %{REQUEST_FILENAME} girl.*
  RewriteRule ^girl(.*)$ index.php?q=/node$1 [L,QSA]
 
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !node.*
  RewriteCond %{REQUEST_FILENAME} !girl.*
  RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
</IfModule>



Можно нас поздравить, теперь 'ненавистный' node не увидишь в строке адреса, на его месте красуется girl.

Однако все ссылки drupal генерит с node! Их видно в строке состояния, в исходном тексте и т.д. Не говоря уже о том, что .htaaccess добавил нагрузку на сервер! Мы проделали этот трюк исключительно для изучения mod_rewrite, реально так изменять ссылки не рекомендуется, ведь можно же подправить модуль pathauto.

Комментарии

Аватар пользователя B.X B.X 15 октября 2006 в 3:06

спасибо за обстоятельное howto, а то инструкций иного, а применить их сложно...
кстати, а pathauto разве не добавляет нагрузки на сервер? или на php? ведь там всё равно идёт замена стандартного node...
и вот, кстати, есть такой модуль [url=http://drupal.org/project/globalredirect]Global redirect[/url], что можно сказать про него? он вроде тоже всё перенаправляет, только делает это немного по-другому...

Аватар пользователя ˛ ˛ 15 октября 2006 в 9:14

как говорится - незачто Smile
pathauto ресурсы жрет, как и все на этом свете. А какой толк менять через .htacces - если в html-коде у Вас ссылки будут выглядеть по-прежнему? Лучше использовать Global redirect или pathauto. Про Global redirect ничего сказать не могу - никогда не устанавливал. В любом случае, при редиректе через .htaccess сайт впадает в зависимость от броузера посетителя (при использовании флага [R]) - поддерживает он редирект - или нет, или он просто отключен.

Аватар пользователя lalex lalex 21 мая 2007 в 18:07

pathauto сейчас работает довольно грамотно, если не жать правда некоторые настройки (особенно в 4.7)

то автор поста: в каком месте pathauto стал в дистре 5го друпала?

Аватар пользователя Oleksandr Oleksandr (не проверено) 20 мая 2007 в 19:07

Привет, нужна помощь в переписании урла с точкой между группами (.*) . (.*)

из такого
index.php?abc=ABC&xyz=XYZ

в такой
ABC.XYZ

это
RewriteRule (.*).(.*)$ index.php?abc=$1&xyz=$2 [L]
и это
RewriteRule (.*)\.(.*)$ index.php?abc=$1&xyz=$2 [L]
не работает

Можно ли вообще использовать точку?
Спасибо

Аватар пользователя Гость Гость (не проверено) 21 мая 2007 в 16:43

Учиться и еще раз учиться.
В данном случае на тему "регулярные выражения"

Аватар пользователя Oleksandr Oleksandr (не проверено) 8 июня 2007 в 22:53

"Учиться и еще раз учиться.
В данном случае на тему "регулярные выражения""

Так и помогите научиться, если знаете!
спасибо

еще вопрос
как можно из index.php?abc=ABC сделать http://домен.com/ABC ?

Если сложно помочь на конкретные вопросы, дайте конкретную ссылку на инфу на русском желательно

Спасибо еще раз!

Аватар пользователя gfedin gfedin 25 июля 2007 в 18:39

господа подскажите!!! Вы знаете!! Старался прикрутить gallery 2 к Drupal 5 все вроде сделал но есть одна заковыка!!

Вот есть .htaccess в нем есть строка

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

Я добавляю

RewriteBase /http://www.photografia.ru/

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} gallery\_remote2\.php
RewriteCond %{REQUEST_URI} !/http://www.photografia.ru/$
RewriteRule . - [L]

И сразу ссылка node/1 перстает работать!! Что надо править откуда ноги растут тут! ????

Аватар пользователя Ne_L Ne_L 8 октября 2009 в 2:04

Помогите отыскать ошибку:

Пример - хочется поменять пути :

с http://мойсайт.ру/category/2/703/22/34/55
на http://мойсайт.ру/category/2/55
то есть убрать все лишние подкатегории (а их может быть различное количество), оставив только последнюю

в существующий .htaccess файл в корне установки друпала дописал строчку
RewriteRule ^category/2/([0-9\/]+)/([0-9]+)$ category/2/$2 [QSA]

но результата нет.

Что я не так сделал?

Спасибо.

upd:
переместил свою команду RewriteRule выше команд RewriteCond которые шли в комплекте с друпалом - заработало.
Но! в поле адреса по прежнему пишется старый адрес, в то время как содержимое отображается доступное по новому адресу.

Вопросы:
почему порядок команд имеет значение в данной ситуации?
как сделать чтобы адрес в строке браузера тоже менялся со старого на новый?

Спасибо.

Аватар пользователя Mascher Mascher 29 января 2010 в 8:16

Возникла проблема, которую не смог решить сам.
Был у меня на сайте форум по ссылке http://my.site/forum
Перенес я форум на другое доменное имя и сделал статью, по тому же адресу где был форум http://my.site/forum .

В файле .htaccess сделал следующее правило:
RewriteRule ^forum/?(.*) /forum [R=301,L]

Но, при заходе на ссылки типа http://my.site/forum/index.php или http://my.site/forum/viewforum.php?f=37 не переадресуется на мою статью http://my.site/forum
Пробовал много разных правил, так и не заработала переадресация...