Skip to content

Usage

Engine lifecycle

The GuardEngine facade composes config, route resolution, Redis, the IP ban manager, the rate limit handler, and the check pipeline.

$config = new SecurityConfig(
    enableRedis: true,
    redisPrefix: 'guard_core:',
    enableRateLimiting: true,
    rateLimit: 30,
    rateLimitWindow: 60,
);

$engine = new GuardEngine($config);
// Connects Redis when enabled and initializes ban/rate-limit state.
// Call once before the first execute().
$engine->initialize();

Exposed accessors: config(), redis(), banManager(), rateLimitHandler(), cloudManager(), responseFactory(), pipeline().

The request contract

Adapters (or your own middleware) translate native requests into a GuardRequest implementation. SimpleGuardRequest covers the common shape:

$request = new SimpleGuardRequest(
    urlPath: '/api',
    urlScheme: 'http',
    host: 'example.com',
    method: 'POST',
    clientHost: '203.0.113.9',   // null lets the engine resolve from headers
    headers: ['content-type' => 'application/json'],
    queryParams: ['q' => 'value'],
    body: '{"key": "value"}',
);

Pass clientHost: null to have the engine resolve the client IP through ClientIpResolver using trustedProxies and the forwarded header chain. A RequestState carries per-request resolution results (clientIp, guardRouteId, bypass flags); seed your own instance to attach route IDs.

Checking requests

$verdict = $engine->execute($request);
if ($verdict !== null) {
    // Blocked. Write $verdict->statusCode(), $verdict->headers(), $verdict->body().
}

Well-known block verdicts:

Situation Status Body
Banned IP 403 IP address banned
Auto-ban during detection 403 IP has been banned
Suspicious content 400 Suspicious activity detected
Rate limit exceeded 429 Too many requests (fixed body in this port; customErrorResponses does not tune 429)

All other default bodies can be overridden through customErrorResponses.

Managers

The managers are usable on their own for admin tooling:

// IP bans
$engine->banManager()->ban('192.0.2.10', 3600, 'manual');
$engine->banManager()->isIpBanned('192.0.2.10');
$engine->banManager()->unban('192.0.2.10');

// Redis state (built-in RESP2 client; REDIS_HOST / REDIS_PORT env respected)
$engine->redis()->ping();

Bans that overlap loopback or a configured trusted proxy are refused (the manager warns and returns false) so a deployment cannot ban itself.

The block hook

SecurityConfig(onBlock: Closure(object $request, array $payload): void) is the telemetry seam. The pipeline fires it for every block or passive detection verdict with a flat payload: check_name, reason, trigger_info, passive_mode, client_ip, path, method, and status_code. The hook is panic-guarded (throwing hooks are swallowed) and never alters the verdict.

Conformance

php bin/conformance.php replays the shared JSON fixture corpus (tests/Conformance/guard-core-spec-4.0.2/) generated from the Python engine and compares verdicts field by field, so any detector change that would drift from the reference fails CI. Never hand-edit expected values or the generated tables under src/Support/Generated/.