Start · Sprachen · PHP · Referenz · session_set_save_handler

session_set_save_handler

Funktion

Registriert benutzerdefinierte Callback-Funktionen oder ein <code>SessionHandlerInterface</code>-Objekt als Session-Speicher-Backend.

seit PHP 4.0.0 Kategorie: http

Signatur

session_set_save_handler(callable $open, callable $close, callable $read, callable $write, callable $destroy, callable $gc, callable $create_sid = ?, callable $validate_sid = ?, callable $update_timestamp = ?): bool

Beschreibung

session_set_save_handler() ermöglicht es, den Standard-Session-Speichermechanismus von PHP (üblicherweise Dateien) durch eine eigene Implementierung zu ersetzen. Typische Anwendungsfälle sind das Speichern von Sessions in einer Datenbank, einem Redis-Cache, Memcached oder einem anderen verteilten Speicher — zum Beispiel wenn mehrere Web-Server auf denselben Session-Zustand zugreifen müssen.

Ab PHP 5.4 kann statt einzelner Callbacks auch ein Objekt übergeben werden, das das Interface SessionHandlerInterface implementiert. Das ist die bevorzugte, objektorientierte Variante. Ein optionaler zweiter Parameter register_shutdown (Standard: true) sorgt dafür, dass session_write_close() automatisch als Shutdown-Funktion registriert wird.

Die Callbacks werden in folgender Reihenfolge aufgerufen: openread → (Skriptausführung) → writeclose. Der Garbage-Collector-Callback gc wird probabilistisch basierend auf den INI-Einstellungen session.gc_probability und session.gc_divisor aufgerufen. Mit PHP 7.0 kamen create_sid, validate_sid und update_timestamp als optionale Erweiterungen hinzu.

Wichtig: session_set_save_handler() muss zwingend vor session_start() aufgerufen werden, damit der eigene Handler aktiv wird.

Parameter

Name Typ Default Beschreibung
$open Pflicht callable Wird beim Öffnen der Session aufgerufen. Signatur: open(string $savePath, string $sessionName): bool. Erhält den Speicherpfad und den Session-Namen.
$close Pflicht callable Wird nach dem Schreiben der Session aufgerufen, um Ressourcen freizugeben. Signatur: close(): bool.
$read Pflicht callable Liest die serialisierten Session-Daten für eine gegebene Session-ID. Signatur: read(string $sessionId): string|false. Muss einen leeren String zurückgeben, wenn keine Daten vorhanden sind.
$write Pflicht callable Schreibt die serialisierten Session-Daten. Signatur: write(string $sessionId, string $data): bool.
$destroy Pflicht callable Löscht eine Session anhand ihrer ID (z. B. bei session_destroy()). Signatur: destroy(string $sessionId): bool.
$gc Pflicht callable Garbage-Collector: Entfernt abgelaufene Sessions. Signatur: gc(int $maxlifetime): int|false. Erhält die maximale Lebensdauer in Sekunden.
$create_sid callable Erzeugt eine eindeutige Session-ID. Signatur: create_sid(): string. Optional, verfügbar ab PHP 5.5.1.
$validate_sid callable Prüft, ob eine Session-ID gültig und im Speicher vorhanden ist. Signatur: validate_sid(string $sessionId): bool. Optional, verfügbar ab PHP 7.0.
$update_timestamp callable Aktualisiert den Zeitstempel einer Session ohne die Daten zu verändern. Signatur: update_timestamp(string $sessionId, string $data): bool. Optional, verfügbar ab PHP 7.0.

Rückgabewert

Typ
bool
Beschreibung
Gibt true bei Erfolg zurück, false bei einem Fehler (z. B. wenn die Funktion nach session_start() aufgerufen wird).

Beispiele

Datenbankbasierter Session-Handler mit SessionHandlerInterface

<?php
class PdoSessionHandler implements SessionHandlerInterface
{
    private PDO $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function open(string $savePath, string $sessionName): bool
    {
        return true; // Verbindung bereits im Konstruktor hergestellt
    }

    public function close(): bool
    {
        return true;
    }

    public function read(string $id): string|false
    {
        $stmt = $this->pdo->prepare(
            'SELECT data FROM sessions WHERE id = :id AND expires_at > NOW()'
        );
        $stmt->execute([':id' => $id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        return $row ? $row['data'] : '';
    }

    public function write(string $id, string $data): bool
    {
        $stmt = $this->pdo->prepare(
            'INSERT INTO sessions (id, data, expires_at)
             VALUES (:id, :data, DATE_ADD(NOW(), INTERVAL :lifetime SECOND))
             ON DUPLICATE KEY UPDATE data = :data,
             expires_at = DATE_ADD(NOW(), INTERVAL :lifetime SECOND)'
        );
        $lifetime = (int) ini_get('session.gc_maxlifetime');
        return $stmt->execute([':id' => $id, ':data' => $data, ':lifetime' => $lifetime]);
    }

    public function destroy(string $id): bool
    {
        $stmt = $this->pdo->prepare('DELETE FROM sessions WHERE id = :id');
        return $stmt->execute([':id' => $id]);
    }

    public function gc(int $maxlifetime): int|false
    {
        $stmt = $this->pdo->prepare('DELETE FROM sessions WHERE expires_at < NOW()');
        $stmt->execute();
        return $stmt->rowCount();
    }
}

$pdo = new PDO('mysql:host=localhost;dbname=app', 'user', 'secret');
$handler = new PdoSessionHandler($pdo);

// Handler registrieren — MUSS vor session_start() stehen!
session_set_save_handler($handler, true);
session_start();

$_SESSION['user_id'] = 42;
echo 'Session gestartet: ' . session_id();
Session gestartet: abc123def456...

Einfacher In-Memory-Handler mit einzelnen Callbacks (Debugging/Tests)

<?php
$storage = [];

session_set_save_handler(
    open: function(string $path, string $name): bool {
        return true;
    },
    close: function(): bool {
        return true;
    },
    read: function(string $id) use (&$storage): string {
        return $storage[$id] ?? '';
    },
    write: function(string $id, string $data) use (&$storage): bool {
        $storage[$id] = $data;
        return true;
    },
    destroy: function(string $id) use (&$storage): bool {
        unset($storage[$id]);
        return true;
    },
    gc: function(int $maxlifetime): int {
        return 0; // In-Memory: kein Ablauf
    }
);

session_start();
$_SESSION['test'] = 'Hallo Welt';
session_write_close();

echo 'Gespeicherte Sessions: ' . count($storage);
Gespeicherte Sessions: 1

// Wichtig · Fallstricke

Sicherheit: Bei datenbankbasierter Session-Speicherung immer Prepared Statements verwenden, um SQL-Injection über Session-IDs zu verhindern. Session-IDs können prinzipiell manipuliert werden, wenn keine Validierung erfolgt.

Reihenfolge ist entscheidend: session_set_save_handler() muss vor session_start() aufgerufen werden. Ein Aufruf danach hat keine Wirkung und gibt false zurück.

Shutdown-Registrierung: Der zweite Parameter register_shutdown beim objektbasierten Aufruf ist standardmäßig true. Das ist empfehlenswert, weil PHP sonst unter Umständen die Session nicht korrekt abschließt, wenn das Skript durch exit() oder einen fatalen Fehler beendet wird.

Serialisierung: PHP serialisiert die Session-Daten selbst — im read- und write-Callback wird immer mit rohen, serialisierten Strings gearbeitet. Das Format wird durch session.serialize_handler bestimmt.