PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Sessionklasse



Turbohummel
06-03-2006, 17:28
Hallo,

ich suche eine Sessionklasse, die auf eine Datenbank (MySQL MEMORY/HEAP) aufsetzt.
Nein, besser: Mit der ich mit einem Script alle Sessions, die laufen, ansehen und bearbeiten / löschen kann. Insbesondere soll ein "Doppellogin" eines Users verhindert werden. Eine solche muss aber wohl auf eine Datenbank aufsetzen, was ich auch für ok halte, RAM steht genug zur Verfügung.

Weitere Anforderungen:
- Lesbarer Code
- Sessionvariablen als einfache Variablen und Arrays, Objekte nicht notwendig
- Lösung über Cookies, Fallbacksystem nicht notwendig

Ich lege mehr wert auf Performance als auf Flexibilität.

Natürlich habe ich auch schon selbst gesucht, frage aber nochmal, welche dieser Klassen ihr einsetzt.

Gruß

Turbohummel

Gaert
07-03-2006, 08:28
Hallo,

Ich benutze eine eigene Klasse für das Session handling zum speichern der Session in einer Datenbank - ließe sich auch erweitern für Shared Memory, wenn man sehr viel Wert auf Performance legt. Das ganze basiert auf dem Standard Session Management von PHP - ich lege die Daten lediglich woanders ab. Wenn du ein beispiel brauchst kann ich sie dir mal schicken (per pm melden), ansonsten reichts eigentlich sich die Session Funktionen anzusehen und die User Comments zu lesen: http://de2.php.net/session

Gruß,

Gaert

Turbohummel
07-03-2006, 16:09
Hallo,

inzwischen hab ich ne Lösung entwickelt, die mein Problem (absolut sicheres Verhindern von Doppellogins - das wäre für den Zweck nämlich tödlich) viel einfacher lösen. Beim Erzeugen einer Session (sprich beim Login) wird in einer MySQL-Heap-Tabelle "active_sessions" (Felder: session_id, user_id, start) ein "DELETE FROM active_sessions WHERE user_id = xxx LIMIT 1" ausgeführt und die neue Session eingetragen. Bei jedem Seitenaufruf gucke ich in die Tabelle, ob die Session-id noch eingetragen ist. Wenn nein -> Session beenden.

Einfach, aber genau das was ich will (wieder mal einer meiner Ideen, die ich Nachts um 3 hatte).

nul
16-03-2006, 14:18
Ich hab das so geloest dass wenn fuer einen Benutzer bereits eine Session existiert er ueberhaupt nicht mehr auf die Login-Seite kommt sondern immer auf die Hauptseite zurueckgeleitet wird.

Turbohummel
16-03-2006, 16:30
Das löst das Problem nicht, wenn der User sich von nem anderen PC aus einloggt - was ja eben verhindert werden soll.

nul
16-03-2006, 18:49
Doch, es wird ja ueberprueft ob der Benutzer schon angemeldet ist - und wenn das so ist wird er einfach mit ner Fehlermeldung wieder zum Login geschickt!

Turbohummel
17-03-2006, 05:50
Da würd ich gerne mal den Code sehen, um das auszuprobieren.

nul
17-03-2006, 11:09
Das ganze System ist zwar noch nicht ganz ausgereift, aber ich kann mal die Kernstuecke posten.
In der login.php hab ich folgendes am Anfang:

<?php
require_once dirname( __FILE__ ) . '/include/config/config.inc.php';

if ( !$session->requireNewSession() ) {
redirectTo( 'index.php' );
}

if ( isset( $_POST['usr_login'] ) && isset( $_POST['usr_pass'] ) ) {
$user = new User();
if ( $user->exists( $_POST['usr_login'], md5( $_POST['usr_pass'] ) ) ) {
$_SESSION['sss_usr'] = $user->getAttribute( 'usr_id' );
$session->registerNewSession( $_SESSION['sss_usr'] );

if ( !$session->requireNewSession() ) {
if ( count( $emess ) > 0 )
$_SESSION['sss_usr'] = -1;
redirectTo( 'index.php' );
}
}
}
?>
In $emess stehen dabei die Meldungen, die aufgetreten sind, als man sich versucht hat anzumelden. Im Fall vom zweiten Login waere das zum Beispiel die Fehlermeldung von MySQL, dass der Benutzer schon angemeldet ist.
Die MySQL-Tabelle dazu sieht so aus:

CREATE TABLE `usm_session` (
`sss_id` int(11) unsigned NOT NULL auto_increment,
`sss_usr` int(11) unsigned NOT NULL default '0',
`sss_ip` varchar(25) NOT NULL default '',
`sss_port` varchar(255) NOT NULL default '',
`sss_tstamp` timestamp(14) NOT NULL,
PRIMARY KEY (`sss_id`),
UNIQUE KEY `sss_usr` (`sss_usr`)
) ENGINE=MyISAM AUTO_INCREMENT=47 ;
die User-id ist unique, deshalb bekomm ich dann immer die Meldung!
Im Prinzip sollte damit alles gesagt sein.
Vielleicht die Session-Klasse noch:

<?php
class Session {

function Session() {
}

function requireNewSession() {
$result = TRUE;

$config =& $GLOBALS['config'];
$database = new Database( $config );
$database->connect();
$database->selectDB();

$timeout = $config->getValue( 'timeout' );
$select = $this->_startSession( $timeout );

if ( $select->getRowNums() == 1 ) {
$result = FALSE;
} else {
$this->_destroySession( $timeout );
$result = TRUE;
}
$select->freeResult();
$database->disconnect();

return $result;
}

function registerNewSession( $userId ) {
$database = new Database( $GLOBALS['config'] );
$database->connect();
$database->selectDB();

$fields = array( 'sss_usr' => $userId, 'sss_ip' => $_SERVER['REMOTE_ADDR'],
'sss_port' => $_SERVER['REMOTE_PORT'],
'sss_tstamp' => date( 'YmdHis', mktime() ) );
$insert = new Insert( 'usm_session', $fields );
$insert->execQuery();

$database->disconnect();
}

function _startSession( $timeout ) {
$timeout = $this->_getCorrectTimeoutCalc( $timeout );
$select = new Select( NULL, 'usm_session' );
$select->addWhere( array( 'sss_usr' => $_SESSION['sss_usr'] ) );
$select->addWhere( array( 'sss_tstamp' => $timeout ), '>', 'AND' );
$select->execQuery();
return $select;
}

function _destroySession( $timeout ) {
$timeout = $this->_getCorrectTimeoutCalc( $timeout );
$delete = new Delete( 'usm_session' );
$delete->addWhere( array( 'sss_usr' => $_SESSION['sss_usr'] ) );
$delete->addWhere( array( 'sss_tstamp' => $timeout ), '<', 'AND' );
$delete->execQuery();
}

function _getCorrectTimeoutCalc( $timeout ) {
$now = date( 'YmdHis', mktime() );
return "'$now' - '$timeout'";
}
};
?>
Die Klassen Database, Select, Insert, Delete, User und Config poste ich mal nicht, das wird zu viel. Und das Abmelden fehlt noch.
Und damit sind wir auch schon beim Problem das auftreten kann!
Wenn man z.B. irgendwo eingelogged ist und beendet die Sitzung nicht regulaer, dann kann sich derselbe Bentuzer solange nicht mehr anmelden bis das Timeout eingetreten ist - man muesste also den Session-Eintrag von Hand loeschen, dann kann er sich wieder anmelden!

mfg

P.S.: Waer das von Microsoft waerde das sicher ein Feature und kein Fehler :D

PierreS
17-03-2006, 22:27
Das einfachste ist wirklich beim Start einer Session die Einträge zu löschen, die unter der gleichen ID gespeichert sind. Das ist ziemlich robust.

Turbohummel
18-03-2006, 07:27
@PierreS: Jop, mach ich ja auch so.

So ähnlich hab ich das auch gelöst, hattest du nur mit

Ich hab das so geloest dass wenn fuer einen Benutzer bereits eine Session existiert er ueberhaupt nicht mehr auf die Login-Seite kommt sondern immer auf die Hauptseite zurueckgeleitet wird.
nicht ganz so beschrieben, oder steh ich da auf dem Schlauch?

Als Tabellentyp würde ich HEAP nehmen, das ist für die Performance (in 99% der Fälle) förderlich.