ЧПУ с mod_rewrite

Человеко-понятный URL нужен. Так наглядней видеть где вы находитесь. Реализовать ЧПУ можно несколькими способами.

(Apache) mod_rewrite

В зависимости от архитектуры web-системы, загрузка отдельных модулей происходит как правило если не напрямую через GET запрос, то хотя-бы косвенно. Косвенно это когда создаётся страница, а потом специально для неё создаётся путь, сохраняется в БД, изменяем и красив.

Преобразование разных параметров в папки по-моему самое нужное. Включаем mod_rewrite, создаём или дописываем .htaccess что-бы работало всё так:

http://kurapov.name?mod=gallery&action=list&page=5
http://kurapov.name/gallery/list/?page=5

Options +FollowSymLinks
RewriteCond %{REQUEST_FILENAME} !-f
RewriteEngine On
RewriteRule ^([A-Za-z0-9^/]+)/([A-Za-z0-9_^/]+)/$ /index.php?mod=$1&action=$2 [QSA,L]
RewriteRule ^([A-Za-z0-9^/]+)/([A-Za-z0-9_^/]+)/?$ /index.php?mod=$1&action=$2 [QSA,L]


Самое главное это конечно же RewriteRule, которое построено на регулярных выражениях , поэтому многие веб-разработчики и не прошли через этот участок. В данном примере в URL ищется в начале (знак ^) две папки, названия которых состоят из букв и цифр. Первая папка становится значением $1, вторая соответсвенно $2. В итоге запрос передаётся в обработку в index.php с GET параметрами. Параметр QSA=query string append добавляет в конец ещё параметры которые запрашивал пользователь.

Установка ЧПУ на существующую систему

Какой получается минус? Если есть файл resources/thumbs/generator.php , то получится что обращение тоже будет перезаписываться, и в действительности будет всё идти на index.php. Более того, если система была спроектирована по относительным путям, где все картинки, фреймы, ссылки не велись от корня, то возникнет проблема с новой адрессацией.

404 перезапись

Как очень быстрое и простое решение можно вместо mod_rewrite использовать перенаправление 404 ошибки

ErrorDocument 404 /index.php

Теперь достаточно в index.php обратится к массиву и вызвать нужный модуль:

header("HTTP/1.1 200 OK");
header("Status: 200 OK");

$arrURL=explode('/',$_SERVER['REQUEST_URI']);

Не забудьте проверять существует ли такой модуль в системе, и сделать обработку ошибок, в том числе и на уровне header-ов, иначе поисковики могут посчитать что у вас всюду брак.

RSS

Комментарии

  • hokeist
    А не проще сделать вот так?
    RewriteEngine on RewriteBase / RewriteRule .* index.php
    В index.php разбирать QUERY_STRING
  • Артём Курапов
    Да, я так и использую..
    RewriteEngine on Options +FollowSymLinks RewriteBase / RewriteRule ^.htaccess$ - [F] RewriteCond %{REQUEST_FILENAME} !\.(jpg|jpeg|gif|png|css|js|pl|txt)$ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ /index.php [QSA]
  • sup
    Автор, ты охуителен! На этом сайте я узнал про QSA. До этого ночей не спал - думал, как сделать, чтобы параметры GET-запроса не затирались mod_rewrite
  • Дмитрий
    Подскажите, пожалуйста, как сделать чтобы при
    site.ru/catalog/proc/intel -> index.php
    site.ru/catalog/ -> index.php
    т.е. все что только можно ссылалось на index.php

    делаю так:
    RewriteEngine On RewriteCond %{REQUEST_FILENAME} !\.(jpg|jpeg|gif|png|css|js|pl|txt)$ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^([A-Za-z0-9/-]+)/?$ index.php

    Реврайт на index.php РАБОТАЕТ, но css, картинки, скрипты не грузятся.
    т.е. у них адрес остается http://site.ru/catalog/proc/themes/logo.png
    при запросе site.ru/catalog/proc/
    (картинки в /themes относительно корня)
  • Артём Курапов
    Честно говоря идей нет. Если сама картинка по полному пути не открывается - это проблема с mod_rewrite правилами. А если просто путь неправильный - то проблема движка. Как я понял у вас по правилу все папки перезаписываются на index, а css/картинки не должны как-то затрагиваться.
  • Дмитрий
    Уф...
    нужно было к путям картинок, стилей, скриптов дописать в начало слэш, т.е:
    было: src="inc/jquery-1.3.1.min.js"
    стало: src="/inc/jquery-1.3.1.min.js"
    также картинки:
    < img src="/themes/logo.png"/>
    все гениальное просто :-)
  • Дмитрий
    Исправление:
    также картинки:
    src="/themes/logo.png"

    P.S. можно было еще через так да же проще :-)
  • Hugo
    Автор, ты реально охутиелен, спасибо за QSA :D
  • Вадим
    Кто нибудь расскажет наконец, как сделать чтобы в браузере не index.php отображался url в адресной строке а именно url несуществующей страницы? В то время как загружен и работает index.php. Неужели подложные файлы надо делать.
  • Так не надо ссылки на index.php делать, ссылайтесь на папку, а apache уже сам решит что там надо вызывать - html, htm, php, phtml или inc файл.
  • Вадим
    Сейчас делаю так - все ссылки на сайте делаю типа корень/ссылка1/ или корень/ссылка2/ - так в анкоре и прописываю. насоздовал в корне на ФС все эти каталоги с index.php внутри. каждый index.php вызывает "include ("../index.php");" . В главном index.php который в корне я разбираю $_SERVER['REQUEST_URI'] , в зависимости от этого строю дальнейшую логику.
  • Это грабли. Почитайте статью - вам надо только один index.php в корне и поддержку mod_rewrite у веб-сервера с .htaccess правилом перенаправления всех запросов в этот коренной index файл
  • Вадим
    Но уже возникли проблемы с корневой директорией (/ в корне и ../ в каталогах из которых index.php вызываются). Изза этого в html темплейте надо динамически менять путь до css файла и прочих js. Да и вообще не уверен что это все будет работать. Если мне надо много параметров будет обработать - это куча вложенных каталогов должна быть на ФС. пипец. уже быдлокод выходит. а заморачиваться с БД не хочу.
  • Вадим
    Если делать по статье, то при переходу по ссылке /корень/documents/ я попадаю на index.php нов браузере в адресной строке пишется index.php?mod=documents&action=
    Это же не ЧПУ. Одностороннее ЧПУ получается, ссылки красивые создавать можно, но в адресной строке в итоге все равно будет треш.
  • Вадим
    Как мне сказали - это происходит redirect. Т.е. mod_rewrite не должен менять url в браузере, запрос от клиента уже отправлен, на самом сервере просто произошел редирект на index с параметрами, а адрес в браузере как был так и остался, но у меня адрес меняется. Вопрос - почему. Как отменить редирект в mod_rewrite. Рою httpd.conf - никак не найду...
  • Да, в файле httpd.conf модуль включается раскомментировав:

    LoadModule rewrite_module modules/mod_rewrite.so AddModule mod_rewrite.c ClearModuleList

    (или .dll) и перезапустив сервер
  • Нет, это не редирект. Mod rewrite такой URL делает Внутренний для сайта - для браузера в адресной строке так и будет /корень/documents
  • Вадим
    у меня в modrewrite было чтото типа rewriterule (.*)/(.*)/ http://mydomain.ru/index.php&par1=$1&par2=$2. это очень приблизительно - но это работало как редиерект и меняло url в браузере. стоило избавиться от домена во второй части и написать что то типа /index.php&par1=$1&par2=$2 - то стало именно открывать index.php с параметрами, а url в браузере оставался прежним. т.е. если во второй части выражения домен указывается, то апач думает что надо редиректить, неважно, даже если домен находится на этом же сервере.
    Теперь все почти как надо, но у меня меняется document_root и файл style.css который лежит в корне, рядом с index.php не находится. если на него ссылку сделать например как ../../style.css то находиться и стили начинают работать. количество переходов вверх зависит от кол-ва слешей (уровней) в красивом урле. вот теперь это надо грамотно зарешать и можно жить. но я чувствую тут будет большой геморой, как бы не пришлось все пути в include файлах менять. к картинкам, к css, к .js. а степень вложенности урла будет меняться, т.е. "../../" часть надо определять переменной в php и подставлять в инклюдируемый шаблон перед именем файла. так работает, но это не правильно, не тру.
  • Собственно для этого в статье и написано исключение на случай существования файла
    RewriteCond %{REQUEST_FILENAME} !-f
  • Вадим
    Options +FollowSymlinks RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteEngine on RewriteRule ^([A-Za-z0-9^/]+)/?$ /index.php?mod=$1 [QSA,L] RewriteRule ^([A-Za-z0-9^/]+)/([A-Za-z0-9_^/]+)/?$ /index.php?mod=$1&action=$2 [QSA,L] ErrorDocument 404 /index.php
    Вот при таком содержимом все равно не подхватывается styles.css. Причем при ссылке типа http://mydomain.ru/wer стили все таки подхватываются, а при http://mydomain.ru/wer/ (со слешем в конце) или http://mydomain.ru/wer/asa/ или http://mydomain.ru/wer/asa или любой другой пример дальше по вложенности уже не подхватывается.

    в index.php у меня есть include("template.php") в темплейте
  • Вадим
    ... в темплейте есть строка :
  • Вадим
    все, догуглил, что пути надо начинать с / . типа /somefile.ext. тогда работает