Session-Handler-Funktionen für PostgreSQL mit PHP4 |
Dies ist ein Beispiel für benutzerdefinierte Session-Handler-Funktionen mit PHP 4 für PostgreSQL. Im Anschluss an die Session-Handler-Funktionen finden Sie beispielhaft einige Funktionen für den Zugriff auf die Sessiondaten.
Diese Quelltexte wurden freundlicherweise von Yasuo Ohgaki, dem Maintainer der PostgreSQL-Extension von PHP, zur Verfügung gestellt. |
| Falls Sie Vorschläge oder Kommentare zu diesen Funktionen haben, schicken Sie eine Mail an yohgaki@php.net. |
So geht's: |
- Erstellen Sie eine Session-Datenbank und darin die weiter unten beschriebene Tabelle.
- Passen Sie die Konstanten SESS_CONN, SESS_TABLE und SESS_DATA_MAX an Ihre Systemumgebung an
- Der Wert der Konstanten SESS_DATA_MAX muß kleiner sein als eine PostgreSQL Seite. SESS_DATA_MAX soll höchstens den Wert (Seitengröße - Feldgröße - Seiten-Overhead) haben. Normalerweise ist die Größe einer PostgreSQL-Seite 8 KB.
- PostgreSQL ab der Version 7.1 kann beliebig große Daten speichern, vorausgesetzt Sie kompilieren es mit einer Version der Bibliothek libpq, die in einer Distribution ab Version 7.1 enthalten ist.
- "track_vars" sollte aktiviert sein
- Erstellen Sie eine Datei browser_check.html. Diese Datei soll prüfen, ob der Browser des Clients Cookies und JavaScript unterstützt. Speichern Sie die Datei im Verzeichnis "/lib/browser_check.html", es sei denn, sie löschen oder kommentieren die Codezeilen aus, die die Session-ID prüfen.
|
| Beachten Sie: |
- Im praktischen Einsatz sind Funktionen zur Fehlerbearbeitung notwendig.
- Fehler werden entsprechend Ihren Einstellungen in der php.ini protokolliert oder ausgegeben. Aber nicht alle Fehler, die in Session-Handler-Funktionen auftreten werden angezeigt.
- Falls die Sessiondaten sehr umfangreich sind, können sie einen großen Teil der Rechnerleistung und anderer Ressourcen in Anspruch nehmen.
- Für umfangreiche Session-Daten können Transaktionen benutzt werden. (Große Datenmengen führen offenbar eher zu Fehlerbedingungen.)
- Für die Session-Datenbank ist es sinnvoll, fsync() auf FALSE zu setzen. Dies erhöht die Verarbeitungsgeschwindigkeit und im Falle eines Systemabsturzes werden die Sessiondaten ohnehin nicht mehr gebraucht.
- Transaktionen sichern die Datenkonsistenz, falls ein Benutzer mehrere Browser öffnet
|
| Die globalen Variablen: |
$session_db - Die Verbindungskennung
$session_property - Die Session-Eigenschaften, wie Zugriffszähler, aktive Zeit, Erzeugungszeitpunkt usw.
|
Die PostgreSQL Tabelle: |
CREATE TABLE sys_session (
session_id varchar(32) NOT NULL,
i_created integer NOT NULL,
i_active integer NOT NULL,
i_counter integer NOT NULL DEFAULT 1,
i_error integer NOT NULL DEFAULT 0,
i_warn integer NOT NULL DEFAULT 0,
t_message text,
t_remote_addr varchar(32) DEFAULT '',
t_session_data text,
PRIMARY KEY (session_id)
); |
|
Die Quelltexte
|
<?php
|
| // Definition der Konstanten |
// Der Verbindungsstring zur Datenbank Session // define('SESS_DB', 'host=dev dbname=db_session user=yohgaki'); // Den Namen der Session-Tabelle setzen define('SESS_TABLE', 'sys_session')); // Maximale Größe der Sessiondaten (100KB) define('SESS_DATA_MAX', 102400); // Der Pfad zu der Datei browser_check.html define('SESS_BROWSER_CHECK_HTML', '/lib/browser_check.html');
|
| // Setup Session |
// Die Session.Handler-Funktionen registrieren session_set_save_handler ( 'pg_session_open', 'pg_session_close', 'pg_session_read', 'pg_session_write', 'pg_session_destroy', 'pg_session_gc' );
// Prüfen, ob der session_cache_limiter geändert werden sollte. if (isset($session_cache_limiter)) { session_cache_limiter($session_cache_limiter); }
// Die Session starten session_start();
// Session ID prüfen. Falls Sie das nicht brauchen, // kommentieren Sie diese Zeilen aus oder löschen Sie sie. // falls es keine Session ID in dem COOKIE-Array oder GET-Array gibt, redirect. if (!isset($HTTP_COOKIE_VARS[session_name()]) && !isset($HTTP_GET_VARS[session_name()])) { // header('Cache-Control: public,
max-age=10800'); // header('Status: 302 Moved
Templorarily'); if ($HTTP_SERVER_VARS['SERVER_PORT'] == 443) { $session_check_url = 'https://'. $HTTP_SERVER_VARS['SERVER_NAME'] . SESS_BROWSER_CHECK_HTML; } else { $session_check_url = 'http://'. $HTTP_SERVER_VARS['SERVER_NAME'] . SESS_BROWSER_CHECK_HTML; } header('Location: '. $session_check_url .'?sid='. session_id() . '&sname='. session_name() .'&url='. rawurlencode($HTTP_SERVER_VARS['REQUEST_URI'])) exit; } // ENDE Session ID prüfen
|
| // Die Session-Handler-Funktionen |
function pg_session_open ($save_path, $session_name) { //error_log('session_open(): Called', 0);
global $session_db;
$session_db = pg_pconnect(SESS_DB); pg_exec($session_db, 'BEGIN TRANSACTION;'); if (pg_errormessage($session_db)) { trigger_error('pg_session_open(): Keine Verbindung zum Datenbankserver.' . pg_errormessage($session_db), E_USER_WARNING); return false; }
return true; }
function pg_session_close() { //error_log('session_close(): Called', 0);
global $session_db;
pg_exec($session_db, 'COMMIT;'); if (pg_errormessage($session_db)) { trigger_error('pg_session_close(): Fehler beim Beenden der Transaktion' . pg_errormessage($session_db), E_USER_WARNING); } return true; }
function pg_session_read ($session_id) { //error_log('session_read(): Called', 0); global $session_db, ;$session_property;
if (strlen($session_id) != 32) { trigger_error('pg_session_read(): Fehlerhafte SessionID = ' . $session_id, E_USER_NOTICE); return ''; }
$session_id = addslashes($session_id); $result = pg_exec($session_db, 'SELECT * FROM '. SESS_TABLE . "WHERE session_id = '$session_id' FOR UPDATE") if (pg_numrows($result) == 1) { $session_property = pg_fetch_array($result, 0, PGSQL_ASSOC); return $session_property['t_session_data']; } elseif (pg_errormessage($session_db)) { trigger_error('pg_session_read(): Konnte Sessiondaten nicht lesen.' . pg_errormessage($session_db), E_USER_WARNING); return ''; } else { $session_property = null; // Für session_write()
return ''; } }
function pg_session_write ($session_id, $session_data) { //error_log('session_write(): Called', 0);
global $session_db, $session_property, $HTTP_SERVER_VARS;
if (strlen($session_id) != 32) { trigger_error('pg_session_write(): Fehlerhafte Session ID ='. $session_id, E_USER_NOTICE); return false; } if (strlen($session_data) > intval(SESS_DATA_MAX)) { trigger_error('pg_session_write(): Die Sessiondaten sind zu gross. '. $session_id, E_USER_WARNING); }
if ($session_property) { $query = 'UPDATE '. SESS_TABLE . " SET i_active = ". time() . ", i_counter = ". ++$session_property['i_counter'] . ", t_session_data =
'$session_data' WHERE session_id = '$session_id';"; } else { $query = 'INSERT INTO ' . SESS_TABLE . " (session_id, i_created, i_active, t_remote_addr, t_session_data) VALUES ('$session_id', " . time() . ", ". time() . ", '" . $HTTP_SERVER_VARS['REMOTE_ADDR'] . "', '$session_data');"; }
pg_exec($session_db, $query); if (pg_errorMessage($session_db)) { trigger_error('pg_session_write(): INSERT/UPDATE der Tabelle session fehlgeschlagen.
' . pg_errormessage($session_db ). ' Query: ' . $query, E_USER_WARNING); } return true; }
function pg_session_destroy ($session_id) { //error_log('session_destory(): Called', 0);
global $session_db;
pg_exec($session_db, 'DELETE FROM ' . SESS_TABLE . " WHERE session_id = '" . addslashes($session_id) . "'"); if (pg_errormessage($session_db)) { trigger_error('pg_session_destory(): Konnte die Session nicht zerstören. ' . pg_errormessage($session_db), E_USER_WARNING); return false; } else { return true; } }
function pg_session_gc ($maxlifetime = 4000) { //error_log('session_gc(): Called', 0);
global $session_db;
pg_exec($session_db, 'DELETE FROM ' . SESS_TABLE . " WHERE i_active < " . (time() - $maxlifetime)); if (pg_errormessage($session_db)) { trigger_error('pg_session_gc(): Konnte alte Sessions nicht löschen.' . pg_errormessage($session_db), E_USER_WARNING); return false; } else { return true; } }
|
| // Auf Sessiondaten zugreifen |
// Session-Informationen auslesen (Basic Auth Info) //
Diese Funktion arbeitet beim ersten Aufruf nicht, es sei denn // Sie benutzen die Datei browser_check.html. function session_get_info() { global $session_propety;
if (!isset($session_property['session_id'])) { trigger_error('session_get_info(): Keine Session ID', E_USER_NOTICE); return null; } else { return $session_property; } }
// Session-Informationen setzen (Basic Auth Info) //
Diese Funktion arbeitet beim ersten Aufruf nicht, es sei denn // Sie benutzen die Datei browser_check.html. function session_set_info($user, $login_type) { global $session_property; global $session_db;
if (!isset($session_property['session_id'])) { trigger_error('session_set_info(): Keine Session ID', E_USER_NOTICE); return false; }
$session_property['user'] = (empty($user)? 'null' :$user); $session_property['login_type'] = (empty($login_type)? 'null' :$login_type); $query = 'UPDATE ' . SESS_TABLE . '
SET user = ' . $session_property['user'] . ", login_type = '" . $session_property['login_type'] . "'" . " WHERE session_id = '" . $session_property['session_id'] . "'"; pg_Exec($session_db, $query); if (pg_ErrorMessage($session_db)) { trigger_error('session_set_info(): ' . pg_ErrorMessage($session_db) . ' Query: ' . $query, E_USER_WARNING); return false; } return true; }
// Diese Funktion inkrementiert den Fehlerzähler für die Sessions // Sie gibt -1 zurück, falls ein Fehler auftritt // Diese Funktion arbeitet beim ersten Aufruf nicht, es sei denn // Sie benutzen die Datei browser_check.html. function session_add_error_count($error_message = 'Unbekannter Fehler') { global $session_db;
$session_id = session_id(); if (!$session_id) { // Keine Session vorhanden.
return -1; }
// Den aktuellen Zählerstand holen $query = 'SELECT i_error FROM
' .SESS_TABLE." WHERE session_id = '".$session_id."'"; $result_id = @pg_Exec($session_db, $query); if (pg_ErrorMessage($session_db)) { trigger_error('session_add_error_count(): '.pg_ErrorMessage($session_db). ' Query: '.$query, E_USER_WARNING); return -1; }
$record = pg_Fetch_Array($result_id, 0, PGSQL_ASSOC); if (pg_ErrorMessage($session_db)) { trigger_error('session_add_error_count(): '.pg_ErrorMessage($session_db), E_USER_WARNING); return -1; }
$query = "UPDATE ". SESS_TABLE ." SET i_error=".++$record['i_error'].", t_message = '$error_message'"; pg_Exec($session_db, $query); if (pg_ErrorMessage($session_db)) { trigger_error('session_add_error_count(): '.pg_ErrorMessage($session_db). ' Qeury: '.$query, E_USER_WARNING); return -1; }
return $record['i_error']; }
// Diese Funktion inkrementiert den Fehlerzähler für die Sessions // Sie gibt -1 zurück, falls ein Fehler auftritt // Diese Funktion arbeitet beim ersten Aufruf nicht, es sei denn // Sie benutzen die Datei browser_check.html.
function session_add_warn_count($warn_message = 'Warnung unbekannt') { global $session_db;
$session_id = session_id(); if (!$session_id) { // Es gibt keine Session
return -1; }
// Den Stand des Fehlerzählers auslesen
$query = 'SELECT i_warn FROM
'.SESS_TABLE." WHERE session_id = '".$session_id."'"; pg_Exec($session_db, $query); if (pg_ErrorMessage($session_db)) { trigger_error('session_add_warn_count(): '.pg_ErrorMessage($session_db). ' Qeury: '.$query, E_USER_WARNING); return -1; }
$record = pg_Fetch_Array($result_id, 0, PGSQL_ASSOC); if (pg_ErrorMessage($session_db)) { trigger_error('session_add_warn_count(): '.pg_ErrorMessage($session_db), E_USER_WARNING); return -1; }
$query = "UPDATE ". SESS_TABLE ." SET i_warn=".++$record['i_warn'].", t_message = '$warn_message'"; pg_Exec($session_db, $query); if (pg_ErrorMessage($session_db)) { trigger_error('session_add_warn_count(): '.pg_ErrorMessage($session_db). ' Qeury: '.$query, E_USER_WARNING); return -1; } return $record['i_warn']; }
?>
|
Ein Beispiel
|
<?php
/* *
session_test.php - Ein Testscript für die PostgreSQL Session-Handler * * *
Beachten Sie, dass "track_vars" aktiviert sein muss. * "register_globals" sollte besser deaktiviert sein.
* */
$session_cache_limiter = 'nocache'; // Das Caching deaktivieren require_once('session.php'); //Die Session einrichten und starten
?> <html> <head>
<title>PgSQL Session Handler Test</title> </head>
<body bgcolor="#FFFFFF"> <h1>PgSQL Session Handler
Test</h1> <?php
// Nur als Beispiel um zu zeigen, dass eine // PHP4 Session mit Objekten umgehen kann
class object_counter { var $cnt = 0;
function increment() { $this->cnt++; }
function get() { return $this->cnt; } }
if (!isset($HTTP_SESSION_VARS['integer_counter'])) { // Initialisierung, falls es keine Sessionvariablen gibt.
$HTTP_SESSION_VARS['integer_counter'] = 0; $HTTP_SESSION_VARS['object_counter'] = new object_counter; $HTTP_SESSION_VARS['array_counter'] = array('counter' => 0); }
// Die Zähler inkrementieren $HTTP_SESSION_VARS['integer_counter'] ++; $HTTP_SESSION_VARS['object_counter'] -> increment(); $HTTP_SESSION_VARS['array_counter']['counter'] ++;
// Die Werte anzeigen. print("<b>\n"); print('Integer Zähler: '.$HTTP_SESSION_VARS['integer_counter']."<br>\n"); print('Objekt Zähler: '.$HTTP_SESSION_VARS['object_counter']->get()."<br>\n"); print('Array Zähler: '.$HTTP_SESSION_VARS['array_counter']['counter']."<br>\n"); print("</b>\n");
if (!isset($HTTP_GET_VARS['notable'])) { // Den Inhalt der Datenbank session ausgeben
// die Sessiondaten holen
$query = 'SELECT * FROM sys_session ORDER BY i_active DESC'; $qid = pg_exec($session_db, $query);
print("<br>Beachten Sie: <br>Die Session-Daten werden geschrieben, nachdem die Verbindung zum Datenbankserver geschlossen wurde. Darum ist der Stand des Session-Zugriffszählers um 1 geringer als der Stand des Session-Variablen-Zählers. "); print("Die Sessiondaten werden vor dem Update ausgegeben. Wenn Sie die Datenbank abfragen, erhalten Sie dieselben Werte wie oben angezeigt.<br>\n"); // Header ausgeben print("<table
border=\"2\"><tr>\n"); $row = 0; $rec = @pg_fetch_array($qid, $row, PGSQL_ASSOC); if (is_array($rec)) { foreach($rec as $k => $v) { print("<th>$k</th>\n"); } } print("</tr>\n");
// Print data while($rec = @pg_fetch_array($qid, $row++, PGSQL_ASSOC)) { print("<tr>\n"); foreach($rec as $k => $v) { print("<td>$v</td>\n"); } print("</tr>\n"); } print("</table>\n"); }
?>
|
© 2002 by Cornelia Boenigk |
|
|