Sessions
HTTP ist ein zustandsloses Protokoll; fast jede Anwendung muss jedoch den Zustand zwischen den Requests bewahren, etwa den Inhalt eines Warenkorbs. Genau dafür dienen Sessions. Wir zeigen Ihnen:
- wie man Sessions verwendet
- wie man Namenskonflikte vermeidet
- wie man die Ablaufzeit einstellt
Bei der Verwendung von Sessions erhält jeder Benutzer einen eindeutigen Bezeichner, die Session-ID, die in einem Cookie übertragen wird. Sie dient als Schlüssel zu den Session-Daten. Anders als Cookies, die auf der Seite des Browsers gespeichert werden, liegen die Session-Daten auf der Seite des Servers.
Sessions konfigurieren wir in der Konfiguration; besonders wichtig ist die Wahl der Ablaufzeit.
Um die Verwaltung der Session kümmert sich das Objekt Nette\Http\Session, das Sie sich per Dependency Injection übergeben lassen können. In
Presentern genügt der Aufruf $session = $this->getSession().
→ Installation und Anforderungen
Session starten
Standardmäßig startet Nette die Session automatisch in dem Moment, in dem wir beginnen, Daten aus ihr zu lesen oder in sie zu
schreiben. Um eine Session manuell zu starten, verwenden Sie $session->start().
PHP sendet beim Starten der Session HTTP-Header, die das Caching beeinflussen (siehe session_cache_limiter), und eventuell ein Cookie mit der Session-ID. Deshalb muss die Session immer gestartet werden, bevor irgendeine Ausgabe an den Browser gesendet wird; sonst wird eine Exception geworfen. Wenn Sie also wissen, dass beim Rendern der Seite eine Session verwendet wird, starten Sie sie vorher manuell, zum Beispiel im Presenter.
Im Entwicklungsmodus startet Tracy die Session, weil sie sie zur Anzeige der Bars für Weiterleitungen und AJAX-Requests in der Tracy Bar nutzt.
Abschnitte
In reinem PHP ist der Speicher für Session-Daten als Array umgesetzt, das über die globale Variable $_SESSION
zugänglich ist. Das Problem ist, dass Anwendungen üblicherweise aus vielen unabhängigen Teilen bestehen, und wenn allen nur ein
einziges Array zur Verfügung steht, kommt es früher oder später zu einer Namenskollision.
Das Nette Framework löst dieses Problem, indem es den gesamten Raum in Abschnitte aufteilt (Objekte vom Typ Nette\Http\SessionSection). Jede Einheit nutzt dann ihren eigenen Abschnitt mit einem eindeutigen Namen, und es kann zu keiner Kollision kommen.
Einen Abschnitt erhalten wir von der Session:
$section = $session->getSection('eindeutiger Name');
Im Presenter genügt getSession() mit einem Parameter:
// $this ist ein Presenter
$section = $this->getSession('eindeutiger Name');
Ob ein Abschnitt existiert, lässt sich mit der Methode $session->hasSection('eindeutiger Name') prüfen. Eine
Liste der Namen aller existierenden Abschnitte liefert $session->getSectionNames().
Die Arbeit mit dem Abschnitt selbst ist dann mit den Methoden set(), get() und remove()
sehr einfach:
// eine Variable schreiben
$section->set('userName', 'john');
// eine Variable lesen, gibt null zurück, wenn sie nicht existiert
echo $section->get('userName');
// eine Variable entfernen
$section->remove('userName');
Um alle Variablen eines Abschnitts zu erhalten, können Sie eine foreach-Schleife verwenden:
foreach ($section as $key => $val) {
echo "$key = $val";
}
Ablaufzeit einstellen
Die Ablaufzeit lässt sich für einzelne Abschnitte oder sogar für einzelne Variablen einstellen. Wir können die Anmeldung eines Benutzers nach 20 Minuten ablaufen lassen und uns den Inhalt des Warenkorbs trotzdem weiter merken.
// der Abschnitt läuft nach 20 Minuten ab
$section->setExpiration('20 minutes');
Um die Ablaufzeit für einzelne Variablen zu setzen, verwenden Sie den dritten Parameter der Methode set():
// die Variable 'flash' läuft nach 30 Sekunden ab
$section->set('flash', $message, '30 seconds');
Denken Sie daran, dass die Ablaufzeit der gesamten Session (siehe Session-Konfiguration) gleich oder größer sein muss als die für einzelne Abschnitte oder Variablen gesetzte Zeit.
Um eine zuvor gesetzte Ablaufzeit aufzuheben, verwenden Sie die Methode removeExpiration(); um die Ablaufzeit
einer bestimmten Variablen zu löschen, übergeben Sie ihren Namen: removeExpiration('flash'). Um den gesamten
Abschnitt sofort zu entfernen, verwenden Sie die Methode remove().
Events $onStart, $onBeforeWrite
Das Objekt Nette\Http\Session hat die Events
$onStart und $onBeforeWrite, Sie können also Callbacks hinzufügen, die nach dem Start der Session bzw.
vor dem Schreiben auf die Festplatte und dem anschließenden Beenden aufgerufen werden.
$session->onBeforeWrite[] = function () {
// Daten in die Session schreiben
$this->section->set('basket', $this->basket);
};
Session-Verwaltung
Übersicht der Methoden der Klasse Nette\Http\Session zur Verwaltung der Session:
start(): void
Startet die Session.
isStarted(): bool
Ist die Session gestartet?
close(): void
Beendet die Session. Die Session endet am Ende der Skriptausführung automatisch.
destroy(): void
Beendet und löscht die Session.
exists(): bool
Enthält der HTTP-Request ein Cookie mit einer Session-ID?
regenerateId(): void
Erzeugt eine neue zufällige Session-ID. Die Daten bleiben erhalten.
getId(): string
Gibt die Session-ID zurück.
Konfiguration
Die Session konfigurieren wir in der Konfiguration. Wenn Sie eine Anwendung schreiben, die keinen DI-Container verwendet, nutzen Sie zur Konfiguration diese Methoden. Sie müssen vor dem Start der Session aufgerufen werden.
setName (string $name): static
Setzt den Namen des Cookies, in dem die Session-ID übertragen wird. Der Standardname ist PHPSESSID. Das ist
nützlich, wenn Sie mehrere verschiedene Anwendungen auf derselben Website betreiben.
getName(): string
Gibt den Namen des Cookies zurück, in dem die Session-ID übertragen wird.
setOptions (array $options): static
Konfiguriert die Session. Es lassen sich alle Session-Direktiven von PHP setzen (im camelCase-Format,
schreiben Sie also z. B. savePath statt session.save_path) und außerdem readAndClose.
setExpiration (?string $expire): static
Setzt die Zeit der Inaktivität, nach der die Session abläuft.
setCookieParameters (string $path, ?string $domain=null, ?bool $secure=null, SameSite|string|null $samesite=null): static
Setzt die Parameter für Cookies. Die Standardwerte der Parameter können Sie in der Konfiguration ändern.
setSavePath (string $path): static
Setzt das Verzeichnis, in dem die Session-Dateien gespeichert werden.
setHandler (\SessionHandlerInterface $handler): static
Setzt einen eigenen Handler, siehe die PHP-Dokumentation.
Sicherheit geht vor
Der Server geht davon aus, dass er mit demselben Benutzer kommuniziert, solange die Requests dieselbe Session-ID mitbringen. Aufgabe der Sicherheitsmechanismen ist es, dafür zu sorgen, dass das auch tatsächlich so ist und der Bezeichner sich weder stehlen noch austauschen lässt.
Das Nette Framework konfiguriert die PHP-Direktiven deshalb richtig, sodass die Session-ID nur in Cookies übertragen wird, für JavaScript unzugänglich ist und Bezeichner in der URL ignoriert werden. Außerdem erzeugt es in kritischen Momenten, etwa bei der Anmeldung eines Benutzers, eine neue Session-ID.
Zur Konfiguration von PHP dient die Funktion ini_set, die manche Hoster leider verbieten. Wenn das
bei Ihrem Hoster der Fall ist, versuchen Sie mit ihm zu vereinbaren, dass er Ihnen diese Funktion erlaubt oder den Server
wenigstens richtig konfiguriert.