Problem mit eigener Sessionverwaltung und mysqli

Mordor

Registered User
Mahlzeit allerseits
Ich wollte gestern eine Sessionverwaltung von normalem mysql auf mysqli umstellen. Da ich die Verbindung schon vorher in einem anderen Script hergestellt habe, habe ich die Variable für die Datenbankverbindung ($mysqli) über Global in die Klasse eingesetzt und diese dann der Klassenvariable $this->DB übergeben.

Hier erst mal der Code:
Code:
<?php
class sessionmanager
{
	const SESSIONNAME = 'SESSION';
	const DBDROP = "DROP TABLES session IF EXISTS";
	const DBDEVINITION = "
	CREATE TABLE  `session` (
 	`sessionid` VARCHAR( 32 ) NOT NULL ,
 	`userid` BIGINT( 20 ) NOT NULL ,
 	`variables` TEXT NOT NULL ,
 	`lacces` INT( 14 ) NULL ,
	PRIMARY KEY (  `sessionid` ),
	KEY `userid`(`userid`)
	) TYPE = MYISAM ;";
	
	private $DB;
	
	public function __construct() {
		global $mysqli;
		$this->DB= $mysqli;
		ini_set('session.use_trans_sid',1);
		ini_set('session.use_coockies',0);
		ini_set('session.gc_probability',1);
		session_module_name("user");
		session_set_save_handler(array('sessionmanager',
										'ms_open'),
								array('sessionmanager',
										'ms_close'),
								array('sessionmanager',
										'ms_read'),
								array('sessionmanager',
										'ms_write'),
								array('sessionmanager',
										'ms_destroy'),
								array('sessionmanager',
										'ms_gc'));								
		session_name(self::SESSIONNAME);
		session_start();
	}
	
	private function settable(){
		
		$this->DB->query(self::DBDROP);
		$this->DB->query(self::DBDEVINITION);
	}

	function ms_open($sesspath, $sessname)
	{
		$time = time();
		$sessid = session_id();
		$query = "SELECT * FROM session WHERE sessionid = '$sessid'";
		$sql = $this->DB->query($query);
		if($sql->num_rows == 0)
		{
			$query = "INSERT INTO`session`(`sessionid` , `lacces` ) VALUES ('$sessid', '$time');";
		}
		else 
		{
			$query = "UPDATE session SET lacces = '$time' WHERE sessionid='$sessid'";
		}
		$sql->close();
		$RS = $this->DB->query($query);
		return $RS;
	}
	
	function ms_read($sessid)
	{
		$query = "SELECT * FROM session WHERE sessionid = '$sessid'";
		$sql = $this->DB->query($query);
		$arrRS = $sql->fetch_assoc();
		if (is_array($arrRS))
		{
			return $arrRS[variables];
		}
		else
		{
			return FALES;
		}
		$sql->close();
	}
	
	function ms_write($sessid, $varis)
	{
		$query = "UPDATE session SET variables = '$varis' WHERE sessionid = '$sessid'";
		$sql = $this->DB ->query($query);
		return (bool)$sql;
	}
	
	function ms_destroy($sessid)
	{
		$query = "DELETE FROM session WHERE sessionid = '$sessid'";
		$RS = $hits->DB->query($query);
		return (bool) $RS;
	}
	
	function ms_gc($sesslt)
	{	
		$tstamp = time() - $sesslt;
		$query = "DELETE FROM session WHERE lacces < '$tstamp'";
		$RS = $this->DB->query($query);
		return (bool) $RS;
	}
	
	function ms_close()
	{
		return;
	}
}
new sessionmanager();

?>
Das ganze funktioniert eigentlich recht gut, bis auf die Funktion ms_write().
Jedesmal wenn PHP diese Funktion aufruft erhalte ich folgende Fehlermeldung:
Code:
[13-Apr-2007 02:30:05] PHP Fatal error:  Using $this when not in object context in /Applications/MAMP/htdocs/portal/includes/session_verwaltung.inc.php on line 89
Mit Zeile 89 ist die Zeile $sql = $this->DB->query($query) in der Funktion ms_write gemeint.
Das was ich nicht ganz verstehe ist, warum ich hier keinen Aufruf mit $this machen darf. In den anderen Funktionen funktioniert es ja auch. Und bis zu diesem Punkt läuft es ja einwandfrei.

Ich habe dann noch versucht, das ganze über mysqli_query aufzurufen, dass funktioniert auch. Jedoch hätte ich gerne den Aufruf mit $this, da dies zum einen sauberer ist, und zum anderen produziert der Aufruf mit myslqi_query noch ein PHP-Warning.

Vieleicht hab ich ja nur etwas übersehen, und jemand hat bessere Augen wie ich.

Gruß Mordor
 
Hallo Mordor,

die Zeile 89...bist Du Dir sicher, dass er da ms_write und nicht ms_destroy meint?

Denn in der wäre zumindest mal ein Fehler:
Code:
	function ms_destroy($sessid)
	{
		$query = "DELETE FROM session WHERE sessionid = '$sessid'";
		$RS = [B]$hits[/B]->DB->query($query);
		return (bool) $RS;
	}

Was meinst Du?

Grüße
Sinepp
 
@Sinepp
Danke auf jedenfall schon mal für den Fehler. Hab den gleich mal ausgebessert, und es funktioniert immer noch nicht. Bekomme immer noch die gleiche Meldung.

Außerdem ist es ja so, dass wenn ich die Zeile in der ms_write ändere, und anstatt $this->DB->query den Befehl mysqli_query verwende, dann funktioniert es ja. PHP scheint sich nur an dem Aufruf $this zu stören, und sagt dazu, dass dies hier kein Objekt ist. Das Komische ist ja auch, dass es in den anderen Funktionen ja auch funktioniert.

Gruß Mordor
 
Last edited by a moderator:
So, ich bin jetzt schon mal nen Schritt weiter!

Ich habe die Variable $DB bei der Initalisierung von
Code:
private $DB
auf
Code:
private static $DB
geändert. Danach rufe ich sie in allen Funktionen nichtmehr mit
Code:
$this->DB
sondern mit
Code:
self::$DB
auf.

Das was ich erreicht habe ist, dass mit PHP keinen Fatal Error mehr ausspuckt, sondern nur noch
Code:
[13-Apr-2007 20:33:53] PHP Warning:  mysqli::query() [<a href='function.mysqli-query'>function.mysqli-query</a>]: Couldn't fetch mysqli in /Applications/MAMP/htdocs/portal/includes/session_verwaltung.inc.php on line 85

Die Sache ist nur, dass ich damit nicht wirklich leben will. Das Programm geht zwar duchr, und er arbeitet alle Instanzen der Klasse ab, jedoch denke ich mir sollte ich das Warning auch noch weg bekommen.

Har vieleicht jemand noch ne Idee?
 
Mahlzei
Nein, der ist mir auch schon aufgefallen.
Es geht ja viel mehr darum, dass alle Funktionen sauber aufgerufen werden. Mittlerweile auch die Writefunktion, nachdem ich die Variable $DB als static eingesetzt habe. Das Problem ist nur noch, dass PHP in den ebuglogs ein Warnung verursacht, und ich dieses gerne weg hätte. Denn irgendwie macht mich das noch nervös, bzw. ich möchte das ganze nicht so online stellen.
 
Hallo.

Also PHP gehoert ja nun zu den Sprachen mit denen ich noch nichts gemacht habe, aber die Meldung hier
Code:
[13-Apr-2007 02:30:05] PHP Fatal error:  Using $this when not in object context in /Applications/MAMP/htdocs/portal/includes/session_verwaltung.inc.php on line 89
Mit Zeile 89 ist die Zeile $sql = $this->DB->query($query) in der Funktion ms_write gemeint.
koennte man so interpretieren, dass die Methode zu einem Zeitpunkt aufgerufen wurde, zu dem das betreffende Objekt nicht (mehr) existierte.

Nur so eine Idee sowas passiert ja auch schon mal schnell und der Gebrauch von this erfolgt ja in der Klassendefinition eindeutig im "richtigen Kontext".
Wie gesagt, ich kenne PHP so nicht und kann nicht beurteilen, ob ein quasi statischer Methodenaufruf so durchgehen wuerde, aber das koennte auch noch eine Ursache sein die nicht so schnell ins Auge faellt weil da der Zustand des Objektes im Programmablauf gefragt ist.

Ciao,
Mercy.
 
@Mercenary
Klingt eigentlich plausibel. Dann wäre meine nächste Frage, ob jemand weiß, wann die Funktion ms_write von PHP aufgerufen wird.
Prinzipiell ist das komplette Skript so angelegt, dass zuerst ein Skript aufgerufen wird, in welchem die Klasse mysqli erstellt und initalisiert wird. Danach rufe ich das Skript für die Sessionverwaltung auf. Darauf folgen dann sämtliche Sachen, die für die eigentliche Seite wichtig wären und zum Schluss schliesse ich dann mysqli mit $mysqli->close()

Jetzt ist die Frage, ob ms_write erst aufgerufen wird, wenn das komplette Skript durchgelaufen ist, was heißen würde, dass es erst aufgerufen wird, wenn die Klasse mysqli schon wieder geschlossen wurde.

Auf jedenfall eine gute Idee, werde das mal ausprobieren.

Der Grund warum ich das ganze so abändern wollte ist folgender:
Forher hatte ich die Sessionverwaltung über eine komplett eigene Mysql-Verbindung am laufen. Das Problem ist aber, dass Sobald jemand ein Skript aufruft, zwei Datenbankverbindungen gleichzeitig am laufen sind. Dies wollte ich einfach auf eine Datenbankverbindung minimieren. Vieleicht geht das auch garnicht.


[Edit]Also ich habs jetzt mal ausprobiert. Es ist vom Ablauf her so, dass zuerst ms_read aufgerufen wird. Danach wirden sämtliche Skripts aufgerufen, und wenn diese abgearbeitet sind, dann wird erst ms_write und ms_close aufgerufen.
Also ist zu dem Zeitpunkt wo ms_write aufgerufen wird, die mysqli-Verbindung schon wieder geschlossen, da ich diese im Hauptskript am Ende schließe.

Dann dachte ich mir, dass ich sie einfach nicht am Ende des Hauptskripbt schließe sondern erst in der Funktion ms_close. Das führt jedoch dazu, dass ich dann zwei warnungen bekomme. Zum einen die die wir schon kennen aus der Funktione ms_write, zum anderen noch eine aus der Funktion ms_close.
Also wird mir wohl nichts anderes übrig bleiben, als für die Sessionverwaltung eine eigene Verbindung zu erstellen. Oder fällt irgendjemandem noch eine andere Variante ein???
 
Last edited by a moderator:
Kann es sein, daß Du PHP5 nutzt?
Dort dürfen keine Objekt-Instanzen für die Funktionen verwendet werden.
(Bevor ein Haarspalter kommt: Ja, nur für die Schreib- und Beenden-Funktionen. Aber mal ehrlich: Warum sollte man 2 Funktionen als Objekt und 2 ohne schreiben.)
Siehe roten Kasten: PHP: session_set_save_handler - Manual

D.h. Deine Funktionen werden ausserhalb des Instanz-Kontext aufgerufen und kennen keine Belegung für gewisse Variablen. Der Versuch mit static hätte klappen können, wenn Du hier nicht das mysqli-Objekt hinterlegt hättest sondern den Handler (bzw. im mysqli-Jargon: "Link"). Denn dieser wird bei permanenten Verbindungen nicht ins Nirvana geschickt. Dann kannst Du über mysqli_query auf die Datenbank zugreifen.
Abgesehen davon vermisse ich aber den (fast vorgeschriebenen) "$rs->close();" nach jedem query(). Denn damit kannst Du ganz hässlich Nebeneffekte bei anderen Queries produzieren, bei denen Du ewig nicht drauf kommst, was da jetzt sperrt.

huschi.
 
Danke erst mal. Sieht wohl so aus, dass ich die alte Sessionverwaltung verwenden werde. Die funktioniert mit einem normalen mysql und hat die komplette Datenbankverbindung integriert. Diese hat auch keine Probleme gemacht.

Danke nochmal an alle!
 
Back
Top