Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  

Название темы: mod_rewrite etc.
Показать сообщение отдельно

Аватара для vadimiron

Ветеран


Сообщения: 1864
Благодарности: 120

Профиль | Отправить PM | Цитировать


Делать мне было нечего и решил я по данной теме маленькую статью накатать
Надеюсь кому нибудь поможет.
Ссылки на официальный мануал (перевод на русский):
Мануал
Ну сначало, проверьте, установлен ли этот модуль у вас. Внимание: это спец модуль к апачу, с другими серверами он *не работает.
Все команды данного модуля пишуться в файл .htaccess, причём если уже что то в данном файле стоит, то можно смело писать со следущей строки.
Команды модуля состоят из определённых директив, вот они :
RewriteEngine
RewriteBase
RewriteCond
RewriteLock
RewriteLog
RewriteLogLevel
RewriteMap
RewriteOptions
RewriteRule
Скажу честно, что не всеми директивами я пока владею, но всё основное сейчас опишу.
Начинается вся красота с включения модуля
Код: Выделить весь код
RewriteEngine on
Эта первая строчка, которая должна присутствовать, чтобы модуль заработал, причём если далее следует много различных директив, достаточно поставить RewriteEngine off, чтобы деактивировать действие всех команд, не надо при этом комментировать все строчки.
Вторая обязательная строчка, без которой механизм преобразований работать не будет:
Код: Выделить весь код
Options +FollowSymlinks
Если ваш системный администратор запрещает Вам использование «Options +FollowSymlinks», Вы не сможете ограничить использование mod_rewrite для отдельных каталогов, вместо этого изменения будут действовать на весь сервер.
Следущей обязательной командой нужно определить базовый URL (область) работы модуля, этим занимается директива RewriteBase:
Код: Выделить весь код
RewriteBase /
"/" эквивалентно http://yoursite.com, но можно конечно и другой базовый URL указывать(например, когда URL'ы НЕ прямо соответствуют физическим путям, но об этом подробнее в официальном мануале)
Следущая интересная директива это RewriteLog, как ни сложно догадаться, она служит для определения файла ведения логов работы модуля. Пример из мануала:
Код: Выделить весь код
RewriteLog "/usr/local/var/apache/logs/rewrite.log"
Раз уж говорим про ведение журнала, то ещё одна директива по этому поводу: RewriteLogLevel а, причём а равно от 0 до 9, где 0=журнализация не ведётся, 9=записываються почти все действия модуля.
Ну а теперь самое интересное: директива RewriteRule-она как раз занимается обработкой и перезаписью урлов (и не только этим).
На каждое правило пишется свой RewriteRule. Также очень важен порядок, надо следить, чтобы второй RewriteRule не испортил работу первого RewriteRule, то есть чтобы они не пересекались.
В общем виде выглядит это так:
Код: Выделить весь код
RewriteRule шаблон действие
Шаблон-это "нормальный урл", который мы ищем для обработки. Шаблон основан на ПЕРЛ-совместимых регулярных выражениях. Действием же может быть "новый урл", то есть тот урл, который мы хотим получить в результате обработки, или какой нибудь флаг (будут ниже рассмотрены).
Также следует отметить, что в RewriteRule и RewriteCond(следует ниже) можно использовать переменные сервера (%{VARNAME}) (их полный список в официальном мануале).
Ну теперь перейдём к простому примеру:
Код: Выделить весь код
RewriteRule ^file.ext$ - [F]
^ якорь начала строки
$ якорь конца строки
file.ext какой то любой файл
[F] флаг, обозначающий запрещение.
То есть вся строка обозначает, что при вызове данного файла будет выдана ошибка номер 403.
Следущий пример: перед нами стоит задача-вместо такого урла topic.cgi?forum=20&topic=1089, получать такой topic.cgi/20/1089
Код: Выделить весь код
RewriteRule ^topic\.cgi/(\d{,2})/(\d{,5})$ topic.cgi?forum=$1&topic=$2
Сначало замечу: то, что в шаблоне пишеться в скобках, используется потом в качестве переменных в действии (в порядке возникновения скобок получаем $1, $2, $3 ....).
Теперь как действует предыдущий пример: есть например такой запрос topic.cgi/20/1089, данная строка сверяется с шаблоном и если строка совпадает с шаблоном, что и происходит в нашем случае, урл трансформируется в topic.cgi?forum=20&topic=1089 и далее идёт вызов именно этого урла.
20 в нашем случае = $1 ( то есть(\d{,2}) ), а 1089-$2 ( то есть(\d{,5}) ).
Ещё один пример: мы перенесли папку soccer из корня сайта в папку sport, и не хотим переписывать все ссылки (ну и ссылки в избранном юзеров мы не сможем поменять)
Код: Выделить весь код
RewriteRule ^soccer/(.*)$ sport/soccer/$1
(.*) равно $1 и обозначает любые знаки в любом количестве, так как вряд ли вызывается просто папка, наверняка какой нибудь файл из даной папки со своими переменными и тд.

Следует отметить, что RewriteRule не так часто употребляется в одиночестве, чаще его действие ограничивается условием, когда может выполняться данный RewriteRule. Условие выполнено в виде отдельной директивы RewriteCond. Главное здесь, что условие должно быть прописано перед правилом. На одно правило может приходится несколько условий (все эти условия должны быть выполнеными, чтобы перейти к выполнению правила, но также условия можно связать словом "или"-для этого в конце каждого условия, кроме последнего, ставится флаг [OR]).
В общем виде условие выглядит так: RewriteCond СравниваемаяСтрока Условие
СравниваемаяСтрока в 99% выражается серверной переменной (но также может быть простым текстом с использованием например переменной($1, $2, $3...), созданной в правиле, к которому относится данное условие), условие же это шаблон, то есть регулярное выражение с некоторыми дополнениями. Данные дополнения выписываю просто из мануала:
'<Условие' (лексически меньше)
Условие считается простой строкой и *лексически сравнивается с СравниваемаяСтрока. Истинно если СравниваемаяСтрока лексически меньше чем Условие.
'>Условие' (лексически больше)
Условие считается простой строкой и *лексически сравнивается с СравниваемаяСтрока. Истинно если СравниваемаяСтрока лексически больше чем Условие.
'=Условие' (лексически равно)
Условие считается простой строкой и лексически сравнивается с СравниваемаяСтрока. Истинно если СравниваемаяСтрока лексически равно Условие, т.е. эти две строки полностью одинаковы (символ в символ). Если Условие имеет вид "" (два знака дюйма идущих подряд) это сравнивает СравниваемаяСтрока с пустой строкой.
'-d' (является ли каталогом)
СравниваемаяСтрока считается путем, проверяется существование этого пути и то что этот путь является каталогом.
'-f' (является ли обычным файлом)
СравниваемаяСтрока считается путем, проверяется существование этого пути и то что этот путь является обычным файлом.
'-s' (является ли обычным файлом с ненулевым размером)
СравниваемаяСтрока считается путем, проверяется существование этого пути и то что этот путь является обычным файлом, размер которого больше нуля.
'-l' (является ли символической ссылкой)
СравниваемаяСтрока считается путем, проверяется существование этого пути и то что этот путь является символической ссылкой.
'-F' (проверка существования файла через подзапрос)
Проверяет через все списки контроля доступа сервера, существующие в настоящий момент, является ли СравниваемаяСтрока существующим файлом, доступным по этому пути. Для этой проверки используется внутренний подзапрос, поэтому используйте эту опцию с осторожностью *— это отрицательно сказывается на производительности сервера!
'-U' (проверка существования URL через подзапрос)
Проверяет через все списки контроля доступа сервера, существующие в настоящий момент, является ли СравниваемаяСтрока существующим URL, доступным по этому пути. Для этой проверки используется внутренний подзапрос, поэтому используйте эту опцию с осторожностью *— это отрицательно сказывается на производительности сервера!

Пример
Код: Выделить весь код
RewriteCond %{REMOTE_ADDR} ^212.37.64.23$
RewriteRule ^.*$ - [F]
Если REMOTE_ADDR равен 212.37.64.23, то ставим запрет на любой запрос, исходящий с данного айпи

Код: Выделить весь код
RewriteCond %{REMOTE_HOST} ^www.somesite.com$
RewriteRule ^.*$ page.html
Всех, пришедших по ссылкам, расположенным на сайте www.somesite.com, перенаправляем на страницу page.html

Код: Выделить весь код
RewriteCond %{REQUEST_URI} !uri1
RewriteCond %{REQUEST_URI} !uri2
RewriteCond %{REQUEST_URI} !uri1
RewriteRule ^([a-zA-Z0-9_-]{3,40})$ user.php?user=$1
Если ури не равен uri1, uri2 или uri3, то переписываем данный ури ([a-zA-Z0-9_-]{3,40}-это я так данный ури выразил) как user.php?user=$1 (вместо $1 можно было бы написать %{REQUEST_URI}, по сути получается то же самое)

Вроде, если в кратце рассказывать-это всё.
Ещё пару интересных примеров, которые я нашёл на различных сайтах:
Пример 1
Код: Выделить весь код
Цель – показать посетителям «фото дня». Посетитель, кликнувший по ссылке http://yoursite.com/pic.html увидит лучшую 
фотографию или картинку дня, и так каждый день. Мы будем работать с серверными переменными:
TIME_MON 
TIME_DAY
Поместим в файл .htaccess одну единственную строку:
RewriteRule ^pic.html$ pic-%{TIME_MON}-%{TIME_DAY}.html
Запрашиваемый URL будет перезаписан, например:
pic-08-28.html 
pic-08-29.html 
pic-08-30.html 
и так далее.
Теперь, все что вы должны сделать – это единожды загрузить файлы с соответсвующими именами и 
забыть о ежедневном обновлении ссылки. Переменные времени также могут использоваться для другой периодичности.
Пример 2
Код: Выделить весь код
Проблема отсутствующего завершающего слэша
Описание:
Каждый вебмастер может спеть песню о проблеме отсутствующих завершающих слэшей при использовании URL ссылающихся на каталоги. 
Если они отсутствуют, сервер выдает ошибку, потому что если вы пишете /~quux/foo вместо /~quux/foo/ сервер ищет файл foo. 
И поскольку этот файл является каталогом, происходит ошибка. В действительности, в большинстве случаев это исправляется само, однако, 
в некоторых случаях, нужно самим эмулировать этот механизм. 
Например, после того, как вы сделали массу сложных редиректов URL на CGI скрипты и т.д.

Решение:
Решение этой тонкой проблемы — это позволить серверу добавлять завершающий слэш автоматически. 

Чтобы сделать это правильно, мы должны использовать внешний редирект, для того чтобы браузер правильно запрашивал картинки и пр. 
В случае если бы мы *сделали только внутренний редирект, это бы работало только для самой страницы каталога (страницы по-умолчанию), 
однако были бы проблемы при наличии любых картинок на этой странице с относительными URL,
 потому что браузер сделал бы запрос на вставку in-lined объекта. Например, запрос для image.gif на странице /~quux/foo/index.html
без внешнего редиректа выглядел бы как /~quux/image.gif!

Поэтому, для того чтобы сделать это трюк, мы пишем:

RewriteEngine *on
RewriteBase * */~quux/
RewriteRule * *^foo$ *foo/ *[R]

Сумашедший и ленивый может даже сделать следущее в *файле .htaccess находящемся в корне веб-пространства своего сайта. 
Однако, следует отметить, что это создает некоторые накладные расходы.

RewriteEngine *on
RewriteBase * */~quux/
RewriteCond * *%{REQUEST_FILENAME} *-d
RewriteRule * *^(.+[^/])$ * * * * * $1/ *[R]
Пример 3
Код: Выделить весь код
Поиск страниц больше чем в одном каталоге
Описание:
Иногда необходимо позволить веб-серверу искать страницы больше чем в одном каталоге. Здесь вам не помогут ни MultiViews ни *другие техники.

Решение:
Мы пишем явный набор правил который ищет файлы в каталогах.

RewriteEngine on

# * во-первых попытаемся найти это в указанном месте/...
# * ...и если нашли то заканчиваем поиск и сидим и радуемся:
RewriteCond * * * * /your/docroot/dir1/%{REQUEST_FILENAME} *-f
RewriteRule *^(.+) */your/docroot/dir1/$1 *[L]

# * во-вторых - попытаемся найти это в pub/...
# * ...и если нашли то заканчиваем поиск и сидим и радуемся:
RewriteCond * * * * /your/docroot/dir2/%{REQUEST_FILENAME} *-f
RewriteRule *^(.+) */your/docroot/dir2/$1 *[L]

# * иначе продолжаем для других директив Alias или ScriptAlias,
# * и т.д.
RewriteRule * ^(.+) *- *[PT]
Короче ещё много чего можно придумать

И наполедок ещё две директивы: RewriteMap и относящиеся к ней RewriteLock. Директива RewriteMap-ассоциативный массив преобразований, который может быть использован в правилах преобразований и использующий соответствующие функции для вставки/извлечения элементов, для поиска по ключу соответствующих значений. Источник этого поиска может иметь различный тип. Но я этим не умею пользоваться, подробности смотрим в мануале.

[s]Исправлено: Prisoner, 3:43 29-08-2004[/s]

-------
Fortes fortuna adiuvat

Это сообщение посчитали полезным следующие участники:

Отправлено: 00:34, 17-08-2004 | #7

Название темы: mod_rewrite etc.