Middleware
Middleware allows you to run code before a request is completed. You can modify the response, rewrite, redirect, update headers, or respond directly.
Middleware
Middleware allows you to run code before a request is completed. Then, based on the incoming request, you can modify the response by rewriting, redirecting, modifying the request or response headers, or responding directly.
Use Cases
Integrating Middleware into your application can lead to significant improvements in performance, security, and user experience. Some common scenarios where Middleware is particularly effective include:
- Authentication – Verify user credentials before granting access.
- Authorization – Check roles and permissions before accessing resources.
- Logging – Log requests, responses, and errors for debugging and monitoring.
- Server-Side Redirects – Redirect users based on conditions (locale, role, etc.).
- Caching – Cache responses to improve performance and reduce load.
- Rate Limiting – Limit the number of requests by IP to prevent abuse.
- Compression – Compress responses to reduce bandwidth and improve load times.
Recognizing situations where middleware may not be optimal is just as important:
- Heavy Processing – Avoid expensive operations that slow requests.
- Blocking – Middleware that blocks execution may degrade performance.
- Over-Engineering – Keep middleware simple and focused.
- Security Risks – Avoid vulnerabilities such as injection attacks.
- Direct Database Operations – DB queries should be in route handlers or utilities.
Convention
Middleware in Prisma PHP is an app-owned convention, not a framework class. Middleware classes live in
src/Lib/Middleware and are called from
bootstrap.php. A generated project ships two of them:
-
CorsMiddleware— called at the very top ofbootstrap.php, before the session starts, so preflight requests never reach route resolution. -
AuthMiddleware— called inside route resolution with the resolved$pathname, so it can redirect before any route file is included.
Where each hook runs
The CORS hook is a top-level statement; the auth hook lives inside the private
Bootstrap::determineContentToInclude() method, between path resolution and route lookup.
Add your own middleware next to the existing call.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/settings/paths.php';
use Dotenv\Dotenv;
use Lib\Middleware\CorsMiddleware;
if (file_exists(DOCUMENT_PATH . '/.env')) {
Dotenv::createImmutable(DOCUMENT_PATH)->safeLoad();
}
// Runs before the session and before any routing work.
CorsMiddleware::handle();
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
use Lib\Middleware\AuthMiddleware;
final class Bootstrap extends RuntimeException
{
private static function determineContentToInclude(): array
{
$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
$requestUri = trim(self::uriExtractor($requestUri));
$scriptUrl = explode('?', $requestUri, 2)[0];
$pathname = trim($scriptUrl, '/');
/**
* ============ Middleware Management ============
* AuthMiddleware handles authentication for the current route.
* ================================================
*/
AuthMiddleware::handle($pathname);
// Place your custom middleware here.
/**
* ============ End of Middleware Management ======
* ================================================
*/
// ... route resolution continues
}
}
Do not reimplement what the runtime already does. CSRF and origin checks
(PP\Security\Csrf) and RPC rate limiting
(PP\Security\RateLimiter) are applied by the bootstrap on every
pp.rpc call.
Route-level access control belongs in
AuthConfig, and function-level
access control in #[Exposed(requiresAuth: true, allowedRoles: [...])].
Reach for custom middleware only for concerns none of those cover.
bootstrap.php is framework-managed. If you customise it, add it to
excludeFiles in prisma-php.json so a project update does
not overwrite your middleware wiring.