Hallo,
ich habe zwei Probleme mit meinem selbstgeschriebenen, datenbankbasierter (MySQL 5) PHP5-Session-Handler. In das Ganze involviert ist außerdem die PHP-eigene mysqli-Schnittstelle, welche sich eine MySQLi-Wrapper-Klasse zunutze macht. Bevor ich Genaueres schreibe, hier schonmal meine beiden Probleme:
-
Die Garbage-Collector-Methode des Session-Handlers löscht alte Datenbank-Einträge erst nach 30 Stunden anstatt 30 Minuten (d.h. nach [eingestellte Zeit in Minuten] * 60). Das ist nicht nur Zufall: Über SHOW PROCESSLIST habe ich schon ein paar mal die Anfrage "... INTERVAL 1800 MINUTE ..." (30 * 60 = 1800) vom Garbage-Collector entdeckt. Wenn ich die Methode Session::_gc() aber "von Hand" aufrufe, steht im Datenbank-Query - wie erwünscht - "... INTERVAL 30 MINUTE ...".
-
Sporadisch tritt die Fehlermeldung "Notice: Object of class mysqli_result could not be converted to int in [...]index.php on line 85" auf. In dieser Zeile steht nichts außer "session_start();". Das interessante ist, dass das wirklich nur sporadisch auftritt - bei ca. 98% aller Skriptaufrufe kommt diese Fehlermeldung nicht. Ich konnte bisher keinerlei Regelmäßigkeit hinter diesen Meldungen erkennen. Weder erscheint sie immer beim ersten Aufruf der Website, noch beim "manuellen" Ändern oder Weglassen/Hinzufügen der/einer Subdomain o.Ä.
Und nun einige Informationen zu dem Skript und den Session-Konfigurationsvariablen.
// Session-Konfigurationsvariablen laut phpinfo() (lokale und globale Werte sind jeweils identisch)
session.auto_start Off
session.bug_compat_42 Off
session.bug_compat_warn On
session.cache_expire 180
session.cache_limiter nocache
session.cookie_domain no value
session.cookie_httponly Off
session.cookie_lifetime 0
session.cookie_path /
session.cookie_secure Off
session.entropy_file no value
session.entropy_length 0
session.gc_divisor 100
session.gc_maxlifetime 1440
session.gc_probability 0
session.hash_bits_per_character 4
session.hash_function 0
session.name PHPSESSID
session.referer_check no value
session.save_handler files
session.save_path /var/lib/php5
session.serialize_handler php
session.use_cookies On
session.use_only_cookies Off
session.use_trans_sid 0
// Definition der unten eingebauten Konstanten (vor dem Einbinden + Aufruf der Session-Klasse)
define('SESSION_LIFETIME', 30); // in minutes
define('SESSION_GC_PROBABILITY', 1);
define('SESSION_COOKIE_DOMAIN', ".meinedomain.de"); // hier steht natürlich im Original die echte Domain :-)
// Session-Handler-Klasse
ini_set('session.gc_maxlifetime', (int)SESSION_LIFETIME*60);
ini_set('session.gc_probability', SESSION_GC_PROBABILITY);
ini_set('session.gc_divisor', 100);
ini_set('session.cookie_domain', SESSION_COOKIE_DOMAIN);
$session = new Session();
class Session
{
public function __construct()
{
session_set_save_handler(array('Session', '_open'),
array('Session', '_close'),
array('Session', '_read'),
array('Session', '_write'),
array('Session', '_destroy'),
array('Session', '_gc'));
}
public function _open()
{
// DB-Verbindung besteht zu diesem Zeitpunkt bereits
}
public function _close()
{
// DB-Verbindung wird am Ende der Skriptlaufzeit geschlossen
}
public function _read($sess_id)
{
global $db;
$res = $db->query("SELECT sess_data FROM sessions WHERE sess_id = '" . mysqli_real_escape_string($sess_id) . "'");
$row = mysqli_fetch_assoc($res);
return array_pop($row);
}
public function _write($sess_id, $sess_data)
{
global $db;
if(!is_object($db)) $db = new Sqli(DBDSN);
return $db->query("REPLACE INTO sessions SET sess_id = '" . mysqli_real_escape_string($sess_id) . "', last_access = NOW(), sess_data = '" .mysqli_real_escape_string($sess_data) . "'");
}
public function _destroy($sess_id)
{
global $db;
return $db->query("DELETE FROM sessions WHERE sess_id = '" . mysqli_real_escape_string($sess_id) . "'");
}
public function _gc($sess_lifetime = SESSION_LIFETIME)
{
global $db;
$db->query("DELETE FROM sessions WHERE last_access < DATE_SUB(NOW(), INTERVAL " . $sess_lifetime . " MINUTE)");
return $db->query("OPTIMIZE TABLE ".DBPREFIX."sessions");
}
}
Hat jemand einen Denkanstoß für mich?
Gruß,
Günther