Skip to content

Middlewares PSR-15

Middleware řídí tok požadavku skrz aplikaci: auth, CSRF, session, CORS, logování, hlavičky a další cross-cutting logiku.

Petrovo CMS používá vlastní PSR-15 pipeline Core\Middleware.

Koncept

Middleware v Petrovo:

use function Core\Middleware\pipe;
use function Core\Route\dispatch;
use function Core\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 Core\Middleware

use function Core\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 Core\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 Core\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 Core\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, 'website');

Implementované middlewares

Middleware soubory se autoloadují přes composer.json sekci "files":

{
  "autoload": {
    "files": [
      "app/Middlewares/Auth/authAdminMiddleware.php",
      "app/Middlewares/Auth/permissionAdminMiddleware.php",
      "app/Middlewares/Auth/authMiddleware.php",
      "app/Middlewares/Input/csrfAdminMiddleware.php",
      "app/Middlewares/Input/csrfMiddleware.php",
      "app/Middlewares/Log/loggingAdminMiddleware.php",
      "app/Middlewares/Request/proxyMiddleware.php",
      "app/Middlewares/Response/headersMiddleware.php",
      "app/Middlewares/Restriction/corsMiddleware.php",
      "app/Middlewares/Restriction/ipBlacklistMiddleware.php",
      "app/Middlewares/Restriction/ipFilteringMiddleware.php",
      "app/Middlewares/Session/sessionExpirationAdminMiddleware.php",
      "app/Middlewares/Url/redirectionMiddleware.php"
    ]
  }
}

Struktura middleware souboru:

<?php
declare(strict_types=1);

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

Aktuální skupiny middleware

Auth

  • authAdminMiddleware kontroluje admin session a passkey login flow
  • permissionAdminMiddleware hlídá admin oprávnění
  • authMiddleware řeší autentizaci na frontendu

Input

  • csrfAdminMiddleware ověřuje CSRF v adminu
  • csrfMiddleware ověřuje CSRF na website a /RUN

Log

  • loggingAdminMiddleware loguje admin akce

Request

  • proxyMiddleware upravuje request/server kontext za proxy

Response

  • headersMiddleware nastavuje response hlavičky

Restriction

  • corsMiddleware řeší CORS
  • ipBlacklistMiddleware blokuje blacklistované IP
  • ipFilteringMiddleware řeší IP omezení v jiných částech systému

Session

  • sessionExpirationAdminMiddleware řeší timeout a obnovu admin session

Url

  • redirectionMiddleware řeší redirect logiku starých URL