PHP Tutorials, PHP lernen, PHP Forum, PHP Community and more ... MyWebsolution.de!

Sidebar

Home News Tutorials Workshops Tipps Artikel Gästebuch Sitemap Unicode Shopping

Suche

Members

Forum Login Registrierung

Statistik

Statistikbereich
Jetzt2
Heute52
Gestern263
Gesamt1642567

Sessions in PHP - Datenbank basierte Sessionverwaltung

Autor Flitze
Klicks 168211
Rating für Sessions in PHP
  8.7 von 10
Bewertungen132
Stand 12.06.2013
Keywords:
Datenbank, Sessionverwaltung, session_set_save_handler, Datenbank basierte Session,PHP Session in Datenbank speichern

Amazon: PHP 5.3 und MySQL 5.1
Breadcrumb:
Workshops » Sessions in PHP » Sessions in PHP - Datenbank basierte Sessionverwaltung
Seite : 1 2 3 4 5 Bewerten
Article Wizard - deutscher Article Spinner

4. Datenbank basierte Sessionverwaltung

Ich stand vor der Problematik, dass ich den Login meiner User durch die Session ID verifiziere. Diese Session bleibt dem User bis zu seinem Logout erhalten, da darin z.B. seine bereits gelesenen Forenthreads gespeichert werden. Um das zu realisieren setzte ich die Lifetime der Sessions sowie die der gesetzten Cookies auf mehr als ein Jahr, so dass ich sicher sein konnte, dass der User auch wirklich eingeloggt bleibt. Dabei bedachte ich nicht, dass für jeden User eine Session gestartet wird, egal ob registrierter User, der sich einloggt, oder Gast, der nur kurz auf der Seite vorbeischaut. Die Folge dieses 'unsauberen' Managments wurde mir klar, als ich den tmp Ordner kontrollierte, in dem die Session gespeichert werden. Auf 1200 Besucher kamen 1492 Sessions von denen 1490 'tot' waren, also keine Daten enthielten. Normalerweise kümmert sich die garbage collection darum, doch dadurch, dass ich die Lifetime der Session auf 1 Jahr gesetzt hatte, hätte das noch einige Zeit gedauert.

An dieser Stelle musste ich mich intensiver mit Sessions und deren Handling vetraut machen. Dabei stieß ich auf die Möglichkeit, Sessions per Datenbank zu verwalten. Das hat den riesen Vorteil, dass man beliebig viele zusätzliche Daten zu einer Session speichern kann, wie z.B. dass eine Session nach einer Stunde als Müll gilt und entsorgt wird, aber eine andere hingegen niemals.

Zu dem Verständnis ein solches Managment zu realisieren, haben mir vor allem drei Quellen geholfen, die ich an dieser Stelle nennen möchte:

1. session_set_save_handler Referenz auf PHP.net
2. Custom Session Handling von Zend.com
3. Guru Speak: Storing Sessions in a Database

Diese Quellen sind jedoch mit Ausnahme von php.net alle auf Englisch verfasst. Allerdings sind von dieser Quelle eigentlich nur die Kommentare interessant.. und die sind wiederum auf Englisch ;)
Wie dem auch sei, zumindest habe ich kein ausführliches Tutorial zu dieser Problematik auf Deutsch gefunden und das soll sich nun ändern.

Warum soll ich mein Sessionmanagment über eine Datenbank verwalten?

Zunächst einmal stellt sich berechtigterweise die Frage nach dem Sinn der Implementierung eines eigenen, Datenbank basierten Sessionmanagments. Die Antwort lautet: Weitsicht und Funktionalität. Durch 'eigenes' wird es eigentlich schon deutlich, denn ihr bekommt dadurch die volle Kontrolle über eurer Sessions, so dass es einfacher ist, neue Dinge zu implementieren. Ein Beispiel dafür habe ich bereits in der Einleitung gegeben.

Ein weiterer Grund wäre die Erweiterbarkeit des Projektes. Sobald euer Projekt größere Ausmaße erreicht und ein Server evtl. nicht mehr ausreicht, so dass ihr einen weiteren Server benötigt und die beiden aufeinander abstimmt könnt ihr das File basierte Session Managment vergessen. Dem entgegen muss man bei der Datenbanklösung lediglich die entsprechende MYSQL-Connection in der Session laden und das ganze funktioniert wieder reibungslos.

Es gibt sicherlich noch weitere Vorteile, aber die werdet ihr selbst herausfinden. Let's get it on..

Die MySQL-Tabelle

Die Sessions werden über eine Datenbank verwaltet, also brauchen wir auch eine entsprechende Tabelle. Diese sieht folgendermaßen aus
Code:
+-----------+------------------+------+-----+---------+-------+
| Spalte    | Typ              | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+-------+
| ses_id    | VARCHAR(32)      |      | PRI |         |       |
| ses_time  | INT              |      |     | 0       |       |
| ses_value | MEDIUMTEXT       |      |     | ''      |       |
+-----------+------------------+------+-----+---------+-------+

Der Name der Tabelle lautet Sessions. Zum erstellen könnt ihr den folgenden Code verwenden

PHP:
<?php
$sql 
'CREATE TABLE `Sessions` ('
        
' `ses_id` VARCHAR(32) NOT NULL PRIMARY KEY, '
        
' `ses_time` INT NOT NULL DEFAULT \'0\', '
        
' `ses_value` MEDIUMTEXT NOT NULL DEFAULT \'\' '
        
' )';

mysql_query($sql) OR die($sql.mysql_error());
?>


Erläuterungen:

ses_id enthält die Session ID
ses_time enthält einen Timestamp des letzten Zugriffs
ses_value enthält die serialisierten Daten der Session

Die Basis für die Sessions ist damit geschaffen und wir müssen PHP nun noch klar machen, dass er die Sessions auch gefälligst dort zu verwalten hat.

Die Konfiguration von session_set_save_handler

session_set_save_handler() erwartet 6 Parameter, die alle angegeben werden müssen:

session_set_save_handler
(
callback öffnen,
callback schließen,
callback lesen,
callback schreiben,
callback löschen,
callback gc
)

Diese 6 Funktionen müssen wir nun mit Leben füllen, deshalb werde ich zu jeder Funktion eine kurze Erklärung geben und einen entsprechenden Quellcode bereitstellten.

Vorbedingung
Da wir mit Datenbanken arbeiten muss zum Arbeiten mit den Sessions als erstes eine Datenbankverbindung aufgebaut werden, sofern dies nicht schon an anderer Stelle geschehen ist.

PHP:
<?php
    $MYSQL_HOST 
'localhost';
    
$MYSQL_USER 'Flitze';
    
$MYSQL_PASS 'blablubb';
    
$MYSQL_DATA 'MeineDatenbank';

    @
mysql_connect($MYSQL_HOST,
                   
$MYSQL_USER,
                   
$MYSQL_PASS) OR die("Error: ".mysql_error());
    
mysql_select_db($MYSQL_DATA) OR die("Error: ".mysql_error());
?>


öffnen

Diese Funktion wird als erstes aufgerufen wenn eine Session gestartet wird, bzw. konkreter, wenn session_start aufgerufen wird.
Per Definition werden ihr 2 Parameter übergeben, der Speicherpfad der Session und der Name der Session. Diese beiden Parameter werden in der php.ini definiert und zwar als session.save_path und session.name. Wir müssen sie auch in unserer Funktion definieren, auch wenn wir sie letztendlich nicht nutzen werden ;). Der Rückgabewert der Funktion muss vom Typ bool sein, also entweder TRUE oder FALSE.

Unsere Funktion sieht schlicht und ergreifend folgendermaßen aus

PHP:
<?php
    
function ses_open($path$name) {
        return 
TRUE;
    }
?>


schließen

Diese Funktion wird als letztes aufgerufen. Sie erwartet keine Parameter. Der Rückgabewert der Funktion muss wieder vom Typ bool sein. Auch diese Funktion müssen wir nicht behandeln.

PHP:
<?php
    
function ses_close() {
        return 
TRUE;
    }
?>


lesen

Wie der Name schon sagt, wird diese Funktion zum Auslesen der Daten aufgerufen. Sie enthält als Parameter die Session ID mittels derer wir einen SQL-Query formulieren können, um die entsprechenden Sessiondaten zu laden. Der Rückgabewert der Funktion muss vom Typ String sein. Wenn also ein Fehler auftritt muss dennoch ein string zurückgegeben werden und nicht etwa false.

PHP:
<?php
    
function ses_read($ses_id) {
        
$sql "SELECT
                        ses_value
                FROM
                        Sessions
                WHERE
                        ses_id = '"
.mysql_real_escape_string($ses_id)."'
               "
;
        
$result = @mysql_query($sql);
        
// Fehler im Query, return leeren String
        
if (!$result)
            return 
'';
        
// Session nicht gefunden, return leeren String
        
if (!mysql_num_rows($result))
            return 
'';

        
// Session gefunden, return Daten der Session
        
$row mysql_fetch_assoc($result);
        return 
$row["ses_value"];
    }
?>


Anmerkungen:
mysql_real_escape_string() wird benutzt, da der User die Session ID theoretisch manipulieren kann, indem er an seinem Cookie herumspielt.
Intern werden die Daten beim return unserialisiert.


schreiben

Diese Funktion fügt einer Session neue Daten hinzu. Als Parameter werden die Session ID und alle Werte der Session übergeben. Durch die ID können wir nun die Daten über einen entsprechenden Query hinzufügen. Der Rückgabewert muss vom Typ bool sein.

PHP:
<?php
    
function ses_write($ses_id$data) {

        
$sql "REPLACE INTO
                        Sessions
                        (ses_id,
                         ses_time,
                         ses_value)
                VALUES ('"
.mysql_real_escape_string($ses_id)."',
                        '"
.time()."',
                        '"
.mysql_real_escape_string($data)."')
               "
;
        return (bool)@
mysql_query($sql);
    }
?>


Anmerkungen:
mysql_real_escape_string() wird bei den Daten benutzt, da wir uns natürlich gegen jegliche SQL-Injektion absichern müssen. Außerdem würde es sonst einen Fehler geben, wenn wir in den Daten single und double quotes ( ' )( " ) verwenden würden, da der Query zerstört würde.
Ich verwende den REPLACE Befehl da es zu Fehlern kommen kann, wenn man zuerst prüft, ob die Session bereits existiert und die existierende Session dann updatet bzw. eine neue Session erstellt, falls keine Session zum Updaten gefunden wurde. Diese Fehler treten auf, wenn man sehr schnell refresht. Intern wurde $data bereits vor Übergabe als Parameter serialisiert. Die Methode dazu wird übrigens in session.serialize_handler definiert.
Außerdem 'update' ich bei jedem Aufruf die Zeit der Session, was später bei der garbage collection von Bedeutung ist.

löschen

Diese Funktion wird aufgerufen, wenn man eine Sessions mittels session_destroy zerstört. Als Parameter hat sie die Session ID und als Rückgabewert wird TRUE oder FALSE erwartet. In unserem Fall bedeutet das, die betreffende Session aus der Datenbank zu löschen.

PHP:
<?php
    
function ses_destroy($ses_id) {
        
$sql "DELETE FROM
                        Sessions
                WHERE
                        ses_id = '"
.mysql_real_escape_string($ses_id)."'
               "
;
        return (bool)@
mysql_query($sql);
    }
?>


gc
Das Aufräumkommando unter den Funktionen. Ihr Aufrufe hängt von den Werten session.gc_probability und session.gc_divisor ab, die eine Wahrscheinlichkeit für den Aufruf dieser Funktion definieren. Inhaltlich sorgt diese Funktion dafür, dass alte sprich inaktive, Sessions gelöscht werden. Dazu wird als Parameter eine Zeit übergeben, die in session.gc_maxlifetime gesetzt ist.

PHP:
<?php
    
function ses_gc($life) {
        
$ses_life time()-$life;

        
$sql "DELETE FROM
                        Sessions
                WHERE
                        ses_time < "
.$ses_life."
               "
;
        return (bool)@
mysql_query($sql);
    }
?>


Anmerkungen:
$ses_life enthält einen Timestamp der mit der letzten Zugriffszeit der Session, ses_time, verglichen wird. Wird ein Datensatz gefunden, bei dem dies zutrifft, so wird er gelöscht.

Nachdem nun alle benötigten Funktionen definiert wurden, kann session_set_save_handler aufgerufen werden und im Anschluss daran kann die Session gestartet werden.

PHP:
<?php
    session_set_save_handler 
('ses_open',
                              
'ses_close',
                              
'ses_read',
                              
'ses_write',
                              
'ses_destroy',
                              
'ses_gc');
    
session_start();
?>


Anwendung der Sessions

Sessions können nun weiter wie gewohnt verwendet werden, als User bemerkt man keinen Unterschied. Um das ganze noch zu optimieren zeige ich nun nochmal den kompletten Code samt dem Setzen einiger php.ini Werte.

PHP:
<?php
    $MYSQL_HOST 
'localhost';
    
$MYSQL_USER 'Flitze';
    
$MYSQL_PASS 'blablubb';
    
$MYSQL_DATA 'MeineDatenbank';

    @
mysql_connect($MYSQL_HOST,
                   
$MYSQL_USER,
                   
$MYSQL_PASS) OR die("Error: ".mysql_error());
    
mysql_select_db($MYSQL_DATA) OR die("Error: ".mysql_error());

    
// Lifetime auf eine Stunde setzen
    
ini_set('session.gc_maxlifetime'3600);
    
// gc mit einer Wahrscheinlichkeit von 1% aufrufen
    
ini_set('session.gc_probability'1);
    
ini_set('session.gc_divisor'100);

    function 
ses_open($path$name) {
        return 
TRUE;
    }

    function 
ses_close() {
        return 
TRUE;
    }

    function 
ses_read($ses_id) {
        
$sql "SELECT
                        ses_value
                FROM
                        Sessions
                WHERE
                        ses_id = '"
.mysql_real_escape_string($ses_id)."'
               "
;
        
$result = @mysql_query($sql);
        
// Fehler im Query, return leeren String
        
if (!$result)
            return 
'';
        
// Session nicht gefunden, return leeren String
        
if (!mysql_num_rows($result))
            return 
'';

        
// Session gefunden, return Daten der Session
        
$row mysql_fetch_assoc($result);
        return 
$row["ses_value"];
    }

    function 
ses_write($ses_id$data) {

        
$sql "REPLACE INTO
                        Sessions
                        (ses_id,
                         ses_time,
                         ses_value)
                VALUES ('"
.mysql_real_escape_string($ses_id)."',
                        '"
.time()."',
                        '"
.mysql_real_escape_string($data)."')
               "
;
        return (bool)@
mysql_query($sql);
    }

    function 
ses_destroy($ses_id) {
        
$sql "DELETE FROM
                        Sessions
                WHERE
                        ses_id = '"
.mysql_real_escape_string($ses_id)."'
               "
;
        return (bool)@
mysql_query($sql);
    }

    function 
ses_gc($life) {
        
$ses_life time()-$life;

        
$sql "DELETE FROM
                        Sessions
                WHERE
                        ses_time < "
.$ses_life."
               "
;
        return (bool)@
mysql_query($sql);
    }

    
session_set_save_handler ('ses_open',
                              
'ses_close',
                              
'ses_read',
                              
'ses_write',
                              
'ses_destroy',
                              
'ses_gc');
    
session_start();
?>


Diese Datei kann nun als mySess.php gespeichert werden. Nun muss nur noch jedes session_start() in euren Skripten durch

PHP:
<?php
    
require('mySess.php'); 
?>


ersetzt werden und wir sind fertig. Eine Beispieldatei zum Testen sieht so aus:

PHP:
<?php
    
// Session starten
    
require('mySess.php');
    
$_SESSION['counter'] = 1;
    for(
$i=0$i<10$i++){
        
$_SESSION['counter']++;
        echo 
$_SESSION['counter'];
    }
    
// Session zerstören
    
session_destroy();
?>


Zurück zur vorigen Seite:
Sessions in PHP - php.ini
Bewerten

»» Zurück zum Menu

Suchmaschinenoptimierung

Suchmaschinenoptimierung (SEO - Search Engine Optimization)

Ranking

Tutorials (13)

8.6
8.4
8.1

Workshops (3)

8.8
8.7
7.6

Tipps (13)

7.2
6.7
6.5

Artikel (30)

8.4
7.2
6.6

RSS Feeds

Full Feed Tutorials Workshops Tipps Artikel

Twitter

Follow me on Twitter

Partner & Links


Valid HTML 4.01 Transitional
Valid CSS
nach oben

Diese Seiten unterstützen MyWebsolution:
 
© MyWebsolution.de
2006-2017