Организация маршрута /checkout в PHP проектах

Раздел: Веб-разработка на PHP -> Маршрутизация PHP

Маршрутизация для страницы оформления заказа

Основной подход: маршрутизация через единую точку входа с использованием switch

Наиболее распространённый способ организации маршрута /checkout – создание файла index.php, который принимает параметр route (например, через $_GET['route']). Далее выполняется простое ветвление на основе значения этого параметра.

Код index.php (базовый вариант):


<?php
// index.php – единая точка входа
$route = $_GET['route'] ?? 'home';

switch ($route) {
    case 'checkout':
        // подключаем файл обработчика оформления заказа
        require_once 'checkout.php';
        break;
    case 'home':
    default:
        require_once 'home.php';
        break;
}
?>
  

Php route information information information (маршрут информации (повтор))

Запрос вида /index.php?route=checkout приводит к выполнению checkout.php. Внутри этого файла уже можно реализовать всю логику – показ формы заказа, обработку данных, сохранение в БД. Маршрут удобно расширять добавлением новых case.

Типичные ошибки и их решение

  • Параметр route не передан – срабатывает default, что может привести к показу не той страницы. Решение: всегда задавать значение по умолчанию (?? 'home').
  • Использование include вместо require_once может вызвать повторное подключение того же файла. Лучше применять require_once.
  • Без URL rewriting пользователь видит в адресной строке ?route=..., что некрасиво. Исправить можно с помощью .htaccess (будет показано в вариантах ниже).

Цель и случаи использования

Подходит для небольших проектов, где не требуется гибкая маршрутизация с параметрами. Простота реализации, легко читается новичками.

Как сделать гибкую маршрутизацию, поддерживающую динамические сегменты URL?

Применение регулярных выражений для разбора URL позволяет извлекать динамические параметры, например, /checkout/order/123.


<?php
// index.php с регуляркой
$url = $_SERVER['REQUEST_URI'];
$url = parse_url($url, PHP_URL_PATH); // убираем query

$pattern = '#^/checkout/order/(\d+)$#';
if (preg_match($pattern, $url, $matches)) {
    $orderId = (int)$matches[1];
    require_once 'checkout.php';
} else {
    // 404
    header('HTTP/1.0 404 Not Found');
    echo 'Страница не найдена';
}
?>
  

Index php route product category (маршрут категории продуктов)

Проблемы

  • Регулярные выражения сложно поддерживать при росте количества маршрутов.
  • Необходимо корректно обрабатывать все возможные символы в URL (спецсимволы, кириллица).

Решение

Применять только для простых сценариев или перейти на готовые библиотеки.

Как организовать маршрутизацию, используя готовую библиотеку FastRoute?

FastRoute (от Nikic) предлагает быстрый и удобный способ определить маршруты с поддержкой HTTP методов и параметров.


<?php
// index.php
require 'vendor/autoload.php';

$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/checkout', 'CheckoutController@index');
    $r->addRoute('POST', '/checkout', 'CheckoutController@process');
    $r->addRoute('GET', '/checkout/order/{id:\d+}', 'OrderController@show');
});

// Получаем HTTP метод и URI
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Удаляем query string
$uri = (false !== $pos = strpos($uri, '?')) ? substr($uri, 0, $pos) : $uri;
$uri = rawurldecode($uri);

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::NOT_FOUND:
        header('HTTP/1.1 404 Not Found');
        echo 'Страница не найдена';
        break;
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        header('HTTP/1.1 405 Method Not Allowed');
        echo 'Метод не разрешён';
        break;
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        // Разбираем контроллер@метод
        list($class, $method) = explode('@', $handler);
        $controller = new $class;
        call_user_func_array([$controller, $method], $vars);
        break;
}
?>
  

Php route module (маршрут модуля)

Возможные сложности

  • Требуется установка через Composer и автозагрузка.
  • Начальная настройка может показаться избыточной для простого маршрута.
  • Неверное указание CONTROLLER@METHOD приведёт к ошибке.

Как обеспечить чистые URL без параметра route в адресной строке?

Используется веб-сервер (Apache) с модулем mod_rewrite и файлом .htaccess, перенаправляющим все запросы на index.php.


RewriteEngine On
RewriteBase /

# Если запрошенный файл или директория существуют - не перенаправляем
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# Перенаправляем всё на index.php
RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]
  

Теперь URL /checkout будет обработан как index.php?route=checkout. Внутри index.php можно использовать предыдущий switch или регулярные выражения.

Проблемы и решения

  • На сервере может быть отключён mod_rewrite – потребуется включение или альтернатива Nginx (использовать try_files).
  • Некорректные правила могут зациклить перенаправление. Нужно проверять флаги [L,QSA].
- Index php route (маршрут index.php)

Расширенные примеры реализации маршрута /checkout

Пример 1: FastRoute с поддержкой middleware и контроллером

Установка через Composer: composer require nikic/fast-route

Создание контроллера CheckoutController.php

Пример

<?php
class CheckoutController
{
    public function index()
    {
        // Рендерим форму заказа
        require_once 'views/checkout_form.php';
    }

    public function process()
    {
        // Обработка POST-данных
        $data = $_POST;
        // Валидация, сохранение в БД
        header('Location: /checkout/success');
    }
}
?>

Файл index.php с middleware для логирования

Пример

<?php
require 'vendor/autoload.php';

// Middleware-функция
$logMiddleware = function ($request) {
    $log = date('Y-m-d H:i:s') . ' ' . $request['method'] . ' ' . $request['uri'] . PHP_EOL;
    file_put_contents('access.log', $log, FILE_APPEND);
};

$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/checkout', 'CheckoutController@index');
    $r->addRoute('POST', '/checkout', 'CheckoutController@process');
});

$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
$uri = (false !== $pos = strpos($uri, '?')) ? substr($uri, 0, $pos) : $uri;
$uri = rawurldecode($uri);

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);

// Вызов middleware
$logMiddleware(['method' => $httpMethod, 'uri' => $uri]);

switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        list($class, $method) = explode('@', $handler);
        $controller = new $class;
        call_user_func_array([$controller, $method], $vars);
        break;
    default:
        header('HTTP/1.1 404');
        echo 'Not found';
}
?>

Результат: при каждом запросе к /checkout в файл access.log добавляется строка с временем, методом и URI.

2025-03-18 14:23:45 GET /checkout
2025-03-18 14:24:01 POST /checkout

Пример 2: Ручная маршрутизация с поддержкой параметров через explode

Подходит, когда нет возможности использовать внешние библиотеки. Парсим URL и извлекаем сегменты.

Пример

<?php
$uri = $_SERVER['REQUEST_URI'];
$uri = trim($uri, '/');
$segments = explode('/', $uri);

// /checkout -> ['checkout']
// /checkout/order/123 -> ['checkout', 'order', '123']

$controllerName = isset($segments[0]) ? $segments[0] : 'home';
$action = isset($segments[1]) ? $segments[1] : 'index';
$params = array_slice($segments, 2);

switch ($controllerName) {
    case 'checkout':
        require_once 'controllers/CheckoutController.php';
        $controller = new CheckoutController();
        if (method_exists($controller, $action)) {
            call_user_func_array([$controller, $action], $params);
        } else {
            echo 'Action not found';
        }
        break;
    default:
        // 404
        break;
}
?>

Пример 3: .htaccess для Nginx (альтернатива)

Для серверов Nginx конфигурация отличается. Пример для виртуального хоста:

Пример

server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    location / {
        try_files $uri $uri/ /index.php?route=$uri&$args;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Результат: все запросы, не соответствующие существующим файлам, перенаправляются на index.php с параметром route.

Пример 4: Использование AltoRouter (лёгкая библиотека)

Установка: composer require altorouter/altorouter

Пример

<?php
require 'vendor/autoload.php';

$router = new AltoRouter();

$router->map('GET|POST', '/checkout', function() {
    require 'checkout_handler.php';
});

$router->map('GET', '/checkout/order/[i:id]', function($id) {
    echo "Показываем заказ номер: " . htmlspecialchars($id);
});

$match = $router->match();

if ($match && is_callable($match['target'])) {
    call_user_func_array($match['target'], $match['params']);
} else {
    header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
    echo 'Страница не найдена';
}
?>

AltoRouter предлагает простой синтаксис с поддержкой типов параметров ([i:id] – целое число).

Результат:

URL /checkout/order/42 -> выведет "Показываем заказ номер: 42"

Маршрут оформления заказа - comments

En
Index php route checkout checkout (php)