Пример работы с mod_rewrite
03.01.2009Многие веб-разработчики наслышаны про человекопонятные УРЛы (ЧПУ), но до сих пор теряются в том, как это реализуется. Несложно найти в инете примеры mod_rewrite директив, но не всегда понятно до конца как это работает. В данном посте я постараюсь расставить всё по своим местам.
Итак, начнём с того, что реализуется это за счёт модуля Apache под названием mod_rewrite. Для подключения его необходимо создать в корневой папке сайта (например, http://ctepeo.net/) файл с расширением .htaccess (без имени), который в свою очередь и будет сообщать серверу, что для данной папки и вложенных папок правила определяются не общими настройками сервера, а директивами, указанными в нём.
Создали? Продолжим. Откроем данный файл в удобном для Вас текстовом редакторе и начнём добавлять директивы.
RewriteEngine on
RewriteBase /
Первая строчка указывает серверу, что необходимо подключить модуль rewrite (он же mod_rewrite). Вторая строчка указывает путь, относительно которого будут действовать правила переадресаций, то есть, если Вам необходимо реврайтить пути не из текущей директории, а например, из папки test, находящейся в корневой директории сайта, то RewriteBase будет /test/.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
ErrorDocument 404 /index.php
Эти строчки указывают нам на то, что при физическом наличии файла – открывать именно его, в противном случае вызывается ошибка 404 «Документ не найден». Именно в этом месте и начинается трюк. Вместо обычной статичной html странички мы указываем серверу, что нужно показать index.php.
В index.php легко узнать за какой страницей пришёл пользователь (какой УРЛ он вводил), делается это примерно так:
$xurl = explode(‘/’,$_SERVER['REQUEST_URI']);
Эта строчка разбивает строку запроса (Например, http://ctepeo.net/test/myarticle/testme.html) на массив, получая элементы такие как: [0] – ctepeo.net, [1] – test, [2] – myarticle, [3] testme.html. Далее мы зная запрос можем вызывать необходимый нам модуль (Например, сделав запрос в базе по FakeURL (testme) и показав именно страницу testme, хотя физически файла /test/myarticle/testme.html не существует) или отобразить сообщение, что такого файла действительно нету.
Внимание! Для корректной индексации поисковиками в начале php-кода необходимо принудительно указывать header 200 OK. Делается это так:
<?php
Header(«HTTP/1.0 200 OK»);
?>
В некоторых случаях необходимо делать исключения, например, следующая строчка
RewriteRule ^admin/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$ index.php?action=admin [NC,L]
перенаправит все запросы вида /admin/testme/test123/ на index.php с GET action=admin.
Mod_rewrite так же может использоваться и для защиты файлов или директорий от внешних запросов.
RewriteRule ^.config.inc.php$ – [F]
Данная директива будет возвращать ошибку 403 Forbidden при попытке вызывать файл config.inc.php
Подводя итог, хочется сказать, что mod_rewrite штука весьма несложная и в то же время очень мощная, поэтому стоит уделить ей час-два и навсегда избавится от таких насущных проблем, как дружественные УРЛ (friendly URLs).

а что значит [NC,L] в примере исключения?
Comment от Стас — 03.01.2009 @ 05:42
[NC,L] – флаги. NC означает, что регистр не имеет значения. Т.е. http://www.example.com/catalog/ и http://www.example.com/cAtALoG/ будут вести к одному и тому же, а именно, в соответствии с нашим правилом, к http://www.example.com/index.php?page=catalog. L означает, что если это правило подходит под наш URL, то следующие правила не применять, т.е. остановиться.
(c) http://bestblog.name/2008/11/modrewrite.html
Comment от ctepeo — 03.01.2009 @ 05:52
По поводу защиты файлов
Лучше уже использовать
order deny,allow
deny from all
allow from 127.0.0.1
- возможностей больше
А вообще скрывать требуется чаще всего каталоги, с данными, нежели какой-то отдельный файл
deny from all
Comment от Николаев Алексей — 06.03.2009 @ 11:55
Теги мне повырезало
order allow,deny
deny from all
и соответственно
Order Deny,Allow
Deny from All
Comment от Николаев Алексей — 06.03.2009 @ 11:56
ппц, и с пробелами повырезало
оно что, не может при посте htmlspesialchars сделать
Comment от Николаев Алексей — 06.03.2009 @ 11:58
В любом случае, идея понятна
Вы сказали, что «лучше» – хотелось бы уточнить чем лучше? Производительность? В принципе реврайт правилом можно и директории прятать под 403
И ещё: в данном методе не учтена одна штука: в заголовке страницы (header) необходимо передавать 200ый код («ОК»), чтобы поисковики не считали все страницы сайта одной 404ой, то есть статья апдейтед
Comment от ctepeo — 06.03.2009 @ 12:00
Почему лучше – директива Files проверяет обращение к файлу, а RewriteRule проверяет обращение по адресу.
Пример
сайт : http://tanya1.com
в корне имеем: test.php
в .htaccess имеем: RewriteRule ^test.php$ – [F,L]
Вроде все класно – имя файла описано от начала и до конца, «засады» ждать неоткуда.
Обращаемся на: http://tanya1.com/test.php и получаем как и следовало ожидать 403 нет доступа
Тем не менее ломается достаточно просто.
Набираем: http://tanya1.com/test.php%5C10 и файл test.php успешно сообщает нам «Hello world»
В случае с
Files test.php
Deny from all
Files
такой «финт ушами» не проходит.
Подобных извращений с url в какерских целях достаточно много и если уж запрещать доступ к файлу, то делать это директивами для работы именно с файлами, реврайт тут немного не к месту.
ЗЫ: А вообще тема важная и нужная. ПлусадЫн. Прочитай я подобную статью когда делал первые шаги, много нервов сохранил бы. Единственное я бы в статью добавил ссылку на приличный мануал по регулярным выражениям. Т.к. они используются в правилах, а статья рассчитана на новичков – им было бы полезно.
Comment от Николаев Алексей — 07.03.2009 @ 20:43
Относительно поста выше – хотел знакомому показать, не получилось. Начал копать – оказалось то, что я написал, во втором апаче уже не работает
. Но тем не менее на домашней сборке отработала бага.
Comment от Николаев Алексей — 09.03.2009 @ 11:24
Николаев Алексей, проверьте в конфиге апача разрешение на использование .htaccess, думаю, что проблема именно в этом, потому что данные директивы работают у меня лично на apache 2.2
Comment от ctepeo — 09.03.2009 @ 11:31
Только что на втором апаче попробовал обойти правило RewriteRule ^test.php$ – [F,L]
Получилось, просто адрес немного другой будет
набираем http://tanya1.com/test.php/
т.е. со слешем на конце и правило перестает работать – скрипт запускается
Comment от Николаев Алексей — 09.03.2009 @ 11:34
Николаев Алексей, под регулярное выражение ^test.php$ попадает только test.php без всяких вариаций, думаю, я накосячил и стоило писать что-то вроде ^test.php?$, хотя не уверен (не проверял). В любом случае будет полезно почитать про регулярные выражения. Например, вот тут: http://ru.wikipedia.org/wiki/Регулярные_выражения
Comment от ctepeo — 09.03.2009 @ 11:42
А что надо прописать чтобы при заходе в http://test.com/folder/ выдавало ошибку 403 а при заходе явно на http://test.com/folder/index.php обрабатывало корректно ???
Comment от dementiy — 07.11.2009 @ 20:51
Возник вопрос. у себя на сайте в целях проверки решил сделать дружественный URL к странице http://altermuz.ru/view_mus.php?id=45
код :
RewriteRule ^poltora.html /view_mus.php?id=45
теперь если в браузере ввести
http://www.altermuz.ru/poltora.html
действительно откроется эта же страница, но не наоборот (((( то есть ссылка не подменяется налету . с чем это может быть связано ???
думаю что может потомучто в php коте ссылка у меня генерируется следующим образом:
где %s это данные из БД. но если проблема в этом то как тогдабыть ???
помогите плиз.
Comment от Amadey — 12.02.2010 @ 23:06
dementy,
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
AllowOverride None
Order Deny,Allow
Deny from all
Comment от ctepeo — 13.02.2010 @ 16:03
Amadey, так или иначе файл-обработчик будет доступен. Мод_рерайт помогает создать «дружественные» УРЛы. Вариант решения: храните в базе УРЛы + обработчики, например:
/poltora.html | view.php
/distemper.html | view.php
/news.html | news.php
а в .htaccess пропишите перенаправление всех запросов на один файл, который и будет искать в базе по запросу нужный обработчик, примерно вот так:
Options -Indexes
RewriteEngine On
RewriteRule ^$ /engine.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule (.*)$ /engine.php [QSA]
а в файле /engine.php можно получить УРЛ через $_REQUEST, выбрать нужный нам обработчик(напримре, view.php), в нём, зная куда шёл пользователь (1.5кг или дистемпер, например), выбрать нужную информацию и показать её.
Если возникнут какие-либо вопросы, пишите
Comment от ctepeo — 13.02.2010 @ 16:11