# Die Klasse SessionHandler

(PHP 5 >= 5.4.0, PHP 7, PHP 8)

## Einführung

SessionHandler ist eine spezielle Klasse, die verwendet werden kann, um den aktuellen internen PHP-Session-Speicherverwalter (PHP Session Save Handler) durch Vererbung zugänglich zu machen. Es gibt sieben Methoden, die die Wrapper für die sieben internen Callbacks des Session-Speicherverwalters sind (`open`, `close`, `read`, `write`, `destroy`, `gc` und `create_sid`). Standardmäßig ist diese Klasse der Wrapper für den internen Speicherverwalter, der durch die Konfigurationsdirektive session.save_handler definiert ist (normalerweise `files`). Andere interne Session-Speicherverwalter werden von PHP-Erweiterungen wie SQLite (als `sqlite`), Memcache (als `memcache`), und Memcached (als `memcached`) bereitgestellt.

Wenn eine einfache Instanz von SessionHandler mittels session_set_save_handler() als Speicherverwalter festgelegt wird, wird sie zum Wrapper für den aktuellen Speicherverwalter. Eine Klasse, die von SessionHandler abgeleitet ist, erlaubt es, Methoden zu überschreiben, abzufangen oder zu filtern, indem die Methoden der Elternklasse aufgerufen werden, die letztendlich Wrapper für die internen PHP-Sessionverwalter sind.

So können zum Beispiel die Methoden `read` und `write` abgefangen werden, um die Session-Daten zu verschlüsseln bzw. zu entschlüsseln und dann das Ergebnis an die übergeordnete Klasse zu übergeben. Alternativ könnte auch eine Methode wie der Garbage Collection Callback `gc` komplett überschrieben werden.

Da der SessionHandler ein Wrapper für die Methoden des aktuellen internen Speicherverwalters ist, kann das obige Beispiel der Verschlüsselung auf jeden internen Speicherverwalter angewendet werden, ohne dass die Interna des Verwalters bekannt sein müssen.

Um diese Klasse zu verwenden, muss zuerst der gewünschte Speicherverwalter mit session.save_handler festgelegt werden und dann eine Instanz von SessionHandler oder eine Erweiterung davon an session_set_save_handler() übergeben werden.

Es ist zu beachten, dass die Callback-Methoden dieser Klasse dazu gedacht sind, intern von PHP aufgerufen zu werden und nicht aus dem Anwenderprogramm aufgerufen werden sollen. Auch die Rückgabewerte werden intern von PHP verarbeitet. Weitere Informationen über den Ablauf von Sessions sind im Abschnitt session_set_save_handler() zu finden.

## Klassenbeschreibung

class SessionHandler implements SessionHandlerInterface, SessionIdInterface {
/* Methoden */
public function close(): bool
public function create_sid(): string
public function destroy(string `$id`): bool
public function gc(int `$max_lifetime`): int|false
public function open(string `$path`, string `$name`): bool
public function read(string `$id`): string|false
public function write(string `$id`, string `$data`): bool
}

## Anmerkungen

Warnung

Diese Klasse wurde entwickelt, um den aktuellen internen PHP-Session-Speicherverwalter darzustellen. Wenn eine eigene Speicherungsverwaltung benötigt wird, sollte die Schnittstelle SessionHandlerInterface implementiert werden, anstatt SessionHandler zu erweitern.

## Beispiele

Beispiel #1 Die Verwendung von SessionHandler, um den internen PHP-Speicherverwalter mit Verschlüsselung zu versehen

    <?php

     /**
      * decrypt AES 256
      *
      * @param data $edata
      * @param string $password
      * @return decrypted data
      */
    function decrypt($edata, $password) {
        $data = base64_decode($edata);
        $salt = substr($data, 0, 16);
        $ct = substr($data, 16);

        $rounds = 3; // abhängig von der Schlüssellänge
        $data00 = $password.$salt;
        $hash = array();
        $hash[0] = hash('sha256', $data00, true);
        $result = $hash[0];
        for ($i = 1; $i < $rounds; $i++) {
            $hash[$i] = hash('sha256', $hash[$i - 1].$data00, true);
            $result .= $hash[$i];
        }
        $key = substr($result, 0, 32);
        $iv  = substr($result, 32,16);

        return openssl_decrypt($ct, 'AES-256-CBC', $key, true, $iv);
      }

    /**
     * crypt AES 256
     *
     * @param data $data
     * @param string $password
     * @return base64 encrypted data
     */
    function encrypt($data, $password) {
        // Ein kryptographisch sicheres Zufallssalz mit random_bytes() erzeugen
        $salt = random_bytes(16);

        $salted = '';
        $dx = '';
        // key(32) und iv(16) mit Salz versehen = 48
        while (strlen($salted) < 48) {
          $dx = hash('sha256', $dx.$password.$salt, true);
          $salted .= $dx;
        }

        $key = substr($salted, 0, 32);
        $iv  = substr($salted, 32,16);

        $encrypted_data = openssl_encrypt($data, 'AES-256-CBC', $key, true, $iv);
        return base64_encode($salt . $encrypted_data);
    }

    class EncryptedSessionHandler extends SessionHandler
    {
        private $key;

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

        public function read($id)
        {
            $data = parent::read($id);

            if (!$data) {
                return "";
            } else {
                return decrypt($data, $this->key);
            }
        }

        public function write($id, $data)
        {
            $data = encrypt($data, $this->key);

            return parent::write($id, $data);
        }
    }

    // Wir verwenden den nativen 'files'-Handler, aber es funktioniert auch
    // mit anderen internen nativen Handlern wie 'sqlite', 'memcache' oder
    // 'memcached', die von PHP-Erweiterungen bereitgestellt werden.
    ini_set('session.save_handler', 'files');

    $key = 'secret_string';
    $handler = new EncryptedSessionHandler($key);
    session_set_save_handler($handler, true);
    session_start();

    // Fortfahren mit dem Setzen und Abrufen von Werten anhand der
    // Schlüssel von $_SESSION

> Hinweis:

> Da die Methoden dieser Klasse so konzipiert sind, dass sie als Teil des normalen Ablaufs einer Session intern von PHP aufgerufen werden, geben Aufrufe der Kindklasse an die Elternmethoden (d. h. die eigentlichen internen nativen Prozeduren) `false` zurück, es sei denn, die Session wurde tatsächlich gestartet (entweder automatisch oder durch den expliziten Aufruf von session_start()). Es ist wichtig, dies beim Schreiben von Unit-Tests zu beachten, bei denen die Methoden der Klasse manuell aufgerufen werden können.

## Inhaltsverzeichnis

- SessionHandler::close — Schließt eine Session
- SessionHandler::create_sid — Liefert eine neue Session-ID
- SessionHandler::destroy — Löscht eine Session
- SessionHandler::gc — Löscht alte Sessions
- SessionHandler::open — Initialisiert eine Session
- SessionHandler::read — Ruft die Session-Daten ab
- SessionHandler::write — Speichert die Session-Daten

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open