Sessiondaten sind Daten, die z.B. von einem PHP-Script auf dem Server gespeichert werden, und die meistens für die Dauer des Besuchs (Session/Sitzung) auf mehreren Pages einer Website ihre Gültigkeit behalten. Sessiondaten können z.B. dazu benutzt werden, um dem Besucher restriktiven Zugriff (z.B. nach einem Login) auf Teile einer Website zu erlauben - üblicherweise zu einem Administrationsbereich.
In der PHP4-Standardeinstellung werden diese Daten als ASCII- Dateien im /tmp -Verzeichnis ( session.save_path ) des Servers gespeichert. Diese Dateien enthalten das serialsierte ( serialize() ) Abbild der von einem Script gespeicherten Variablen. Der Name dieser Dateien setzt sich aus dem Prefix sess_ und einer 32-Zeichen langen, zufällig ausgewählten Zeichenkette (der Session-ID) zusammen.
Die Manipulation dieser Daten bleibt nur dem serverseitig ausgeführtem PHP-Script vorbehalten - der Client (Browser) weiß nicht welche Daten von dem Script gespeichert werden und er kann keinen mittelbaren Einfluss auf diese Daten nehmen. Ausnahme bildet hier die Änderung/Löschung dieser Daten durch den Administrator oder durch ein Script mit entsprechenden Rechten (siehe auch sessions-schutz ).
Unter diesen Voraussetzungen gelten die Sessiondaten bei einem korrekt installierten Webserver, als sicher und durch den Besucher nicht fakebar.
PHP4 stellt mehrere Funktionen zu Sessionverwaltung zu Verfügung (siehe auch die Sessionsreferenz , die grundlegenden seien hier kurz vorgestellt:
Bei Verwendung dieser Funktionen ist zu beachten, dass eine neue Session nur dann angelegt werden kann, wenn noch keine Ausgabe stattgefunden hat. Mehr Informationen dazu finden sich im Artikel fehler-session-cookie .
session_start()Session(datei) auf dem Server erstellen. Wurde eine gültige Session-ID übergeben, werden die in den Sessiondaten gespeicherten Werte in dem $_SESSION -Hash wiederhergestellt und abhängig von der Einstellung der register_globals auch als Variablen reinitialisiert.
Zusätzlich werden, je nach Einstellung des session.gc_probability -Parameters, in diesem Augenblick die angehäuften und nicht mehr benötigten Sessiondateien vom Server gelöscht. Wenn das error_reporting() schärfer eingestellt ist, gibt session_start() eine entsprechende Notice aus. Da diese üblicherweise nicht erwünscht ist, empfiehlt es sich vor die session_start() -Funktion ein " @ " zu schreiben, welches diese Warnung unterdrückt.
Also:
<?php
@session_start();
?>
Der Zugriff auf Sessionvariablen erfolgt seit PHP 4.1.0 über das assoziative Array $_SESSION . Durch das erste Ansprechen eines Arrayelements wird die Sessionvariable angelegt, durch ein unset() kann eine Variable gelöscht werden. Bis PHP 4.0.6 hieß das entsprechende Array $HTTP_SESSION_VARS . Wenn register_globals aktiviert ist, müssen bei PHP Versionen, die älter als PHP 4.3 sind, die Sessionvariablen mit session_unregister() aus der Session entfernt werden.
session_destroy()Die Funktion session_destroy() veranlasst alle Variablen einer Session zu verwerfen und die Session(datei) löschen.
Ein genauerer Einblick in die Funktionsweise dieser Funktionen wird hier gewährt: sessions-dateisystem .
Beispiel 1 Beispiel 1: seite1.php
<?php
// Falls nicht vorhanden, generiert eine Session(datei)
// auf dem Server.
// Falls bereits vorhanden, liest Sessiondaten wieder ein und
// (re-)initialisiert die gespeicherten Variablen.
@session_start();
// Erst wenn das Script terminiert(!), merkt PHP den Inhalt
// der Variablen $s_userName und $s_userPermissions in
// den Sessiondaten.
$_SESSION['userName'] = "dtg";
$_SESSION['userPermissions'] = "keine :=(";
?>
<?php
// Falls nicht vorhanden, generiert eine Session(datei)
// auf dem Server.
// Falls bereits vorhanden, liest Sessiondaten wieder ein und
// (re-)initialisiert die gespeicherten Variablen.
@session_start();
// Gibt den Inhalt der wiederhergestellten Variablen aus.
echo "<P>Hallo " . $_SESSION['userName'] . ",";
echo "<P>Du hast " . $_SESSION['userPermissions'] . " Zugriffsrechte.";
// Wird in diesem Script kein unset() oder
// session_destroy() ausgeführt, bleiben die Daten erhalten!
?>
Damit das Folgescript ( seite2.php ) weiß, in welcher Datei auf dem Server die benötigten Daten zu finden sind, muss ihm die sog. Session-ID übergeben werden. Diese Session-ID repräsentiert den eindeutigen Namen der Session (es ist der bereits erwähnte 32-Zeichen lange String).
Um die Session-ID an eine andere Seite zu übergeben, benutzt PHP4 in der Standardeinstellung Session-Cookies, welche nicht gespeichert werden und mit dem Schließen des Browsers verfallen. In diesen Cookies wird der Name der Session (z.B. PHPSESSID ) und die zugehörige Session-ID abgelegt. Bei einem Request auf ein Folgescript wird der Cookieinhalt mitgeschickt, und PHP weiß damit in welcher Sessiondatei die benötigten Daten gespeichert sind.
Dies passiert automatisch, ohne dass zusätzlicher Code geschrieben werden muss.
Beispiel 2Hat man z.B. eine komplizierte Suchmaske z.B für eine Datenbank, aus der man eine noch kompliziertere Query basteln muss, über deren Ergebnisse man auf Folgeseiten browsen will, kann es sich lohnen die Grund-Query einmalig zu generieren, und sie dann weiter an das Ausgabe-/Browse-Script zu übergeben, anstatt alle Eckparameter immerwieder zu übergeben und die Query jedesmal neu zu generieren.
Dies darf natürlich nicht über die GET- oder POST-Methode geschehen, denn der User könnte durch die Manipulation dieser Parameter ohne Probleme "böse" Queries an die Datenbank schicken. Ein Datenverlust ist dann vorprogrammiert.
Für diesen Einsatzzweck eignen sich Sessions auch, denn die dynamisch erzeugte Query wird außerhalb der Reichweite des Users auf dem Server gespeichert.
Beispiel 2: seite3.php (Formularseite)
<?php
@session_start();
if (isset($_POST['submit']))
{
// Hier prüfen, ob _alle_ benötigten Variablen,
// die an dieses Script übermittelt wurden,
// legal sind!
// Hier nur fortfahren, wenn alles in Ordnung ist
// Die Query wird anhand der Variablen,
// die submitted wurden, erzeugt
$_SESSION['meineTolleQuery'] = "SELECT ...";
// HTTP-Redirect zu der Ausgabeseite
header("Location: http://" . $_SERVER['SERVER_NAME']
. "/seite4.php");
exit;
}
?>
<FORM action="<?php=$_SERVER['PHP_SELF']?>" method="post">
<!--
Hier ganz viele Radiobuttons, Checkboxen und Inputfelder
-->
<INPUT type="submit" name="submit">
</FORM>
<?php
@session_start();
echo "<P>Diese Query wurde mir übermittelt: "
. $_SESSION['meineTolleQuery'];
echo "<P>und jetzt mache ich was draus!";
?>
Die sog. Session-ID ist ein zufällig ausgewählter Schlüssel, der die Sessiondaten auf dem Server eindeutig identifiziert. Dieser Schlüssel kann z.B. über Cookies oder als Bestandteil der URL an ein Folgescript übergeben werden, damit dieses die Sessiondaten auf dem Server wiederfinden kann.
PHPSESSID ist bei PHP4 der Default-Name der Session. Möchte man diesen Namen aus z.B. ästhetischen Gründen modifizieren - vor allem, wenn er als GET-Parameter als Teil der URL sichbar wird - so kann man dies in der php.ini , der Webserverkonfiguration oder direkt mit PHP bewerkstelligen. Der Artikel sessions-namen geht genauer darauf ein.
Eine Beispiel, wenn die Session-ID als GET-Parameter in der URL übertragen wird:
Query-String (alle GET-Parameter)
Protokoll Subdomain _________________|__________________
| | / \
http://www.daniel-gorski.de?query=xyz&PHPSESSID=cd45a3f73493d5d...
| | \__________________________/
Subdomain Top Level Domain |
Session-Name und Session-ID
Am Beispiel der Session-Fallback-Klasse in sessions-fallback kann man nachvollziehen, wie man feststellen kann, ob der Client Cookies akzeptiert oder nicht. Das Prinzip ist simpel: Das aufgerufene Script prüft, ob ihm eine Session-ID übergeben wurde. Falls nicht, forciert das Script einen Request auf sich selbst und übergibt dabei eine frisch erzeugte Session-ID als GET- Parameter an sich selbst. Beim zweiten Durchlauf des Scriptes kann dieses feststellen, ob ihm vom Browser ein Cookie mit der Session-ID übermittelt worden ist, oder ob es die Session-ID aus dem GET-Parameter benutzen soll.
Viele Browser-User haben in ihrem Browser die Cookies aus diversen Gründen deaktiviert, oder lassen sich jeden Cookie bestätigen. Sollte ein Cookie auf dem lokalen Rechnersystem nicht gesetzt werden können, muss ein Ersatzmechanismus her - ein sog. Fallback. In diesem Fall ist der Fallback (Rückfall / Atavismus) eine Ersatzmethode, die die Übergabe der Session-ID an ein Folgescript ohne Cookies erlaubt.
Man kann den Fallback dadurch realisieren, dass man dem Folgescript die Session-ID quasi "manuell" bei jedem GET
<A href="php/php-faq/static/test.session.php%3F%26lt%3B%3Fphp%3DSID%3F%26gt%3B.html">
oder POST - bei Formularen - mittels
<INPUT type = "hidden"
name = "<?php=session_name()?>"
value = "<?php=session_id()?>">
übergibt. ACHTUNG: Das bedeutet, dass jeder Link und jedes Formular innerhalb einer Website mit einem zusätzlichen Parameter versehen werden muss! Wird die Session-ID nicht korrekt übergeben, wird ein Folge-Script nicht auf die Sessiondaten zugreifen können - diese Daten sind für dieses Script "verloren".
PHP4 kann man auch mit dem --enable-trans-sid -Parameter kompilieren. Dann hat dies zufolge, dass, wenn der Client (Browser) keine Cookies annehmen kann/will, alle relativen Links einer Webpage mit dem zusätzlichen SessionName=Session-ID Parameter ergänzt werden. Dies klingt zunächst gut, aber man sollte beachten, dass durch den zusätzlichen Aufwand, den der PHP-Parser leisten muss, sich diese Technik nicht für High-Traffic-Websites oder Server mit vielen Vhosts eignet. Auch wenn man Projekte realisiert, die auf anderen Webservern laufen sollen, kann man nicht davon ausgehen, dass das betreffende PHP mit --enable-trans-sid kompiliert worden ist.
Die --enable-trans-sid -Technik versagt (PHP 4.0.1.pl2) auch bei folgenden Konstrukten:
<FORM action="<?php=$_SERVER['PHP_SELF']?>">
weil offensichtlich zuerst an den action -Tag die Session-ID-Information angehängt wird, und dann erst der Wert von $_SERVER['PHP_SELF'] . Das Ergebnis sieht dann fälschlicherweise so aus:
<FORM action="?PHPSESSID=cd45a3f76f7325099c755b25b/test.session.php">
Wie bereits erwähnt, muss man u.U. selbst dafür Sorge tragen, dass der Fallback-Mechnismus greift, wenn der Client keine Cookies annimmt. Eine PHP-Klasse die das leisten kann ist auf http://develnet.org/ verfügbar.
Sie fügt bei Bedarf die Session-ID an Hyperlinks, Formulare und Redirects und ermöglicht die punktgenaue Steuerung des Fallbacks. Mit dieser Klasse muss man sich ebenfalls keine Gedanken beim Hosterwechsel machen, da man nicht auf die u.U. nicht vorhandene --enable-trans-sid -Funktionalität angewiesen ist.
Diese Klasse erlaubt zusätzlich das bequeme Registrieren von Session-Variablen, auch wenn PHP mit register_globals=off konfiguriert ist.
In der php.ini wird der Name der Session in dem Parameter session.name festgelegt - standardmäßig auf PHPSESSID . Möchte man ohne Eingriff in die php.ini oder in die Webserverkonfiguration diesen Namen ändern, steht die Funktion session_name() zu Verfügung. Diese Funktion muss vor dem (Re)initialisieren der Sessiondaten ( session_start() ) ausgeführt werden.
<?php
// Einen anderen Namen für die Session festlegen
session_name("meineSession");
@session_start();
?>
Laufen auf einer Maschine mehrere virtuelle Hosts (vhosts), z.B. bei einem Hoster, muss der verantwortliche Administrator dafür Sorge tragen, dass - wenn überhaupt - der Safe-Mode nur für 100% vertrauenswürdige vhost-Nutzer ausgeschaltet werden darf ( safe_mode =Off). Dies würde - neben anderen systemnahen Eingriffen - erlauben, dass ein Script von einem anderen Vhost folgenden Code ausführen darf:
<?php
// Inhalt von /tmp löschen
system("rm -rf /tmp");
?>
Dies hätte in der PHP4-Standardeinstellung (aber mit safe_mode =Off) zufolge, dass alle Sessiondaten anderer Benutzer gelöscht worden wären. Gegebenfalls sollte man sich mit einer entsprechenden Anfrage an seinen Hoster wenden.
Eine andere Möglichkeit dies zu verhindern wäre es, für jeden Vhost eine andere Einstellung des session.save_path -Parameters zu wählen, wenn Sessiondaten in Files gespeichert werden.
Diese Frage lässt sich im Grunde nur mit "maßvoll" beantworten. Der Unterschied zwischen wenigen Bytes und 5KB, wird sich nicht ungünstig auf die Performance des Servers auswirken.
Eigene Performancemessungen ergeben hier eindeutig einen Wissensvorteil. Zudem sollte man bedenken, dass größere Datenmengen besser in einer Datenbank aufgehoben sind - und man sollte seine Datenverwaltung nochmals gründlich überschlafen.
Ähnlich wie die Ausgabe anderer PHP-Hashes (assoziativer Arrays) lassen sich Sessiondaten mittels einer kleinen Schleife ausgeben. Zuvor muss die Session mit session_start() initialisiert werden. Dies bewirkt, dass der $_SESSION -Hash gefüllt wird.
<?php
@session_start();
foreach ($_SESSION as $key =>$value) {
echo $key." = ".$value."<br>";
}
?>
Analog zu obigen Beispiel kann man über $_COOKIE auf den Inhalt eines Cookies zugreifen.
<?php
@session_start();
foreach ($_COOKIE as $key => $value) {
echo $key." = ".$value."<br>";
}
?>
Damit der Vorgang der Sessionspeicherung ein wenig verdeutlicht wird, untersuchen wir die Veränderungen im Filesystem des Servers. Die folgenden Beispiele laufen auf einem Linux/Unixsystem. Um sie nachvollziehen zu können, muss PHP4 mit safe_mode =Off konfiguriert werden. Zusätzlich wird davon ausgegangen, dass der Client (Browser) Cookies akzeptiert.
Als allererstes braucht man ein Script, welches den Inhalt des im session.save_path festgelegten Directories anzeigen kann:
<?php
// Datei: list.dir.php
// Liste das "session.save_path" Directory
// "safe_mode" muss "Off" sein
if (strtolower(session_module_name()) == "files")
{
echo "<pre>";
system("ls -l " . session_save_path());
echo "</pre>";
}
?>
Dieses Script wird unter dem Namen list.dir.php gespeichert. Hat man z.B. Shell-Zugriff auf den benötigten Teil des Servers, führt natürlich auch ein einfaches ls -l /tmp zu der von list.dir.php produzierten Ausgabe.
Das obige Script wird ausgeführt, um den Ursprungszustand des im session.save_path gespeicherten Verzeichnisses zu betrachten. Zunächst produziert das Script folgendes:
Ausgabe (mit ):
insgesamt 0
srwxrwxrwx 1 root root 0 Sep 22 21:38 mysql.sock
Das Verzeichnis (in diesem Fall /tmp ) ist fast leer. Die Datei mysql.sock kann für unseren Zweck vernachlässigt werden.
Als nächstes schreibt man ein Script, welches nach und nach ergänzt oder verändert wird, um die Veränderungen im Filesystem zu beobachten. Der Name diese Scriptes sei session.php . Dieses Script enthält nur die Funktion session_start() . Nach dem Start beobachten wir die Veränderungen:
<?php
// Datei: session.php
@session_start();
?>
insgesamt 0
srwxrwxrwx 1 root root 0 Sep 22 21:38 mysql.sock
-rw------- 1 wwwrun www 0 Okt 1 17:58 sess_cd45a3f76f73250..
Wie man sehen kann, hat PHP eine Sessiondatei mit den Zugriffsrechten des Webservers erzeugt, dessen Prozess es ja ist. Diese Datei ist zunächst 0 (Null) Byte groß. Diese Datei wird gleich die Sessiondaten aufnehmen.
Als nächstes wird in dem Script auf die Sessionvariablen zugegriffen, wodurch diese automatisch erstellt werden.
<?php
// Datei: session.php
@session_start();
$_SESSION['userName'] = "dtg";
$_SESSION['userPermissions'] = "keine :=(";
?>
insgesamt 4
srwxrwxrwx 1 root root 0 Sep 22 21:38 mysql.sock
-rw------- 1 wwwrun www 55 Okt 1 17:58 sess_cd45a3f76f73250..
Die Sessiondatei ist nun auf 51 Byte angewachsen. Sie enthält folgenden String:
userName|s:3:"dtg";userPermissions|s:9:"keine :=(";
also die serialisierten ( serialize() ) Namen und Inhalte der Variablen, die mit session_register() bestimmt wurden. In den Sessiondaten können verschiedene Variablentypen gespeichert werden, also auch Arrays und Objekte.
Wenn man jetzt auf eine Variable in der Sessiondatei verzichten will, kann man mittels unset() PHP davon abhalten, die betreffende Variable zu speichern:
<?php
// Datei: session.php
@session_start();
unset($_SESSION['userPermissions']);
?>
insgesamt 4
srwxrwxrwx 1 root root 0 Sep 22 21:38 mysql.sock
-rw------- 1 wwwrun www 21 Okt 1 17:59 sess_cd45a3f76f73250..
Die Variable $_SESSION['userPermissions'] wurde verworfen, die Sessiondatei ist nur noch 19 Byte groß und enthält nur noch die Variable $_SESSION['userName'] :
userName|s:3:"dtg";
Möchte man nun alle Sessiondaten löschen, stellt PHP4 die Funktion session_destroy() zur Verfügung. Vor einem session_destroy() muss aber ein session_start() ausgeführt werden:
<?php
// Datei: session.php
@session_start();
session_destroy();
?>
insgesamt 0
srwxrwxrwx 1 root root 0 Sep 22 21:38 mysql.sock
Die Sessiondatei wurde gelöscht und die Sessionvariablen stehen für weitere Scripte nicht mehr zur Verfügung. Wird nach diesem Zeitpunkt nochmals die Funktion session_start() im gleichen Browserfenster aufgerufen, wird die Sessiondatei erneut erzeugt, und zwar u.U. mit dem gleichen Namen d.h. mit der gleichen Session-ID(!). Der Grund dafür ist, dass der vom Browser gespeicherte Cookie - der die Session-ID enthält - erneut an den Server übermittelt wird.
Der Wert von session.save_path in der php.ini ist in seiner Standardeinstellung für den Einsatz der session_*() Funktionen auf Win32 unbrauchbar. Abhilfe schafft hier das Anlegen eines neuen Verzeichnisses, zum Beispiel c:\php4\sessions\ , dessen Ort man nun in der php.ini angibt:
session.save_path = c:/php4/sessions
Bei einer Session wird jedem Browser, der auf eine Webanwendung zugreift, eine Kennnummer gegeben, mit der man folgende Zugriffe dieses Browsers wiedererkennen kann. Auf dem Webserver werden unter dieser Kennnummer eine Reihe von PHP-Variablen gespeichert, die auf diese Weise von Seite zu Seite weitergereicht werden. Man erzielt damit einen ähnlichen Effekt wie mit <INPUT TYPE="hidden"> -Variablen, die von Seite zu Seite weitergereicht werden, vermeidet jedoch eine Reihe von Nachteilen dieser Variablen:
Sessionvariablen sind in der Größe nicht durch etwa die Länge der URL oder andere Faktoren beschränkt.
Sessionvariablen werden nicht ständig zwischen dem Browser und dem Webserver hin- und hergebounced und sind daher der Manipulation eines Anwenders entzogen, sobald sie erst einmal Bestandteil der Session sind.
Sessionvariablen erlauben die Entwicklung weitergehender Nutzanwendungen wie zum Beispiel Benutzeranmeldungen, Warenkörbe oder andere Dienste, die einen Zustand bewahren müssen.
Eine Webanwendung muss man sich aus zwei getrennten Teilen bestehend vorstellen. Der eine Teil, bestehend aus dem Webserver und allen anderen involvierten Rechnern auf dieser Seite der Firewall, ist grundsätzlich vertrauenswürdig. Daten, die von solchen Maschinen kommen, sind Bestandteil des durch den Serveradministrator kontrollierten Bereiches und daher mit großer Wahrscheinlichkeit korrekt und nicht kompromittiert.
Der andere Teil ist alles jenseits der Firewall, einschließlich des Browsers des Benutzers. Daten, die von dort kommen, sind nicht vertrauenswürdig:
Bei konventionellen Anwendungen werden mit jedem GET- oder POST-Request Parameter an den Server gesendet. Es handelt sich um sichtbare Formulardaten oder versteckte Formulardaten aus HIDDEN-Feldern oder statisch an URLs angehängte GET-Parameter sowie um Cookies. Diese Daten muss der Server jedes Mal wenn er sie erhält validieren und gegebenenfalls ablehnen. Das ist sehr, sehr schwierig zu machen und die meisten Anwendungen machen es nicht korrekt. Sie haben daher scheunentorgroße Zugangslöcher, die ein Anwender zum Hijacken der gesamten Webservermaschine benutzen kann. Diese Maschine wird dann zum Einfallstor für das gesamte Subnetz, in dem sich diese Maschine physikalisch befindet.
Bei Anwendungen mit Sessions wird bei jedem Request die Session-ID gesendet und diese hat eine Form, die sie schwer manipulierbar macht. Manipuliert der Benutzer die Session-ID, so erwischt er mit an Sicherheit grenzender Wahrscheinlichkeit eine ungültige Session-ID und startet so eine neue Session. Die Anwendung initialisiert sich dann korrekt und der User startet, als hätte er die Anwendung soeben frisch aufgerufen. Manipulation der Session-ID wird also von der Anwendung erkannt und führt zu einem definierten und unschädlichen Verhalten.
Außerdem erhalten auch Anwendungen mit Sessions ebenfalls Daten aus Formularen. In der Regel sind dies keine HIDDEN-Felder, denn der Zustand wird nun auf dem Server als Teil der Session gehalten. Stattdessen handelt es sich ausschließlich um sichtbare Formulardaten. Diese müssen beim Übergang aus dem Kontrollbereich des Benutzers in die Session natürlich validiert werden. Danach verbleiben sie jedoch in der Session und können als vertrauenswürdig angesehen werden.
Vertrauen bedeutet in diesem Kontext, dass die Daten mindestens die zugesicherten Eigenschaften haben, auf die bei der Validierung getestet worden ist. Die Anwendung darf natürlich nicht darauf vertrauen, dass die Daten Eigenschaften haben, die nicht validiert worden sind. Wenn man bei der Übernahme von Formulardaten in Sessiondaten einen Benutzernamen auf \w{3,8} testet, dann kann man in der Anwendung zwar darauf vertrauen, dass der Benutzername keine bösen Sonderzeichen enthält, nicht leer ist und in die Datenbankfelder passt, aber nicht darauf vertrauen, dass der Benutzername auch die Eigenschaft "eindeutig" und "noch nicht vergeben" erfüllt.
Man kann Objekte genau wie alle anderen Typen in Sessions speichern indem man sie in den $_SESSION -Array speichert. Zu beachten ist dabei allerdings, dass auf jeder Seite, in der auf die Session zugegriffen wird (in der also session_start() aufgerufen wird), auch die Klassendefinition eingebunden sein muss. Falls sich diese in einer seperaten Datei befindet, muss sie vor session_start() inkludiert werden. Wenn keine Klassendefinition vorhanden ist, stellt PHP die Klassenfunktionen nicht wieder her - die Klasse ist somit meistens nutzlos.
Oft muss man ein Objekt aufräumen, bevor es am Ende des Skriptes gespeichert (serialisiert) wird. Dazu dient dient die "magische" Funktion __sleep() . Diese wird vor dem Serialisieren des Objekts von PHP aufgerufen. Sie muss einen Array mit allen Variablen des Objektes zurückgegben, die gespeichert werden sollen.
Ihr Gegenstück ist die Funktion __wakeup() . Sie wird beim Wiederherstellen des Objektes aufgerufen.
class myClass {
var $id;
var $text;
var $db;
function getText() {
return $this->text;
}
function setText($text) {
$this->text = $text;
// schreibe Text in die Datenbank
[...]
}
function __sleep() {
// schließe die Datenbankverbindung
$this->db->disconnect();
return array('id', 'text');
}
function __wakeup() {
// stelle die Datenbankverbindung wieder her
$this->db = new DB([...]);
// hole den Text aus der Datenbank
[...]
}
}
Jede Form von Session-Management basiert auf zwei grundlegenden Dingen:
Einer Session-ID, die von Seite zu Seite weitergegeben wird.
Einem Datensatz mit Variablen, der auf dem Server in einem dauerhaften Speicher verbleibt und der mit der Session-ID angesprochen wird.
Grundsätzlich gibt es zwei Methoden, die Session-ID von einer Seite zu nächsten weiterzugeben: Entweder die ID wird per Cookie "unsichtbar" als Bestandteil des Requests weitergegeben, oder sie wird auf irgendeine Weise Bestandteil der URL, etwa als GET-Parameter mit einem ? an die URL angehängt, als PATH_INFO an die URL angehängt, als regulärer Pfadbestandteil, der von mod_rewrite herausgepult wird oder als Bestandteil des Hostnamens mit einem Wildcard A-Records im DNS. PHP unterstützt direkt die Weitergabe der Session-ID als Cookie und als GET/POST-Parameter, über mod_rewrite und einige minimale Änderungen ist jedoch auch die Weitergabe als Pfadbestandteil oder Hostname möglich.
Ist die Session-ID in irgendeiner Form Bestandteil der URL, bekommt man das Problem, dass die URL mit der Session-ID gebookmarked wird oder - schlimmer - irgendwo abgedruckt wird. In diesem Fall kann es dazu kommen, dass zwei Benutzerdie nichts miteinander zu tun haben, dieselbe Session verwenden. Dies kann bei Cookies niemals der Fall sein. Daher ist es aus technischer Sicht auf jeden Fall günstiger, Cookies zur Propagation der Session zu verwenden.
Die Presse und schlecht informierte Verbraucherschützer haben Cookies jedoch einen schlechten Ruf eingebracht. Dort wird behauptet, Cookies seien üble Instrumente, um den Kunden zu tracken und sein Verhalten im Web auszuspionieren. Tatsächlich ist es so, dass man wiedererkennbare Benutzer und ihr Verhalten aufzeichnen und auswerten kann - ohne Wiedererkennung sind jedoch auch keine Warenkörbe, personalisierte Websites oder andere individuelle Services möglich.
Andererseits schützt das Ablehnen eines Cookies auch nicht vor dem Tracking und dem folgenden Auswerten des Benutzerverhaltens: Wie oben gezeigt, kann man Session-IDs auch auf andere, schlechtere Weise als durch Cookies weiterverbreiten. Wenn es eine Website also darauf abgesehen hat, einen Benutzer zu tracken, dann hilft das Ablehnen des Cookies exakt gar nichts. Stattdessen ist es notwendig, den Kontakt zu dieser Website vollständig abzubrechen (dies ist insbesondere dann der Fall, wenn man sich nicht von einer Banneragentur wie DoubleClick ausspionieren lassen möchte. Ablehnen des Cookies nutzt auch hier nichts. Stattdessen muss man sich einen Proxy wie etwa JunkBuster installieren und auf diesem allen Datenverkehr in Richtung DoubleClick erden). Anders gesagt: nicht die Cookies sind böse, sondern das, was manche Firmen damit und jeder anderen Form von eindeutiger Identifikation anstellen.
In den Fragen " sessions-cookie " und " sessions-fallback " wird genauer eingegangen, wie man sich flexibel den Einstellungen der Benutzer anpassen kann.
PHP versucht, Sessions Benutzern zuzuordnen. IP-Nummern sind konstruktionsbedingt immer den Netzwerkinterfaces von Rechnern und nicht Benutzern zugeordnet. Das ist eine vollkommen andere Sache und die Auswertung von IP-Nummern würde zu Fehlern im Betrieb führen.
Ein Rechner kann mehr als einen Benutzer haben. Jeder Benutzer auf diesem Rechner würde mit derselben IP-Nummer arbeiten. Ein Beispiel ist der Rechner kruuna.helsinki.fi :
kris@valiant:~ > finger @kruuna.helsinki.fi | wc -l
114
Auf diesem Rechner sind zum Messzeitpunkt über 110 Benutzer angemeldet gewesen, die alle über dieselbe IP-Nummer arbeiten.
Ein Rechner kann mehr als einen Benutzer repräsentieren. Bei vielen Providern greifen Benutzer über Proxy-Server auf das Netz zu. Nach außen scheinen alle Zugriffe aus dem Netz des Providers von dem Proxy-Server zu kommen. Wenn der Proxy des Providers die Anonymisierungsfunktionen eingeschaltet hat, die z.B. der meistverwendete Proxy, squid2 , ab Werk mitbringt oder die Programme wie WebWasher und JunkBuster bieten, dann sind diese Anwender auch durch weitere Header nicht zu unterscheiden.
Die sichtbare IP-Nummer eines Benutzers kann während der Session wechseln. Viele Proxy-Server arbeiten in einem Cache-Verbund mit Lastverteilung. Die nach außen sichtbare IP-Nummer eines Anwenders wird je nach Lastsituation im Cache-Verbund diejenige IP-Nummer des am wenigsten ausgelasteten Proxy-Servers sein.
Die tatsächliche IP-Nummer eines Benutzers kann während der Session wechseln. Viele Anwender arbeiten mit Timeout bei Inaktivität und dynamisch zugeteilten IP-Nummern. Lässt ein Anwender seinen Browser einige Minuten ungenutzt stehen, wird sich die IP-Verbindung abbauen. Dem Anwender wird beim Neustart der Netzverbindung unter Umständen eine neue, andere IP-Nummer zugeteilt.
Auch eine Auswertung der Headerzeile X-Forwarded-For , die manche Proxies setzen, ist nicht sinnvoll:
Diese Headerzeile kann gesetzt sein, muss jedoch nicht vorhanden sein. Squid, Webwasher und Junkbuster entfernen diese Headerzeile, wenn dies gewünscht wird.
Die Information in dieser Headerzeile ist weder authentisch noch eindeutig: Die verwendete IP-Nummer kann die IP-Nummer eines RFC-Netzes sein - es gibt also sehr viele Maschinen auf der Welt mit der IP-Nummer 192.168.1.1.
Gewöhnlich macht man dies, indem man mit Session arbeitet und bei jedem Formular eine eindeutige ID ("Challenge") als Hidden-Variable in das Formular mit aufnimmt, die man sich außerdem in einer lokalen Sessionvariablen auf dem Server merkt.
Wenn das Formular abgesendet wird, vergleicht man die gelieferte Challenge mit der lokal gemerkten Challenge und akzeptiert das Formular nur dann, wenn beide übereinstimmen.
Wenn das Formular verarbeitet wird, löscht man die Challenge in der Sessionvariablen nach Abschluss der Verarbeitung. Wird das Formular ein weiteres Mal versendet, liefert es die alte Challenge aus der Hidden-Variable, deren Gegenstück in der Sessionvariablen aber bereits gelöscht wurde.
Man kann dies sehr schön mit einem generischen Formularvalidator automatisieren, dann hat man gar keine Arbeit mehr damit.