Sessions ermöglichen es, Daten eines Besuchers über mehrere Seitenaufrufe hinweg zu speichern. Die Funktion session_start() ist der Einstiegspunkt: Sie startet eine neue Session oder setzt eine bestehende fort. Ohne diesen Aufruf bleibt das $_SESSION-Array leer. Dieses Tutorial erklärt, wie session_start() funktioniert, welche Optionen es bietet und wie du Sessions gegen die häufigsten Angriffe absicherst.
graph TD
A["Browser sendet Request"] --> B{"Cookie vorhanden?"}
B -->|Ja| C["Session laden"]
B -->|Nein| D["Neue ID erzeugen"]
C --> E["$_SESSION befuellen"]
D --> E
E --> F["Script laeuft"]
F --> G["session_write_close"]
G --> H["Response mit Cookie"]
So funktioniert session_start()
Beim Aufruf von session_start() passiert Folgendes: PHP prüft, ob der Browser ein Session-Cookie mitgeschickt hat. Wenn ja, wird die zugehörige Session-Datei vom Server geladen und $_SESSION mit den gespeicherten Daten gefüllt. Wenn nein, erzeugt PHP eine neue Session-ID, erstellt eine leere Session-Datei und sendet die ID als Cookie an den Browser.
<?php
session_start();
/* Wert speichern */
$_SESSION["sprache"] = "de";
/* Wert lesen */
echo $_SESSION["sprache"]; // de
?>
Der Aufruf muss vor jeder HTML-Ausgabe stehen, da session_start() einen HTTP-Header (Set-Cookie) sendet. Steht bereits Text in der Ausgabe, erhältst du die Warnung Cannot send session cookie - headers already sent.
Startoptionen übergeben
Seit PHP 7.0 akzeptiert session_start() ein Array mit Optionen. Damit lassen sich Cookie-Einstellungen und Session-Parameter direkt beim Start festlegen:
<?php
session_start([
"cookie_lifetime" => 0,
"cookie_httponly" => true,
"cookie_secure" => true,
"cookie_samesite" => "Lax",
"use_strict_mode" => true,
"gc_maxlifetime" => 1800
]);
?>
Diese Optionen überschreiben die Werte aus der php.ini für die aktuelle Session. So kannst du verschiedene Bereiche einer Anwendung mit unterschiedlichen Session-Einstellungen betreiben.
gc_maxlifetime vs. cookie_lifetime
Zwei Einstellungen bestimmen, wie lange eine Session lebt, und sie werden oft verwechselt. session.gc_maxlifetime legt fest, nach wie vielen Sekunden Inaktivität der Garbage Collector die Session-Datei auf dem Server löscht. session.cookie_lifetime bestimmt, wie lange der Browser das Session-Cookie aufbewahrt.
Wenn gc_maxlifetime kleiner ist als cookie_lifetime, entsteht ein häufiger Bug: Der Browser schickt noch ein gültiges Cookie, aber die Session-Datei auf dem Server existiert nicht mehr. PHP startet dann eine leere Session und der Benutzer ist plötzlich ausgeloggt.
<?php
/* Beispiel: gc loescht nach 30 Min,
Cookie lebt 60 Min = Problem! */
session_start([
"gc_maxlifetime" => 1800,
"cookie_lifetime" => 3600
]);
/* Besser: Beide Werte gleich setzen
oder cookie_lifetime auf 0 (Session-Cookie) */
session_start([
"gc_maxlifetime" => 1800,
"cookie_lifetime" => 0
]);
?>
Mit cookie_lifetime = 0 wird das Cookie beim Schließen des Browsers gelöscht. Das ist für die meisten Webanwendungen die sicherste Einstellung.
Prüfen, ob eine Session läuft
Um zu vermeiden, dass session_start() doppelt aufgerufen wird, kannst du den Session-Status abfragen:
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
/* Jetzt ist $_SESSION sicher verfuegbar */
?>
Die Funktion session_status() gibt drei mögliche Werte zurück: PHP_SESSION_DISABLED (Sessions deaktiviert), PHP_SESSION_NONE (keine Session gestartet) und PHP_SESSION_ACTIVE (Session läuft bereits).
Login-System mit Sessions
Sessions sind die Grundlage für Login-Systeme. Nach erfolgreicher Anmeldung speicherst du die Benutzer-ID in der Session. Auf jeder geschützten Seite prüfst du, ob dieser Wert vorhanden ist:
<?php
session_start();
/* Login-Pruefung */
if (!isset($_SESSION["user_id"])) {
header("Location: login.php");
exit;
}
echo "Willkommen, Benutzer #"
. $_SESSION["user_id"];
?>
In einer echten Anwendung sollte das Passwort nie in der Session gespeichert werden. Die Session enthält nur eine Referenz auf den Benutzer, etwa die User-ID aus der Datenbank.
Session sauber beenden
Beim Ausloggen reicht es nicht, nur $_SESSION zu leeren. Das Session-Cookie muss ebenfalls entfernt werden, damit der Browser die alte Session-ID nicht erneut sendet:
<?php
session_start();
/* Session-Daten leeren */
$_SESSION = [];
/* Cookie im Browser loeschen */
if (ini_get("session.use_cookies")) {
$p = session_get_cookie_params();
setcookie(
session_name(),
"",
time() - 42000,
$p["path"],
$p["domain"],
$p["secure"],
$p["httponly"]
);
}
/* Session-Datei vom Server loeschen */
session_destroy();
?>
Diese drei Schritte stellen sicher, dass weder auf dem Server noch im Browser Reste der alten Session verbleiben.
Session-Timeout mit Inaktivitätsprüfung
Der Garbage Collector allein reicht für ein zuverlässiges Timeout nicht aus, denn er läuft nur mit einer gewissen Wahrscheinlichkeit. Für ein sicheres automatisches Ausloggen nach einer bestimmten Inaktivitätszeit speicherst du den Zeitpunkt der letzten Aktivität direkt in der Session:
<?php
function pruefeSessionTimeout(
int $maxInaktivSekunden = 1800
): bool {
if (isset($_SESSION["letzte_aktivitaet"])) {
$inaktiv = time()
- $_SESSION["letzte_aktivitaet"];
if ($inaktiv > $maxInaktivSekunden) {
/* Session abgelaufen */
session_unset();
session_destroy();
return false;
}
}
/* Zeitstempel aktualisieren */
$_SESSION["letzte_aktivitaet"] = time();
return true;
}
session_start();
if (!pruefeSessionTimeout(1800)) {
header("Location: login.php?timeout=1");
exit;
}
/* Session ist aktiv, weiter im Script */
?>
Mit dieser Funktion wird der Benutzer nach 30 Minuten Inaktivität automatisch ausgeloggt. Der Timeout lässt sich über den Parameter anpassen, etwa auf 900 Sekunden (15 Minuten) für sensiblere Bereiche wie ein Admin-Panel.
Sessions absichern
Sessions sind ein beliebtes Angriffsziel. Wer die Session-ID eines Benutzers kennt, kann dessen Sitzung übernehmen. Die folgenden Maßnahmen schützen dagegen.
Session-ID regelmäßig erneuern
Bei jeder Rechteänderung, insbesondere nach dem Login, sollte die Session-ID erneuert werden. Das verhindert Session-Fixation-Angriffe:
<?php
session_start();
/* Nach erfolgreichem Login */
session_regenerate_id(true);
$_SESSION["user_id"] = $userId;
?>
Der Parameter true löscht die alte Session-Datei. Ohne diesen Parameter bleibt die alte Datei bestehen und ein Angreifer könnte sie weiter nutzen.
Sichere Cookie-Einstellungen mit SameSite
Das Session-Cookie sollte so restriktiv wie möglich konfiguriert werden. Seit 2020 unterstützen alle modernen Browser das SameSite-Attribut, das einen wirkungsvollen Schutz gegen CSRF-Angriffe bietet:
| SameSite-Wert | Verhalten | Einsatz |
Strict | Cookie wird nur bei Anfragen von der eigenen Domain gesendet | Maximale Sicherheit, kann aber Links von externen Seiten brechen |
Lax | Cookie wird bei Navigation gesendet, nicht bei AJAX von Fremdseiten | Empfohlen für die meisten Anwendungen |
None | Cookie wird immer gesendet, erfordert Secure | Nur für Cross-Site-Szenarien wie SSO |
<?php
session_start([
"cookie_httponly" => true,
"cookie_secure" => true,
"cookie_samesite" => "Lax",
"use_strict_mode" => true
]);
?>
cookie_httponly verhindert den Zugriff auf das Cookie per JavaScript und schützt damit vor XSS-Angriffen. cookie_secure stellt sicher, dass das Cookie nur über HTTPS gesendet wird. use_strict_mode weist nicht initialisierte Session-IDs ab und erzeugt stattdessen eine neue.
Session Fixation verhindern
Bei einem Session-Fixation-Angriff unterschiebt der Angreifer dem Opfer eine bekannte Session-ID, etwa über einen manipulierten Link. Das use_strict_mode wehrt diesen Angriff ab, indem PHP nur Session-IDs akzeptiert, die es selbst erzeugt hat. Zusätzlich solltest du nach jedem Login session_regenerate_id(true) aufrufen.
Typische Fehler und Lösungen
Die häufigsten Probleme mit Sessions lassen sich schnell beheben, wenn man die Ursache kennt.
Headers already sent: session_start() steht nach einer HTML-Ausgabe oder nach einem BOM-Zeichen in der Datei. Lösung: Den Aufruf an den Anfang des Scripts setzen und sicherstellen, dass keine Leerzeilen vor <?php stehen.
Session-Daten verschwinden: Entweder wird session_start() auf einer Seite vergessen, oder gc_maxlifetime ist zu niedrig eingestellt. Prüfe beide Einstellungen und stelle sicher, dass session_start() auf jeder Seite aufgerufen wird, die $_SESSION nutzt.
Parallele Anfragen blockieren sich: PHP sperrt die Session-Datei während eines Requests. Wenn zwei AJAX-Requests gleichzeitig laufen, wartet der zweite, bis der erste fertig ist. Die Lösung ist session_write_close().
Performance: Session-Lock minimieren
Solange eine Session geöffnet ist, sperrt PHP die Session-Datei. Das kann bei parallelen AJAX-Requests zum Flaschenhals werden. Mit session_write_close() gibst du die Sperre frei, sobald du keine Session-Daten mehr schreibst:
<?php
session_start();
/* Session-Daten lesen und ggf. schreiben */
$userId = $_SESSION["user_id"] ?? null;
/* Sperre freigeben */
session_write_close();
/* Ab hier laeuft der Rest des Scripts
ohne Session-Lock */
$daten = ladeDatenAusDatenbank($userId);
echo json_encode($daten);
?>
Nach session_write_close() kannst du $_SESSION zwar noch lesen, aber Änderungen werden nicht mehr gespeichert. Setze den Aufruf daher an die Stelle, ab der du keine Session-Daten mehr verändern musst.
Wann Sessions nicht die richtige Wahl sind
Für klassische Webanwendungen mit Server-Rendering sind Sessions ideal. Bei APIs und Microservices lohnt sich ein Blick auf Alternativen wie JWT (JSON Web Tokens). JWTs speichern die Benutzerinformationen direkt im Token, sodass der Server keinen Session-Speicher benötigt. Das macht sie besonders geeignet für verteilte Systeme und mobile Apps. Für einfache Webanwendungen mit Formularen und Seitennavigation bleiben Sessions aber die einfachere und sicherere Lösung.
Verwandte Tutorials
Sessions hängen eng mit anderen PHP-Themen zusammen. Diese Tutorials ergänzen das hier Gelernte: