Rufe session_start() am Anfang einer Seite auf und lies und schreib dann $_SESSION['key'] wie jedes Array: PHP speichert es auf dem Server und findet es bei der nächsten Anfrage des Besuchers wieder. Für einen kleinen Wert, den der Browser behalten soll, rufst du setcookie('name', 'value', time() + 86400) auf und liest ihn bei späteren Anfragen aus $_COOKIE['name'] zurück.
<?php
session_start(); // before any output
setcookie('theme', 'dark', time() + 60 * 60 * 24 * 30); // 30 days, also before output
$_SESSION['visits'] = ($_SESSION['visits'] ?? 0) + 1;
$theme = $_COOKIE['theme'] ?? 'light'; // set on an earlier visit
echo "You have opened this page {$_SESSION['visits']} times.";
Sessions und Cookies ergeben nur über mehrere HTTP-Anfragen eines Browsers Sinn, also sind die Beispiele, die einen brauchen, einfacher Code. Die Logik drumherum ist gewöhnliches PHP mit Arrays, und dieser Teil läuft hier: In jedem ausführbaren Block steht $session für $_SESSION, und jeder Aufruf ist eine Anfrage.
Wie eine PHP-Session funktioniert
- Das erste
session_start()erzeugt eine zufällige ID, schickt sie in einem Cookie namensPHPSESSIDan den Browser und gibt dir ein leeres$_SESSION. - Am Ende der Anfrage speichert PHP
$_SESSIONauf dem Server (standardmäßig in Dateien, oder in Redis oder einer Datenbank). - Bei der nächsten Anfrage schickt der Browser das Cookie zurück,
session_start()liest die ID und lädt das gespeicherte Array.
Der Browser sieht nie die Daten, nur die ID. Deshalb gehört die ID des angemeldeten Nutzers in $_SESSION und nie in ein eigenes Cookie: Ein Besucher kann seine Cookies auf jeden beliebigen Wert ändern, aber $_SESSION kann er nicht ändern.
Einen Nutzer mit einer Session an- und abmelden
Anmelden heißt: das Passwort prüfen, die Session-ID neu erzeugen, die Nutzer-ID speichern. Abmelden ist das Umgekehrte und hat drei Schritte.
<?php
// login.php
session_start();
$user = find_user_by_email($_POST['email'] ?? '');
if ($user && password_verify($_POST['password'] ?? '', $user['password_hash'])) {
session_regenerate_id(true); // new id after login: stops session fixation
$_SESSION['user_id'] = $user['id'];
header('Location: /dashboard.php');
exit;
}
$error = 'Wrong email or password.';
<?php
// any protected page
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: /login.php');
exit;
}
<?php
// logout.php
session_start();
$_SESSION = []; // 1. forget the data
$p = session_get_cookie_params(); // 2. delete the cookie
setcookie(session_name(), '', time() - 3600, $p['path'], $p['domain'], $p['secure'], $p['httponly']);
session_destroy(); // 3. delete the stored session
header('Location: /');
exit;
session_regenerate_id(true) ist wichtiger, als es aussieht. Wenn ein Angreifer ein Opfer dazu bringen kann, eine Session-ID zu verwenden, die der Angreifer kennt (zum Beispiel über einen Link), und die ID nach dem Login gleich bleibt, ist der Angreifer ebenfalls angemeldet. Eine frische ID beim Login schließt diese Lücke. Das Prüfen des Passworts selbst behandelt die Seite zu password_hash.
Eine Session nach Inaktivität ablaufen lassen
PHPs eigene Aufräumarbeit (session.gc_maxlifetime, standardmäßig 1440 Sekunden) läuft zufällig und ist kein verlässlicher Timeout. Speichere die Zeit der letzten Anfrage und prüfe sie selbst. Der Block verwendet feste Timestamps, damit du jeden Fall siehst; ändere $timeout oder die Zeiten.
Der Abstand von 09:05 bis 09:16:40 beträgt 700 Sekunden, unter der Grenze von 15 Minuten, also bleibt der Nutzer angemeldet. Der nächste Abstand beträgt 1000 Sekunden, also wird die Session geleert.
Flash-Meldungen
Eine Flash-Meldung wird bei einer Anfrage gesetzt und bei der nächsten einmal angezeigt, typischerweise „Saved.“ nach einer Weiterleitung. Speichere sie in der Session, dann liest und entfernst du sie in einem Schritt:
Ein Cookie mit setcookie setzen
setcookie() nimmt den Namen, den Wert und ein Options-Array (PHP 7.3 und neuer). Setze diese vier Optionen bei jedem Cookie, außer du hast einen Grund dagegen:
<?php
setcookie('theme', 'dark', [
'expires' => time() + 60 * 60 * 24 * 30, // 30 days; 0 means "until the browser closes"
'path' => '/', // send it on every page, not just this folder
'secure' => true, // only over HTTPS
'httponly' => true, // JavaScript cannot read it
'samesite' => 'Lax', // not sent on most cross-site requests
]);
$theme = $_COOKIE['theme'] ?? 'light';
Zwei Dinge bringen Leute zum Stolpern:
$_COOKIEändert sich nicht in derselben Anfrage. Es enthält, was der Browser mit dieser Anfrage gesendet hat. Ein Cookie, das du jetzt setzt, taucht bei der nächsten Anfrage in$_COOKIEauf.- Cookies sind Header, also muss
setcookie()vor jeder Ausgabe laufen, genau wiesession_start()undheader().
Um ein Cookie zu löschen, setzt du es erneut mit demselben Namen und path und einem Ablaufdatum in der Vergangenheit: setcookie('theme', '', ['expires' => time() - 3600, 'path' => '/']).
Ein Array in einem Cookie speichern
Ein Cookie-Wert ist ein String von höchstens etwa 4 KB, also speicherst du strukturierte Daten als JSON und behandelst, was zurückkommt, als nicht vertrauenswürdig: Der Besucher kann es ändern. Rufe nie unserialize() auf ein Cookie auf: Es kann Objekte deiner eigenen Klassen erzeugen und deren magische Methoden ausführen, während json_decode() immer nur Arrays, Strings, Zahlen, Booleans, null oder stdClass liefert.
Die Seite zu json_encode behandelt die Flags. Für alles, was größer ist als ein paar kurze Werte, behältst du die Daten in der Session (oder einer Datenbank) und speicherst im Cookie nur einen Schlüssel.
Tokens für „angemeldet bleiben“
Ein Cookie für „angemeldet bleiben“ darf weder die Nutzer-ID noch den Passwort-Hash enthalten. Speichere ein langes zufälliges Token im Cookie und nur seinen Hash in der Datenbank, und vergleiche mit hash_equals():
Die Werte ändern sich bei jedem Durchlauf, weil random_bytes() zufällig ist. Wenn die Datenbank leakt, sind die Hashes ohne die Cookies nutzlos, und hash_equals() vergleicht in konstanter Zeit, sodass die Prüfung keine Zeitinformationen preisgibt.
Session oder Cookie: was du verwenden solltest
Session ($_SESSION) | Cookie ($_COOKIE) | |
|---|---|---|
| Gespeichert | Auf dem Server | Im Browser |
| Der Besucher kann es lesen oder ändern | Nein (nur die ID) | Ja |
| Größe | Begrenzt durch deinen Speicher | Etwa 4 KB pro Cookie |
| Hält | Bis der Browser schließt oder die Session abläuft | Bis zu seiner Zeit expires |
| Verwenden für | Angemeldeter Nutzer, Warenkorb, CSRF-Token, Flash-Meldungen | Theme, Sprache, Einwilligung, Token für „angemeldet bleiben“ |
Typischer Fehler: headers already sent
session_start(), setcookie() und header() senden alle HTTP-Header, und Header lassen sich nur vor dem Body senden. Jede Ausgabe vorher, sogar eine Leerzeile vor <?php in einer eingebundenen Datei, erzeugt:
Warning: session_start(): Session cannot be started after headers have already been sent in /var/www/page.php on line 3
Warning: Cannot modify header information - headers already sent by (output started at /var/www/page.php:2) in /var/www/page.php on line 4
Die zweite Meldung sagt dir, wo die Ausgabe begonnen hat (page.php:2): Geh zu dieser Zeile und entferne die Ausgabe oder setze session_start() darüber. In Dateien, die nur PHP enthalten, verhindert das Weglassen des schließenden ?>, dass verirrter Leerraum danach zur Ausgabe wird.
Häufig gestellte Fragen
Was ist der Unterschied zwischen einer Session und einem Cookie in PHP?
Ein Cookie wird im Browser des Besuchers gespeichert und mit jeder Anfrage gesendet, also kann der Besucher es lesen und ändern. Eine Session speichert ihre Daten auf dem Server; der Browser hält nur eine zufällige Session-ID in einem Cookie (PHPSESSID). Leg alles, dem vertraut werden muss, etwa die ID des angemeldeten Nutzers, in $_SESSION ab.
Wie zerstöre ich in PHP eine Session beim Abmelden?
Leere die Daten, lösche das Session-Cookie und zerstöre die gespeicherte Session: $_SESSION = [];, dann setcookie(session_name(), '', time() - 3600, '/'), dann session_destroy();. Leite danach weiter, damit die nächste Seite frisch beginnt.
Wie lösche ich in PHP ein Cookie?
Setze es erneut mit demselben Namen, Pfad und derselben Domain und einem Ablaufdatum in der Vergangenheit: setcookie('theme', '', ['expires' => time() - 3600, 'path' => '/']);. Rufe außerdem unset($_COOKIE['theme']) auf, wenn der Rest des aktuellen Skripts es liest, denn $_COOKIE ändert sich erst bei der nächsten Anfrage.
Wie lange dauert eine PHP-Session?
Standardmäßig hält das Session-Cookie, bis der Browser geschlossen wird (session.cookie_lifetime = 0), und der Server darf Session-Daten nach 1440 Sekunden (24 Minuten) ohne Aktivität löschen (session.gc_maxlifetime). Für einen festen Timeout speicherst du die Zeit der letzten Anfrage in der Session und prüfst sie selbst.
Warum meldet session_start() headers already sent?
Die Session-ID reist in einem Cookie-Header, und Header müssen vor jeder Ausgabe gesendet werden. Ein echo, HTML oder sogar eine Leerzeile oder ein BOM vor <?php schickt die Ausgabe zuerst. Rufe session_start() ganz am Anfang des Skripts auf, bevor irgendetwas ausgegeben wird.