Alpha ZealPHP is early-stage and under active development. APIs may change between minor versions until v1.0. Feedback and bug reports welcome on GitHub.
API Index — Namespaces, Packages, Reports, Indices

HeaderMiddleware
in package
implements MiddlewareInterface

Header Middleware

Declarative response-header manipulation. The most common use case is stamping security headers (X-Frame-Options, CSP, Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) onto every response without sprinkling $response->header(...) calls through handlers.

Apache equivalent (mod_headers):

Header set X-Frame-Options "DENY"
Header append Vary "Accept-Encoding"
Header unset Server
Header add Set-Cookie "..."

nginx equivalent:

add_header X-Frame-Options "DENY" always;
more_clear_headers Server;   # ngx_headers_more module

Status-conditional application (nginx parity)

nginx add_header applies headers only on safe-status responses (200, 201, 204, 206, 301, 302, 303, 304, 307, 308) unless the always keyword is present. ZealPHP mirrors this behaviour through two knobs:

  1. Constructor $alwaysByDefault (default true): when true every rule behaves like nginx add_header ... always — headers are applied to ALL responses regardless of status. Set to false to switch the middleware into nginx-default mode where set/add/append rules are skipped on non-safe-status responses unless the per-rule always flag overrides them.

    BC note: the default is true (apply to all statuses) to preserve the behaviour of existing ZealPHP apps. nginx migrants who want exact add_header-without-always parity should pass false.

  2. Per-rule always flag inside set/add/append entries: wrap a value in ['value' => '...', 'always' => true] to force a specific rule to apply on all statuses even when $alwaysByDefault = false. unset rules are always unconditional — they run on every response status.

Safe statuses (matching nginx ngx_http_headers_filter_module.c:217-233): 200, 201, 204, 206, 301, 302, 303, 304, 307, 308.

Constructor accepts a config array with four operations:

  • set: overwrite the header value (replaces existing)
  • add: append a value (like Apache Header add — emits multiple lines)
  • append: append to existing value comma-separated (like Header append Vary "X")
  • unset: list of headers to strip from the response (always unconditional)

Each rule value may be a plain string (or array for add) or an associative array with 'value' and optional 'always' keys: 'set' => ['X-Frame-Options' => ['value' => 'DENY', 'always' => true]]

Usage in app.php — current default (all-status, BC-safe):

$app->addMiddleware(new \ZealPHP\Middleware\HeaderMiddleware([
    'set' => [
        'X-Frame-Options'            => 'DENY',
        'X-Content-Type-Options'     => 'nosniff',
        'Referrer-Policy'            => 'strict-origin-when-cross-origin',
        'Strict-Transport-Security'  => 'max-age=31536000; includeSubDomains',
        'Content-Security-Policy'    => "default-src 'self'",
    ],
    'append' => ['Vary' => 'Accept-Encoding'],
    'unset'  => ['Server', 'X-Powered-By'],
]));

Usage with nginx semantics (skip on error responses unless always=true):

$app->addMiddleware(new \ZealPHP\Middleware\HeaderMiddleware([
    'set' => [
        // Skipped on 4xx/5xx (nginx default behaviour).
        'Cache-Control' => 'no-cache',
        // Always applied even on error responses.
        'X-Frame-Options' => ['value' => 'DENY', 'always' => true],
    ],
    'unset' => ['Server'],   // unset is always unconditional
], alwaysByDefault: false));

Table of Contents

Interfaces

MiddlewareInterface

Constants

SAFE_STATUSES  : array<string|int, int> = [200, 201, 204, 206, 301, 302, 303, 304, 307, 308]
nginx safe-status set: responses on which add_header fires without always.

Properties

$add  : array<string, array<int, array{value: string, always: bool}>>
Normalised add rules: name => list<array{value: string, always: bool}>.
$append  : array<string, array{value: string, always: bool}>
Normalised append rules: name => ['value' => string, 'always' => bool].
$set  : array<string, array{value: string, always: bool}>
Normalised set rules: name => ['value' => string, 'always' => bool].
$unset  : array<string|int, string>

Methods

__construct()  : mixed
process()  : ResponseInterface
normaliseAddRules()  : array<string, array<int, array{value: string, always: bool}>>
Normalise add config entries into a uniform shape.
normaliseScalarRules()  : array<string, array{value: string, always: bool}>
Normalise set and append config entries into a uniform shape.

Constants

SAFE_STATUSES

nginx safe-status set: responses on which add_header fires without always.

private array<string|int, int> SAFE_STATUSES = [200, 201, 204, 206, 301, 302, 303, 304, 307, 308]

Source: ngx_http_headers_filter_module.c:221-232.

Properties

$add

Normalised add rules: name => list<array{value: string, always: bool}>.

private array<string, array<int, array{value: string, always: bool}>> $add

$append

Normalised append rules: name => ['value' => string, 'always' => bool].

private array<string, array{value: string, always: bool}> $append

$set

Normalised set rules: name => ['value' => string, 'always' => bool].

private array<string, array{value: string, always: bool}> $set

Methods

__construct()

public __construct([array{set?: array, add?: array, append?: array, unset?: string[]} $config = [] ][, bool $alwaysByDefault = true ]) : mixed
Parameters
$config : array{set?: array, add?: array, append?: array, unset?: string[]} = []
$alwaysByDefault : bool = true

When true (the default), every rule applies to ALL responses regardless of HTTP status — this is ZealPHP's historical behaviour (equivalent to nginx always on every rule). Set to false for nginx-default mode: set/add/append rules are skipped on non-safe-status responses unless the per-rule always flag is explicitly set. unset rules are always unconditional in both modes.

process()

public process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
Parameters
$request : ServerRequestInterface
$handler : RequestHandlerInterface
Return values
ResponseInterface

normaliseAddRules()

Normalise add config entries into a uniform shape.

private normaliseAddRules(array<string, string|array<string|int, string>|array{value: string|string[], always?: bool}> $rules, bool $alwaysByDefault) : array<string, array<int, array{value: string, always: bool}>>

Input allows: string, string[], or array{value: string|string[], always?: bool} Output: array<string, list<array{value: string, always: bool}>>

Parameters
$rules : array<string, string|array<string|int, string>|array{value: string|string[], always?: bool}>
$alwaysByDefault : bool
Return values
array<string, array<int, array{value: string, always: bool}>>

normaliseScalarRules()

Normalise set and append config entries into a uniform shape.

private normaliseScalarRules(array<string, string|array{value: string, always?: bool}> $rules, bool $alwaysByDefault) : array<string, array{value: string, always: bool}>

Input: array<string, string|array{value: string, always?: bool}> Output: array<string, array{value: string, always: bool}>

Parameters
$rules : array<string, string|array{value: string, always?: bool}>
$alwaysByDefault : bool
Return values
array<string, array{value: string, always: bool}>
On this page