Как сделать роутинг php
Быстрый роутинг на PHP
Мне не очень хотелось использовать конструкции, предлагаемые большинством фреймворков, в целом выглядящие в таком виде:
Изначально хотелось хранить правила роутинга в JSON или XML.
Однако парсить каждый раз файл не очень хорошая идея, и такой тип более пригоден для статической навигации или навигации вида /controller/action/.
Мне же хотелось большей гибкости в настройке роутинга и в конечном итоге решил использовать XML для хранения правил, а после парсинга файла и создания массива правил сериализовывать его в файл (в дальнейшем используя его для получения настроек)
XML-файл правил роутинга выглядит примерно так:
Структура правила представляет собой следующее
XML-элемент правил содержится в элементе /root/routes, элемент правил должен содержать в себе следующие атрибуты:
match — Используется для поиска по URL
controller — Вызываемый контроллер
action — Вызываемый метод
match может содержать как статические данные, например «secret», так и динамические «page-
В переменной можно указать её тип:
На основе XML формируется массив, который разделает статические и динамические правила.
Все потомки так же разделяются на статических и динамических.
Так же в элементе /root/system
хранятся следующие данные:
Соответственно в случае, если совпадения по правилам роутинга найдены не будут, вернётся 404 ошибка, в случае пустого урл — его index значение
ЧПУ, роутинг, единая точка входа на PHP
Единая точка входа
Принцип работы единой точки входа очень прост.
Вот и весь принцип единой точки входа. Именно так она работает в популярных CMS вроде WordPress и Opencart, в фреймворках Laravel, Symfony и т.д.
Лично я предпочитаю также перенаправлять их на index.php.
На самом деле на сайтах часто используются 2 точки входа.
Плюсы единой точки входа
Единая точка входа с Apache
Этот файл позволяет переопределять настройки Apache для определённых сайтов и папок.
Также в интернете часто можно встретить другой вариант конфига, отличается он только последней строкой:
Единая точка входа с Nginx
Открываем конфиг домена и внутри секции server прописываем следующее правило:
Простой роутинг
Если единая точка входа настроена правильно, то при заходе по любому несуществующему URL-адресу, например /test должен запуститься файл index.php.
Теперь мы можем написать очень простой роутер, который смотрит на текущий URL и подключает соответствующий скрипт:
Внесём ещё пару доработок. Во-первых, зачастую URL-адреса должны работать вне зависимости от наличия GET-параметров, поэтому вырежем их из URI:
Кроме этого, часто требуется получить доступ к определённой части URL. Для этого разобьём URL на части по слешу:
Теперь мы можем легко добавить маршруты для админки:
Это самый простой вариант роутинга. Не идеальный, конечно, но и не требующий знания регулярных выражений (хотя никто не мешает их использовать) и подключения сторонних библиотек.
При хранении URL адресов в базе данных роутинг будет выглядеть примерно так (реальный код зависит от библиотеки, которую вы используете для взаимодействия с БД):
Роутинг средствами htaccess
Какое-то время назад было популярно прописывать правила роутинга прямо в htaccess, вот несколько примеров:
У этого подхода есть несколько недостатков:
Короче, не используйте этот подход.
Структура URL адресов в админке
Обычно URL адреса в админке формируются по одной из следующих схем:
И сразу рассмотрим простой пример:
Перепишем пример, написанный нами в единой точке входа, под новую схему URL:
Итак, мы берём 1-ый фрагмент URL и проверяем, существует ли в папке pages файл с таким названием.
Как видите, при таком подходе нам больше не нужно прописывать соответствие URL-адресов и PHP-файлов. PHP сам будет искать нужный файл в папке pages по первому фрагменту URL.
Вот так выглядит обработка действий. Мы смотрим на второй фрагмент URL и ищем обработчик этого действия. Для каждого действия (add, update, delete) нужно прописать отдельный блок elseif.
Если вам не нравится вложенная проверка метода, можно сделать иначе. В файле index.php сохраним метод в отдельную переменную:
Затем в products.php меняем заготовку на следующую:
Готово. Да, если вам не нравится, что в коде 2 раза встречается одно и то же действие, только с разными методами, можете использовать немного упрощённую схему URL-адресов из фреймворка Laravel:
Добавление префикса /admin/ в URL
Немного изменим код index.php :
Продвинутый роутер FastRoute
Если вы ищете более серьёзную систему роутинга, рекомендую изучить библиотеку FastRoute. Это очень мощный роутер, идеально подходящий для сложных приложений, особенно если вы используете ООП.
PHP-роутинг (Routing) для новичков
Роутинг — это маршрутизация: входящий URL разбирается специальным образом и по его результату выполняется определенный код. С роутингом напрямую связано понятие ЧПУ (человекопонятные урлы), которое позволяет исключить в адресах сложные параметры. Например вместо http://сайт/admin/new-page пришлось бы использовать http://сайт/admin.php?action=new-page
Любой входящий URL на сервере разбирается по единому стандарту. Полностью приводить документацию не буду (см. как пример функцию parse_url), важно лишь понять, что в адресе передается параметр path (путь на сервере), которого на сервере реально может не быть. Например в адресе http://сайт/admin каталога admin реально может не существовать.
Чтобы исключить такой вариант, серверу указывается, что для всех несуществующих каталогов и файлов, подключать php-файл (обычно index.php ).
Тут главная строчка с RewriteRule — именно она определяет шаблон входящего адреса (в примере это регулярное выражение) и что с ним делать. В данном примере будет подключен index.php с параметрами после слэша.
Похожий вариант, только чуть короче, от WordPress:
Здесь принудительно добавляется query-параметр page.
Еще один распространенный вариант (пожалуй самый «типовой»):
Все эти RewriteRule-правила делают простую вещь: как бы «преобразуют» входящий адрес в набор query-параметров. Например адрес http://сайт/admin превратится в http://сайт/index.php?admin
Если это какой-то подкаталог, то он указываетс в RewriteBase и как путь к php-файлу. Например каталог на сервере route :
Если в index.php разместить
Существуют несколько принципиально разных подходов в организации роутинга. Наиболее популярный подход — это когда в адресе передаётся «действие», которое описывается через php-класс. Такой подход хорошо описан в CodeIgniter:
Это сильно утрированный пример, но он хорошо показывает соответствие адреса и php-класса.
Другой вариант похожий, но используется не классы, а функции.
То есть функция — это первый сегмент, а остальные выступают уже как парметры. Встречается более «продвинутый» вариант.
То есть имя функции строится по сегментам URL.
Третий, тоже распространенный вариант — адрес указывает на подключаемый файл.
Здесь все файлы хранятся в каталоге pages и подключаются только если реально существуют. Если файла нет, то подключается предопределенный 404-файл.
Если сайт представляет собой сложный проект, то как правило используют роутинг на основе php-классов. Так его проще поддерживать и развивать. Если же сайт состоит из небольшого количества страниц, то как правило используют подключаемые файлы, где один файл — это одна страница.
Строго говоря, роутинг «на классах» тоже использует «файловое» подключение. Вначале подключается файл с кодом класса, а уже после этого выполняется сам класс.
В задачу роутинга входит не только необходимое «действие», но и валидация входящего адреса и его лексический разбор.
Свой «велосипед» не изобретал только ленивый, но я отмечу довольно известный FastRoute, который вобрал в себя наиболее типичные решения.
В первую очередь это использование регулярных выражений при задании правил, например:
Примерно такой же подход используется и в роутинге CodeIgniter.
То есть входящий адрес должен соответствовать шаблону и только в этом случае он «сработает».
В FastRoute реализована поддержка POST и GET-запросов. Такая возможность интересна, хотя на больших проектах такие вещи лучше делать на уровне самого «действия». Но это уже тонкости. Про эту библиотеку я упоминаю в первую очередь из-за того, что она достаточно популярна и уже используется в нескольких интересных проектах: Slim и Lumen.
Для небольших проектов, конечно же, FastRoute будет избыточна, поэтому можно ограничиться вариантом попроще, да и мозги потренировать. 🙂
Весь код в 2 строчки:
Это простой роутинг для простых проектов. Достаточно создать в content каталог, как он станет доступен по одноименному адресу.
Простой PHP маршрутизатор
Базовым элементом всех современных PHP фреймворков является роутер, по-другому маршрутизатор (Router), который отвечает за вызов контроллера, соответствующего запрошенному url-адресу. Маршрутизаторы, несмотря на все многообразие реализаций, выполняют одну и туже функцию. Далее мы с вами посмотрим на один из вариантов реализации, который похож на те, которые используются в таких популярных PHP фреймворках как Slim, Silex, Laravel и т.д.
// запрещаем создание и копирование статического объекта
private function __construct() <>
private function __clone() <>
Используем следующим образом:
// главная страница вашсайт.рф
Router::route(‘/’, function() <
print ‘Домашняя станица’;
>);
// запускаем маршрутизатор, передавая ему запрошенный адрес
Router::execute($_SERVER[‘REQUEST_URI’]);
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 1 ):
Расскажите пожалуйста по подробней как происходит вызов контролера действия и самое главное параметров в данном случае
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.
Фронт-контроллер и роутинг в PHP
Если вы не работали ранее с регулярными выражениями – пройдите урок по регуляркам в PHP.
Apache RewriteEngine
RewriteEngine – это такой механизм в сервере Apache, который позволяет перенаправлять запросы. А теперь давайте рассмотрим каждую строку файла отдельно.
Опа! Видим текст «Главная страница». Значит мы попали на index.php. Давайте теперь попробуем в index.php вывести GET-параметр route. Уберём пока код, добавленный на предыдущих уроках и оставим только автозагрузку классов и вывод этого GET-параметра.
Снова откроем тот же адрес http://myproject.loc/abracadabra и увидим следующее:
Такие адреса через слэши называются ЧПУ – Человеко Понятные УРЛы. То есть адреса, которые нормально воспринимаются человеком.
Согласитесь
http://myproject.loc/hello/username
лучше чем
http://myproject.loc/?action=hello&name=username
На таких ЧПУ-адресах мы и будем разрабатывать нашу систему.
Роутинг
Ну а теперь мы научимся обрабатывать такие адреса красивым и простым способом – с помощью регулярных выражений.
. Мы выбрали её вместо слэша, чтобы не экранировать слэш в адресной строке. Напомню, что в качестве ограничителя может выступать вообще любой символ.
Перейдём по адресу http://myproject.loc/hello/username и увидим наши совпадения по регулярке:
Нулевой элемент – полное совпадение по паттерну. Первый элемент – значение, попавшее в маску (.*), то есть всё, что идёт после hello/.
Посмотрим, что получилось.
Перейдём теперь на страницу http://myproject.loc/ и увидим сообщение «Главная страница».
Остаётся только добавить обработку случая, когда ни одна из этих регулярок не подошла и просто вывести сообщение о том что страница не найдена.
Давайте просто добавим в конце index.php строку:
А теперь давайте посмотрим на получившийся код и подумаем, нет ли здесь чего-то общего? Да конечно есть! В обоих случаях мы проверяем регулярки и в зависимости от совпадения создаём нужный контроллер, с нужным методом и нужными аргументами. Но механизм-то одинаковый! Значит, будем делать универсальную систему роутинга.
Итак, нам нужно создать такую систему, которая будет на вход получать адрес, а на выходе возвращать имя контроллера, метод и параметры.
Давайте создадим отдельный файл с такой конфигурацией. Пусть это будет файл src/routes.php. Запишем в него следующее содержимое:
src/routes.php
То есть это просто массив, у которого ключи – это регулярка для адреса, а значение – это массив с двумя значениями – именем контроллера и названием метода.
Теперь вернёмся в index.php и научимся обрабатывать этот файл. Для начала давайте просто положим этот массив в отдельную переменную.
Что с этим делать? Да просто пробежаться по нему foreach-ом и найти соответствие по регулярке для текущего адреса. Как только совпадение найдено, нужно остановить перебор. Звучит несложно. Давайте сделаем это!
Всё правильно. Давайте теперь вернёмся на http://myproject.loc/
Видим, что у нас есть имя нужного контроллера и имя метода. Всё, этого достаточно. Вот так это делается в PHP:
Да! Прямо вот так! Переменную можно использовать в качестве имени класса при создании объекта, и даже вместо имени метода!
Зайдите на http://myproject.loc/ и убедитесь, что всё прекрасно работает.
Но у нас осталась еще проблема с аргументами для методов.
Давайте вернёмся к предыдущему варианту кода, где мы просто вывели значения переменных:
Но мы видим, что нужные нам аргументы всегда будут только после нулевого элемента, так как в нём лежит полное совпадение по паттерну. Не беда – просто удаляем этот ненужный элемент:
Получаем следующую картину:
Остаётся только один вопрос – как элементы массива передать в аргументы метода? Для этого в PHP есть специальный оператор троеточия:
Он передаст элементы массива в качестве аргументов методу в том порядке, в котором они находятся в массиве.