Skip to content

Middlewares PSR-15

Middleware řídí výkonný tok požadavků skrz aplikaci - autentifikace, validace, logování, atd.

Petrovo CMS používá vlastní implementaci PSR-15 middleware pipeline (Petrovo\Middleware) bez Laminas/Siler overhead.

Koncept

Middleware v Petrovo:

use function Petrovo\Middleware\pipe;
use function Petrovo\Route\dispatch;
use function Petrovo\Http\request;

$middleware = function($request, $handler) {
    // 1. Logika PŘED handlerem
    $userId = getSessionUserId();
    if (!$userId && isProtectedPath($request)) {
        return redirectToLogin();
    }

    // 2. Předej request dál
    $request = $request->withAttribute('user_id', $userId);
    $response = $handler->handle($request);

    // 3. Logika PO handleru (úprava response)
    $response = $response->withHeader('X-Runtime', microtime(true));

    return $response;
};

// Zaregistruj do pipeline
pipe($middleware, 'admin');

// Middleware se aplikuje automaticky na routy s 'admin' pipeline

Klíčové body:

  • Middleware dostává ServerRequestInterface a RequestHandlerInterface
  • Voláš $handler->handle($request) aby pokračoval do dalšího middleware
  • Parametry mezi middleware: $request->withAttribute() a $request->getAttribute()
  • Middleware se spouští v pořadí registrace

Funkce Petrovo\Middleware

use function Petrovo\Middleware\{pipe, process, handle, reset, get_pipelines};
  • pipe($middleware, 'name') - Zaregistruj middleware do pipeline
  • process($request, 'name') - Vrací closure pro wrappování middleware okolo handleru
  • handle($request, 'name') - Spustí middleware pipeline bez handleru
  • reset() - Vyčisti všechny pipeline (testování)
  • get_pipelines() - Debug - vrací registrované pipeline

Praktické Příklady

Jednoduchý logging middleware

// app/Middlewares/Request/loggingMiddleware.php
use function Petrovo\Middleware\pipe;

$loggingMiddleware = function ($request, $handler) {
    $method = $request->getMethod();
    $path = $request->getUri()->getPath();
    error_log("→ $method $path");

    $response = $handler->handle($request);

    error_log("← " . $response->getStatusCode());
    return $response;
};

// V route:
pipe($loggingMiddleware, 'admin');

Middleware s autentifikací

// app/Middlewares/Auth/authMiddleware.php
use function Petrovo\Http\text;

$authMiddleware = function ($request, $handler) {
    $token = $request->getHeaderLine('Authorization');

    if (!$token || !validateToken($token)) {
        return text('Unauthorized', 401);
    }

    // Úspěšně autentifikován - pokračuj
    return $handler->handle($request);
};

pipe($authMiddleware, 'api');

Middleware který mění request

// app/Middlewares/Request/userMiddleware.php
use function Petrovo\Database\DB;

$userMiddleware = function ($request, $handler) {
    $userId = Session::get('user_id');

    if ($userId) {
        // Načti user z DB a přidej do request
        $user = DB::row("SELECT * FROM users WHERE id = ?", [$userId]);
        $request = $request->withAttribute('user', $user);
    }

    return $handler->handle($request);
};

pipe($userMiddleware, 'admin');

Middleware který mění response

// app/Middlewares/Response/securityHeadersMiddleware.php

$securityHeadersMiddleware = function ($request, $handler) {
    $response = $handler->handle($request);

    // Přidej security headers
    return $response
        ->withHeader('X-Content-Type-Options', 'nosniff')
        ->withHeader('X-Frame-Options', 'SAMEORIGIN')
        ->withHeader('X-XSS-Protection', '1; mode=block')
        ->withHeader('Strict-Transport-Security', 'max-age=31536000');
};

pipe($securityHeadersMiddleware, 'frontend');

Implementované Middlewares

Každý middleware je v jednom souboru v adresáři dle skupin. Automaticky se loadují přes composer.json sekci "files":

{
  "autoload": {
    "files": [
      "app/Middlewares/App/settingMiddleware.php",
      "app/Middlewares/Auth/loginAdminMiddleware.php",
      "app/Middlewares/Auth/loginMiddleware.php",
      "app/Middlewares/Auth/logoutAdminMiddleware.php",
      "app/Middlewares/Auth/logoutMiddleware.php",
      "app/Middlewares/Input/adminAjaxDataMiddleware.php",
      "app/Middlewares/Input/adminCubeDataMiddleware.php",
      "app/Middlewares/Input/csrfMiddleware.php",
      "app/Middlewares/Input/sanitizationMiddleware.php",
      "app/Middlewares/Log/loggingAdminMiddleware.php",
      "app/Middlewares/Request/proxyMiddleware.php",
      "app/Middlewares/Response/headersMiddleware.php",
      "app/Middlewares/Restriction/corsMiddleware.php",
      "app/Middlewares/Restriction/ipFilteringMiddleware.php",
      "app/Middlewares/Restriction/publicEndpointsMiddleware.php",
      "app/Middlewares/Session/sessionExpirationAdminMiddleware.php",
      "app/Middlewares/Url/defineWebMiddleware.php",
      "app/Middlewares/Url/redirectionMiddleware.php"
    ]
  }
}

Struktura middleware souboru:

<?php
declare(strict_types=1);

// $middleware = closure
$settingMiddleware = function ($request, $handler) {
    // ... logika ...
    return $handler->handle($request);
};

Skupiny middlewares

App

  • settingMiddleware - Načítá aplikační nastavení

Auth

  • loginAdminMiddleware - Ověří přihlášení admin uživatele
  • loginMiddleware - Ověří přihlášení uživatele na frontendu
  • logoutAdminMiddleware - Zpracuje admin odhlášení
  • logoutMiddleware - Zpracuje odhlášení

Input

  • adminAjaxDataMiddleware - Zpracovává AJAX data v adminu
  • adminCubeDataMiddleware - Zpracovává data kostek v adminu
  • csrfMiddleware - CSRF ochrana
  • sanitizationMiddleware - Čistí vstupní data

Log

  • loggingAdminMiddleware - Loguje akce v adminu

Request

  • proxyMiddleware - při proxy nastavuje globální $_SERVER proměnné

Response

  • headersMiddleware - Nastavuje response headery

Restriction

  • corsMiddleware - CORS pravidla
  • ipFilteringMiddleware - IP filtrování
  • publicEndpointsMiddleware - Povoluje veřejné datové endpointy

Request

  • sessionExpirationAdminMiddleware - kontroluje expiraci sessionu v adminu

URL

  • defineWebMiddleware - Definuje web kontext (URL, jazyk, atd.)
  • redirectionMiddleware - řeší přesměrovávání