PHP: создание ЧПУ в .htaccess

Основной проблемой любого динамического сайта является отсутствие читабельного URL-адреса. В тоже время, читабельный URL-адрес это подсказка о содержащемся на веб-странице контенте. Таким образом, возникает необходимость создать полноценный ЧПУ. Решением может служить использования модуля преобразований на стороне веб-сервера. В данной статье я хочу помочь Вам решить задачи по созданию ЧПУ и настройке преобразований в файле .htaccess с целью дальнейшей обработки запросов пользователей в PHP-скрипте.

Содержание:

  • Создание ЧПУ
  • Настройка преобразований в .htaccess
    • Разбор регулярного выражения в RewriteRule
  • Обработчик ЧПУ на PHP
  • Подведём итоги

Создание ЧПУ

А начну я с того, что  использование модуля преобразований, в качестве полноценного обработчика ЧПУ, нельзя назвать удачным решением. В частности, это часто приводило к сообщениям об ошибках в логах сервера, которые связанны с многоуровневыми ЧПУ.

Например, если: category/name/ – обрабатывается вполне успешно, то вот просто: category/ – даже при наличии соответствующей директивы в файле .htaccess, выдаёт предупреждение. Впрочем, это никак не сказывается на работе самого сайта. Помимо этого есть и ряд других проблем, но я не буду в них вдаваться, т.к. они носят чисто субъективный характер.

Настройка преобразований в .htaccess

При создании сайтов, лучше использовать несколько более простое преобразование URL-адресов, передавая ЧПУ управляющему php-скрипту. Для этого в фале .htaccess нужно указать что-то вроде следующего:

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

Давайте разберем приведенный пример подробнее.

ifModule – как следует из названия, эта директива проверяет наличия модуля mod_rewrite.c на сервере, который в свою очередь обеспечивает работу директив преобразований.

Далее идёт RewriteEngine – это директива, которая позволяет управлять статусом модуля преобразований. Обычно он отключен, используя директиву RewriteEngine, мы можем его включить. Для этого в качестве значение указываем: on.

Следующий набор директив RewriteCond определяют условия, при которых происходят дальнейшие преобразования. В приведенном примере добавлено три исключения: не файл (!-f), не ссылка (!-l) и не директория (!-d), которые уже существуют без преобразования.

Другими словами, если на сайте есть файл filename.html и к нему идёт обращение, то будет открыт именно этот файл, а не передан запрос обработчику ЧПУ. Таким образом, мы решаем сразу ряд проблем.

Следует также отметить, что эти условия построены на обработке переменной REQUEST_FILENAME – запрашиваемого имени файла.

Последняя директива RewriteRule, определяет правила для механизма преобразований. В нашем случае, это фрагмент URL-адреса начинающийся после доменного имени и заканчивающийся символом вопрос (?), если таковой есть. Он будет передана php-скрипту index.php в качестве значения переменной furl.

Другими словами, php-обработчик получает только ЧПУ, не исключая возможности получения и динамических параметров, методом POST и/или GET.

Разбор регулярного выражения в RewriteRule

Сделаю небольшое отступление и разберу используемое в примере регулярное выражение: ^(.*)$.

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

Другими словами, мы извлекаем подстроку, состоящую из всех символов запроса, от начала и до конца.

Далее идет указание php-скрипта index.php от места расположения файла .htaccess. В качестве значения параметра furl здесь выступает первая (а в нашем случае и единственная) извлекаемая подстрока. Для этого в качестве значения указанна переменная регулярного выражения $1. Соответственно, если в регулярном выражении присутствует несколько извлекаемых подстрок, нужно указывать требуемый их номер очередности.

Отдельно хочу отметить, что регулярное выражение может быть и более сложным, но в нашем случае приведенного примера будет более чем достаточно.

Подведём итоги

В данной статье приведён рабочий пример, который позволяет передать PHP-обработчики фрагмент URL-адреса с целью динамического формирования нужного контента на запрос пользователя. Используемые в файле .htaccess директивы и регулярное выражение описаны в достаточной степени, чтобы решить поставленную задачу на осознанном уровне. На этом у меня всё. Спасибо за внимание. Удачи!

plutov.by
plutov.by комментирует...

Уже почти все фреймворки используют FrontController паттерн, которые автоматически делают понятные ЧПУ. Всего лишь настроить .htaccess, чтобы все запросы шли на index.php, в дальше уже разруливать URL по контроллерам и действиям. Так я сделал в своем блоге на Zend Framework. Пример ссылки последней статьи - http://plutov.by/post/tuffle_intro

Константин Кирилюк
Константин Кирилюк комментирует...

2plutov.by ну, вариантов тут много. Мой пример позволяет получить чистый ЧПУ без строки параметров в виде значения GET переменной. Здесь не нужен бутстрепа и иже... всё просто и понятно. Имхо конечно.

Виталий Пестин
Виталий Пестин комментирует...

Вопрос такой.
Если в теле документа внутренняя ссылка формируется с помощью get переменных, то какой адрес при переходе по ней укажет у себя поисковая машина?

Константин Кирилюк
Константин Кирилюк комментирует...

2Виталий Пестин какой будет доступен для индексирования такой и укажет + метатег canonical конечно.

Сергей Стеклов
Сергей Стеклов комментирует...

Я у себя тоже сделал ЧПУ. У меня WordPress и вывожу я эти нормальные урлы с помощью плагина. Мне так удобнее. Когда я не публикую статьи, то сам плагин отключаю на время. Так меньше нагрузки идет. Когда нужно опубликовать что-то или загрузить фотографии, то плагин опять включаю на определенное время.

Константин Кирилюк
Константин Кирилюк комментирует...

2Сергей Стеклов система ЧПУ уже встроена в WordPress и тут плагин не нужен. Есть конечно надстройка для некоторых плагинов кэширования, чтобы обойти стандартный механизм разбора ЧПУ в WordPress и сразу переводить всё на статику, но там тоже есть свои заморочки. Вообще WordPress это жуткая штука в плане ресурсов.

Сергей Стеклов
Сергей Стеклов комментирует...

Извиняюсь, не так выразился. Да ЧПУ там уже встроены, а я только плагином автоматом перевожу русские символы в латинские. Ну, чтобы избавиться от кракозябр в ссылках.))) Конечно, можно и без плагина обойтись, но тогда нужно все заранее вручную править. Я иногда забудусь вовремя подправить или картинки прописать английскими буквами, вот и использую плагин. Он автоматом все делает. Мне так просто удобнее.))

Константин Кирилюк
Константин Кирилюк комментирует...

2Сергей Стеклов такой плагин нет смысла отключать, т.к. он не потребляет ресурсы и интегрируется обычно только в админку.

Сергей Стеклов
Сергей Стеклов комментирует...

Не, проверял нагрузку плагином P3 (Plugin Performance Profiler), он показал, что плагин создает небольшую нагрузку. Где-то 4% от всех плагинов.)) Может звучит смешно, но когда я не публикую, то на время отключаю плагин. Если ненужно, то стараюсь отключать на время лишние плагины. Просто если каждый создает небольшую нагрузку, то в сумме общая нагрузка от таких плагинов может быть немаленькой. Поэтому лишний раз отключаю.))

Константин Кирилюк
Константин Кирилюк комментирует...

2Сергей Стеклов здесь нужно чётко понимать, что собой представляет та или иная нагрузка. Любой скрипт, программа и т.д., если они работаю, создают нагрузку, занимают память и т.д. Конечно, многое зависит от того, какой плагин ты используешь. Но, например, Cyr-To-Lat это просто функция транслитерации, которая вызывается при добавлении и/или редактировании поста. Основную же нагрузку создают запросы к БД, в WordPress их очень много, но с плагином транслитерации это точно не связано. Точнее говоря, плагин работает только в админке и не работает в блоге.

Сергей Стеклов
Сергей Стеклов комментирует...

У себя я использовал Cyr to Lat enhanced. Иногда нагрузка доходила до 17%. Значит есть что-то! А как проверил Cyr to Lat, так сразу видно, что нет никакой нагрузки, поэтому сейчас на него перешел. Поэтому плагин плагину рознь.

Константин Кирилюк
Константин Кирилюк комментирует...

2Сергей Стеклов посмотрел Cyr to Lat enhanced. Там автор обрабатывает не получаемые из формы данные, а берёт название поста из БД (+1 запрос). К тому же создано создание автоматической обработки для уже опубликованных постов, в том числе и метаданных, и это уже очень серьёзная нагрузка.