Cache-Control in PHP konfigurieren

Schritt-für-Schritt-Anleitung: Cache-Control in PHP — mit differenzierten Strategien für dynamische Seiten, APIs und statische Assets.

PHP · Schritt für Schritt

Cache-Control in PHP

Cache-Control steuert, wie Browser und Proxies Ihre Inhalte cachen. Falsches Caching kann dazu fuehren, dass vertrauliche Daten in öffentlichen Caches landen oder veraltete Inhalte angezeigt werden. Mit 8 von 166 Punkten im Wolf-Agents Web Security Check ist Cache-Control ein wichtiger Sicherheits- und Performance-Header.

In PHP setzen Sie Cache-Control per header(). Der entscheidende Unterschied: Dynamische PHP-Seiten (Login, Dashboard) brauchen no-store, während statische Assets (CSS, JS, Bilder) von aggressivem Caching profitieren. Die auto_prepend_file-Methode eignet sich hier als sicherer Default (no-store), den einzelne Scripts gezielt überschreiben können.

Für Frameworks wie Laravel oder Symfony empfehlen wir eine PSR-15-Middleware, die Cache-Control basierend auf dem Response-Typ setzt. So bekommen HTML-Seiten no-store, während JSON-APIs und statische Ressourcen differenziert gecached werden können.

1 Schritt 1 von 3

Cache-Control in PHP konfigurieren

Drei Implementierungsvarianten: Direkter header()-Aufruf mit differenzierten Strategien, auto_prepend_file als sicherer Default, und PSR-15-Middleware für intelligentes Content-Type-basiertes Caching.

security-headers.php Direkt
<?php
// security-headers.php — Cache-Control

if (!headers_sent()) {
    // Dynamische Seiten: Kein Caching
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Pragma: no-cache');
}

// Fuer statische API-Responses:
// header('Cache-Control: public, max-age=300, s-maxage=600');

// Fuer unveraenderliche Assets (versioniert):
// header('Cache-Control: public, max-age=31536000, immutable');
.user.ini Auto-Prepend
; .user.ini — Cache-Control als Default
; Setzt no-store fuer ALLE PHP-Seiten als sicheren Default

auto_prepend_file = "/var/www/html/security-headers.php"

; ACHTUNG: no-store global = kein Browser-Caching
; Einzelne Scripts koennen den Header ueberschreiben
; PHP-FPM Cache-TTL: 5 Minuten
; Nach Aenderung: systemctl restart php-fpm
src/Middleware/CacheControlMiddleware.php PSR-15
<?php
// src/Middleware/CacheControlMiddleware.php — PSR-15

namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class CacheControlMiddleware implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        $response = $handler->handle($request);
        $contentType = $response->getHeaderLine('Content-Type');

        if (str_contains($contentType, 'text/html')) {
            return $response->withHeader(
                'Cache-Control',
                'no-store, no-cache, must-revalidate'
            );
        }
        return $response->withHeader(
            'Cache-Control',
            'public, max-age=3600'
        );
    }
}
Differenziertes Caching

Setzen Sie no-store nicht pauschal für alle Seiten. Login-Seiten und Dashboards brauchen no-store, öffentliche Seiten profitieren von max-age. APIs können mit s-maxage CDN-Caching nutzen, während der Browser-Cache kurz gehalten wird.

2 Schritt 2 von 3

Konfiguration verifizieren

Prüfen Sie den Cache-Control-Header mit curl. Testen Sie sowohl dynamische PHP-Seiten als auch statische Assets. Beachten Sie: PHP header() wirkt nur für PHP-Dateien — statische Dateien brauchen die Webserver-Konfiguration.

Terminal Verifizierung
# Cache-Control pruefen
curl -sI https://ihre-domain.de | grep -i cache-control

# Erwartete Ausgabe fuer dynamische Seiten:
Cache-Control: no-store, no-cache, must-revalidate

# Statische Assets pruefen (Webserver-Config):
curl -sI https://ihre-domain.de/style.css | grep -i cache-control
Nutzen Sie den Wolf-Agents Web Security Check für eine vollständige Prüfung aller 8 Punkte dieses Headers.
3 Schritt 3 von 3

Häufige Fehler

Headers already sent

Der haeufigste PHP-Fehler: header() nach einer Ausgabe aufrufen. Nutzen Sie auto_prepend_file in der .user.ini oder setzen Sie den Header frueh in Ihrer index.php. Eine BOM oder ein Leerzeichen vor <?php zaehlt als Ausgabe.

no-store auf statischen Assets

Wenn auto_prepend_file global no-store setzt, werden auch PHP-generierte Assets (z.B. dynamische Bilder, PDF-Exporte) nicht gecached. Überschreiben Sie den Header gezielt in diesen Scripts mit max-age.

Pragma vs. Cache-Control

Pragma: no-cache ist ein HTTP/1.0-Header. Für moderne Browser reicht Cache-Control. Setzen Sie Pragma nur für Kompatibilität mit sehr alten Proxies — schadet aber nicht.

PHP OPcache verwechselt

PHP OPcache (für Bytecode-Caching) und HTTP Cache-Control (für Browser-Caching) sind voellig unterschiedliche Systeme. OPcache beeinflusst nicht, wie Browser Seiten cachen. Aenderungen an Cache-Control benoetigen keinen OPcache-Reset.

Compliance-Relevanz

OWASP ASVS — V14.4.7 — Sensible Responses müssen Cache-Control: no-store setzen.
BSI — APP.3.1 — Sichere Caching-Konfiguration für Webanwendungen.
PCI DSS 4.0 — Anforderung 6.5.10 — Verhinderung von Informationslecks durch Caching.
NIS2 — Art. 21(e) — Sicherheit bei der Wartung von Informationssystemen.

Wie steht Ihre Domain bei Cache-Control?

Prüfen Sie es jetzt — kostenlos, ohne Registrierung, mit 166 Prüfpunkte.