Как сделать роутер php

Разработка роутера в своем MVC фреймворке

Теперь вам нужно разработать . Он представляет собой класс, который будет брать массив роутов, брать запрошенный URL, и определять, какой из роутов соответствует данному урл. После нахождения соответствующего роута наш класс должен получить части URL, соответствующие параметрам роута.

Пусть своим результатом наш роутер возвращает объект класса Track , содержащего имя контроллера, который должен быть вызван на данный запрос, имя действия и параметры из URL.

Пусть наш класс Track имеет свойства controller , action и params , доступные только для чтения:

Пример

Для примера, пусть в адресной строке вбито /test/1/2/ . Пусть у нас есть роут, соответствующий этому адресу:

Это значит, что имя контроллера будет test , имя действия — index , а массив параметров будет следующий:.

Цель данного урока — написать класс Router , возвращающий объект класса Track . Остальное нас пока не касается. Давайте приступим к написанию этого класса.

Использование роутера

Вспомним текущее содержимое файла index.php :

Пусть теперь далее в index.php мы хотим использовать наш роутер следующим образом:

Можно переписать более компактно:

Реализация роутера

Давайте теперь напишем заготовку класса Router в соответствии с нашими вызовами:

В методе getTrack мы должны определить, какой из роутов соответствует данному $uri . Для этого нужно перебрать наш массив с роутами циклом:

Если какой-то роут соответствует URI, мы должны получить из этого URI значения параметров роута и вернуть объект класса Track :

Скопируйте код моего класса Track и разместите его в файле /core/Track.php .

Скопируйте мою заготовку класса Router и разместите его в файле /core/Router.php .

Реализуйте описанный класс Router , своим результатом возвращающий объект класса Track . Если будете испытывать затруднения (что весьма вероятно), подсмотрите в исходный код фреймворка, по которому вы изучали использование MVC. Там в классе Router вы найдете недостающую часть реализации и мои комментарии к ней.

Источник

ЧПУ, роутинг, единая точка входа на PHP

Веб-сервер настраивается так, чтобы все HTTP-запросы, вне зависимости от их URL, обрабатывались одним и тем же скриптом index.php .

HTTP-запросы отправляются на сервер, где перенаправляются на index.php

Текущий URL можно получить из переменной $_SERVER[‘REQUEST_URI’] . Дальше останется только написать свои правила обработки URL-адресов. Упрощённый пример:

Однако в схеме выше есть одно упущение. Ведь если на сервер пришёл запрос к существующему файлу (style.css, script.js, logo.png и т.д) — сервер должен отдать этот файл, а не перенаправлять его.

Обработка запросов при использовании единой точки входа

Вот и весь принцип единой точки входа. Именно так она работает в популярных CMS вроде WordPress и Opencart, в фреймворках Laravel, Symfony и т.д.

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

Лично я предпочитаю также перенаправлять их на index.php.

На самом деле на сайтах часто используются 2 точки входа.

Первая — index.php, вторая — отдельный скрипт, предназначенный для работы с сайтом через консоль.

Плюсы единой точки входа

  • Позволяет использовать ЧПУ
  • Позволяет полностью управлять URL-адресами в PHP, в том числе хранить URL-адреса в базе данных
  • Скрипты с конфигами, важными функциями и библиотеками подключаются только 1 раз и становятся доступны везде. Не нужно дублировать их подключение где-либо ещё.

Единая точка входа с Apache

Для настройки единой точки входа необходимо добавить несколько строк в конфиг веб-сервера. Проще всего это сделать с помощью файла .htaccess .

Этот файл позволяет переопределять настройки Apache для определённых сайтов и папок.

Добавляем следующие настройки в .htaccess:

# Включаем перенаправление RewriteEngine On # Не применять к существующим файлам файлам RewriteCond % !-f # Не применять к существующим директориям RewriteCond % !-d # Редирект всех запросов на index.php # L означает Last, нужен чтобы на этом этапе mod_rewrite сразу остановил работу. # Короче, небольшое увеличение производительности. RewriteRule .* index.php [L]

Чтобы перенаправление срабатывало для существующих директорий, удаляем строку с !-d в конце, вот так:

RewriteEngine On RewriteCond % !-f RewriteRule .* index.php [L]

Готово. Получить URL адрес текущей страницы можно из переменной $_SERVER[‘REQUEST_URI’] .

Также в интернете часто можно встретить другой вариант конфига, отличается он только последней строкой:

RewriteRule ^(.*)$ index.php?url_param=$1 [L,QSA]

Главное отличие в том, что URL-адрес текущей страницы будет храниться как в $_SERVER[‘REQUEST_URI’] , так и в отдельном GET-параметре, в нашем случае $_GET[‘url_param’] , причём этот URL будет очищен от GET-параметров.

Флаг QSA нужен, поскольку без него GET-параметры не будут работать, т.е. массив $_GET будет содержать только url_param и больше ничего.

Какой из двух вариантов выбрать — решать вам, лично мне больше нравится первый.

Единая точка входа с Nginx

Открываем конфиг домена и внутри секции server прописываем следующее правило:

Простой роутинг

Если единая точка входа настроена правильно, то при заходе по любому несуществующему URL-адресу, например /test должен запуститься файл index.php.

URL текущей страницы находится в переменной $_SERVER[‘REQUEST_URI’]

Теперь мы можем написать очень простой роутер, который смотрит на текущий URL и подключает соответствующий скрипт:

Внесём ещё пару доработок. Во-первых, зачастую URL-адреса должны работать вне зависимости от наличия GET-параметров, поэтому вырежем их из URI:

// /about?id=5 превратится в /about $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

Кроме этого, часто требуется получить доступ к определённой части URL. Для этого разобьём URL на части по слешу:

$segments = explode('/', trim($uri, '/'));

В переменной $segments для URL /products/15 будет лежать массив вида [0 => ‘products’, 1 => ’15’] .

Теперь мы можем легко добавить маршруты для админки:

Это самый простой вариант роутинга. Не идеальный, конечно, но и не требующий знания регулярных выражений (хотя никто не мешает их использовать) и подключения сторонних библиотек.

При хранении URL адресов в базе данных роутинг будет выглядеть примерно так (реальный код зависит от библиотеки, которую вы используете для взаимодействия с БД):

select('SELECT * FROM `pages` WHERE `url` = ?', [$uri])->first(); // Если статьи нет - показываем ошибку if(!$current_page) require 'pages/404.php'; // Если статья есть - подключаем шаблон, в котором будет доступна переменная $current_page else require 'pages/article.php';

Роутинг средствами htaccess

Какое-то время назад было популярно прописывать правила роутинга прямо в htaccess, вот несколько примеров:

RewriteRule ^/product-(.*)_(9+).php /redirectold.php?productid=$2 RewriteRule ^products/([^/]+)/([^/]+)/([^/]+) product.php?category=$1&brand=$2&product=$3 RewriteRule ^news/203/8/1/[^/]+\.html index.php RewriteCond %/name/$1.php -f RewriteRule ^([^/]+)/([^/]+)/?$ $.php1?action=$2 [L,NC,QSA] RewriteCond %/name/$1.php -f RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ $1.php?action=$2&id=$3 [L,NC,QSA]

У этого подхода есть несколько недостатков:

  • Плохая читаемость правил
  • Нужно хорошо знать регулярки
  • Хранение правил роутинга в настройках веб-сервера — концептуально не очень хорошая идея

Короче, не используйте этот подход.

Мем больной ублюдок - люблю настраивать роутинг в htaccess

Структура URL адресов в админке

Обычно URL адреса в админке формируются по одной из следующих схем:

/модуль/действие/параметр1/значение1/параметр2/значение2 /модуль/действие/значение1/значение2

И сразу рассмотрим простой пример:

/products - просмотр каталога /products/add - добавление товара /products/update - обновление товара /products/delete - удаление товара

Итак, мы видим, что модулем здесь является products , а действием, к примеру, add . Что теперь с этим делать?

Если вы знакомы с ООП и MVC, тогда модулем для вас будет название класса, а действием — метод этого класса, который нужно запустить. Если действие не указано, то принято запускать метод под названием index.

Если вы ничего не поняли — воспринимайте модуль как название файла, который нужно подключить, а действие — как, собственно, действие, которое нужно выполнить.

Перепишем пример, написанный нами в единой точке входа, под новую схему URL:

Итак, мы берём 1-ый фрагмент URL и проверяем, существует ли в папке pages файл с таким названием.

Т.е. при переходе на страницу /test/test2 скрипт проверит существование файла /pages/test.php . Если файл есть — PHP выполнит этот файл, в противном случае выполнится файл /pages/404.php .

Как видите, при таком подходе нам больше не нужно прописывать соответствие URL-адресов и PHP-файлов. PHP сам будет искать нужный файл в папке pages по первому фрагменту URL.

Теперь осталось только создать файл pages/products.php . Сделаем небольшую заготовку:

 elseif($segments[1] === 'add') < // Если запрос пришёл методом POST if($_SERVER['REQUEST_METHOD'] === 'POST') < // добавляем новый товар в базу >// Если запрос пришёл методом GET else < // отображаем форму добавления товара >>

Вот так выглядит обработка действий. Мы смотрим на второй фрагмент URL и ищем обработчик этого действия. Для каждого действия (add, update, delete) нужно прописать отдельный блок elseif.

Внутри обработчика add мы смотрим на то, каким методом пришёл запрос, GET или POST. Если GET — отображаем форму, если POST — добавляем товар.

Если вам не нравится вложенная проверка метода, можно сделать иначе. В файле index.php сохраним метод в отдельную переменную:

$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $segments = explode('/', trim($uri, '/')); $method = $_SERVER['REQUEST_METHOD']; // . 
 elseif($segments[1] === 'add' && $method === 'GET') < // отображаем форму добавления товара >elseif($segments[1] === 'add' && $method === 'POST') < // добавляем новый товар в базу >

Готово. Да, если вам не нравится, что в коде 2 раза встречается одно и то же действие, только с разными методами, можете использовать немного упрощённую схему URL-адресов из фреймворка Laravel:

(GET) /products - отображение товаров (GET) /products?id=5 - отображение 5-ой страницы товаров (GET) /products/create - отображение формы добавления товара (POST) /products/store - сохранение товара из формы добавления (GET) /products/edit/15 - отображение формы редактирования товара с /products/update - сохранение товара из формы редактирования (POST) /products/destroy - удаление товара по его идентификатору в базе

Добавление префикса /admin/ в URL

Немного изменим код index.php :

Теперь при запросе страницы /admin/products PHP будет искать файл с названием не products.php , а admin_products.php .

Переименуйте файл и не забудьте заменить в нём все $segments[1] на $segments[2], поскольку в $segments[1] теперь лежит модуль, а в $segments[2] действие.

Продвинутый роутер FastRoute

Если вы ищете более серьёзную систему роутинга, рекомендую изучить библиотеку FastRoute. Это очень мощный роутер, идеально подходящий для сложных приложений, особенно если вы используете ООП.

Если вы хотите, чтобы я написал отдельную статью по работе с FastRoute — пишите об этом в комментариях.

Источник

Читайте также:  How to get query params javascript
Оцените статью