MindBlower: Who-is-Online Anzeige

Guten Tag,

ich programmiere gerade mit PHP und MySQL (selbstredend mit HTML, CSS, JavaScript und JQuery) ein Portal mit Login-Funktion. Durch den Login werden konfigurations-bedingt Funktionen freigeschaltet.

Eine Anforderung ist es, die momentan eingeloggten User (genauer: deren Usernamen) als Link auf ihr Profil anzuzeigen.

Ich habe von einem OpenSource-Board (PunBB) abgeguckt. Der Programmierer dort löst das mit einer MySQL-Tabelle vom Typ "MEMORY".
Bevor ich mich jetzt sinnlos in diesen Tabellen-Typ einlese, würde ich gerne wissen, ob es eine "elegantere", "einfachere" oder "performantere" Lösung gibt.
Natürlich vor dem Hintergrund, dass User einfach den Browser beenden und vergessen, davor "Logout" zu betätigen.

Gruß

  1. Hi,

    Eine Anforderung ist es, die momentan eingeloggten User (genauer: deren Usernamen) als Link auf ihr Profil anzuzeigen.

    Ich habe von einem OpenSource-Board (PunBB) abgeguckt. Der Programmierer dort löst das mit einer MySQL-Tabelle vom Typ "MEMORY".
    Bevor ich mich jetzt sinnlos in diesen Tabellen-Typ einlese, würde ich gerne wissen, ob es eine "elegantere", "einfachere" oder "performantere" Lösung gibt.

    So viel Arbeit ist das wohl nicht, sich mal kurz zu informieren, was es mit dieser Storage Engine auf sich hat, und wo ggf. die Vor- und Nachteile in Bezug auf das Vorhaben liegen.
    Also kein Grund, diese Arbeit auf uns abzuwälzen, noch dazu mit einer so pauschalen „oder gibt's was besseres“-Fragestellung :-)

    Natürlich vor dem Hintergrund, dass User einfach den Browser beenden und vergessen, davor "Logout" zu betätigen.

    Was soll dieser Hintergrund mit der Speicherung der notwendigen Daten an sich zu tun haben?

    MfG ChrisB

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
  2. Mahlzeit MindBlower,

    Eine Anforderung ist es, die momentan eingeloggten User (genauer: deren Usernamen) als Link auf ihr Profil anzuzeigen.

    Definiere zunächst, was "momentan eingeloggt" bedeutet. Bedenke dabei, dass HTTP ein zustandsloses Protokoll ist.

    "Momentan eingeloggt" könnte z.B. bedeuten, dass eine gültige und nicht abgelaufene Session für den jeweiligen Benutzer existiert. Oder auch, dass der Benutzer in den letzten x Sekunden eine beliebige Interaktion mit dem Server vorgenommen hat. Oder ...

    Letztendlich musst Du dann "nur" für alle "momentan eingeloggten" Benutzer in irgendeiner beliebigen Form (z.B. in einer Datenbank) abspeichern, dass sie "momentan eingeloggt" sind - ob das über ein Flag in einer bestehenden Tabelle, in einer neuen Tabelle (die dann aber regelmäßig aufgeräumt werden muss: Stichworte "Garbage collection" und/oder "cron") oder auf anderem Wege geschieht, ist nahezu egal.

    Natürlich vor dem Hintergrund, dass User einfach den Browser beenden und vergessen, davor "Logout" zu betätigen.

    Du hast offenbar das größte Problem schon erkannt ... :-)

    MfG,
    EKKi

    --
    sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
    1. Hallo,

      Definiere zunächst, was "momentan eingeloggt" bedeutet. Bedenke dabei, dass HTTP ein zustandsloses Protokoll ist.

      "Eingeloggt" soll der Zeitraum zwischen dem Login und Logout bzw. dem Browser-Schließen bedeuten.

      Stichworte "Garbage collection" und/oder "cron"

      Cronjobs stehen mir leider nicht zur Verfügung.
      Werde mich mal über die anderen Möglichkeiten "Garbage Collection" und den Flags informieren.

      Gruß

      1. Definiere zunächst, was "momentan eingeloggt" bedeutet. Bedenke dabei, dass HTTP ein zustandsloses Protokoll ist.

        "Eingeloggt" soll der Zeitraum zwischen dem Login und Logout bzw. dem Browser-Schließen bedeuten.

        Seltsame Definition. Für mich ist "eingelogged" der Zustand, indem mein Browser ein noch nicht verfallenes Cookie bewahrt.
        Ob ich dazwischen den Browser 10 mal beende, ist doch egal, denn das ist meine Einstellungssache.

        Wenn du die Verfallfrist des ausgelieferten Cookies weist, kannst du auch meinen maximalen Login-Zustand voraussagen.

        mfg Beat

        --
        ><o(((°>           ><o(((°>
           <°)))o><                     ><o(((°>o
        Der Valigator leibt diese Fische
        1. Hi,

          "Eingeloggt" soll der Zeitraum zwischen dem Login und Logout bzw. dem Browser-Schließen bedeuten.
          Seltsame Definition. Für mich ist "eingelogged" der Zustand, indem mein Browser ein noch nicht verfallenes Cookie bewahrt.

          auch eine gute Betrachtungsweise. Als Betreiber eines Login-Systems würde ich aber sowieso Cookies mit einer Lebensdauer nur bis zum Ende der Browsersession setzen. Wenn dem Besucher zwischendurch das System abschmiert, muss er sich halt neu einloggen.

          Ciao,
           Martin

          --
          Frage an Radio Eriwan: Kann man eigentlich ein guter Kommunist und gleichzeitig ein guter Christ sein?
          Radio Eriwan antwortet: Im Prinzip ja - aber warum sollte man sich das Leben doppelt schwer machen?
          Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
      2. Mahlzeit MindBlower,

        Definiere zunächst, was "momentan eingeloggt" bedeutet. Bedenke dabei, dass HTTP ein zustandsloses Protokoll ist.

        "Eingeloggt" soll der Zeitraum zwischen dem Login und Logout bzw. dem Browser-Schließen bedeuten.

        Welche Relevanz hat das Browser-Schließen für den Webserver? Richtig: absolut keine. Deswegen hatte ich den zweiten Satz geschrieben.

        Du wirst also (vermutlich) nicht um die Implementierung eines entsprechenden Session-Handlings herumkommen.

        MfG,
        EKKi

        --
        sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
      3. Hi,

        "Eingeloggt" soll der Zeitraum zwischen dem Login und Logout bzw. dem Browser-Schließen bedeuten.

        das ist aber eine Definition, die du nicht in die Praxis umsetzen kannst, denn das Schließen des Browsers (oder auch das userseitige Trennen der Internet-Verbindung) bekommst du nicht mit. Du musst also eine realistische Zeit t definieren und den Login-Status per Timeout bestimmen.
        Demnach gilt ein Benutzer als eingeloggt, wenn seit seinem letzten Request (Lebenszeichen) nicht mehr als die Zeit t vergangen ist und er sich nicht explizit ausgeloggt hat. Als typische Verfallzeit eines Logins könnte ich mir zwischen 10 und 30 Minuten vorstellen.

        Das heißt natürlich auch: Wenn ein Benutzer sich einloggt und dann eine halbe Stunde den Rechner einfach stehenlässt, ist er automatisch auch ausgeloggt.

        Stichworte "Garbage collection" und/oder "cron"

        Warum? Es reicht, den Login-Status aller in Frage kommenden User beim nächsten beliebigen Request neu zu bestimmen. Was zwischendurch los ist, kriegt sowieso niemand mit.

        So long,
         Martin

        --
        F: Was sagt die kleine Kerze zur großen Kerze?
        A: Ich gehe heute nacht aus!
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        1. Hallo Martin

          Du musst also eine realistische Zeit t definieren und den Login-Status per Timeout bestimmen.
          Demnach gilt ein Benutzer als eingeloggt, wenn seit seinem letzten Request (Lebenszeichen) nicht mehr als die Zeit t vergangen ist und er sich nicht explizit ausgeloggt hat. Als typische Verfallzeit eines Logins könnte ich mir zwischen 10 und 30 Minuten vorstellen.

          Okay, soviel zur Theorie des Einloggens und des Eingeloggt-bleibens.
          Aber wie stelle ich nun dar, welche User derzeit das Cookie noch haben?

          Gruß
          MindBlower

          1. Mahlzeit MindBlower,

            Aber wie stelle ich nun dar, welche User derzeit das Cookie noch haben?

            Ein Cookie (auf Client-Seite) muss natürlich immer einem entsprechenden Objekt auf Server-Seite (z.B. eine gültige Session, ein entsprechender Eintrag in einer Tabelle o.ä.) gegenüberstehen.

            MfG,
            EKKi

            --
            sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
            1. Hallo,

              Ein Cookie (auf Client-Seite) muss natürlich immer einem entsprechenden Objekt auf Server-Seite (z.B. eine gültige Session, ein entsprechender Eintrag in einer Tabelle o.ä.) gegenüberstehen.

              Na schön, ich kann ein Cookie erstellen, das die Session-ID in sich trägt und eine Ablaufzeit von 20 Minuten hat. Ich kann auch einen Tabellen-Eintrag erzeugen, der quasi nur aus Session-ID, Username/UserID und Online-Status besteht.
              Aber ich habe keinen Trigger dafür, was passiert, wenn das Cookie abläuft. Nirgends kann ich dann ein Skript laufen lassen, das mir den Tabellen-Eintrag rauslöscht.
              Der Server merkt eh erst frühestens dann, wenn der User das nächste mal auf die Seite geht, dass die Session abgelaufen ist.

              Gruß

              1. Na schön, ich kann ein Cookie erstellen, das die Session-ID in sich trägt und eine Ablaufzeit von 20 Minuten hat. Ich kann auch einen Tabellen-Eintrag erzeugen, der quasi nur aus Session-ID, Username/UserID und Online-Status besteht.
                Aber ich habe keinen Trigger dafür, was passiert, wenn das Cookie abläuft. Nirgends kann ich dann ein Skript laufen lassen, das mir den Tabellen-Eintrag rauslöscht.
                Der Server merkt eh erst frühestens dann, wenn der User das nächste mal auf die Seite geht, dass die Session abgelaufen ist.

                Das ist auch nicht nötig, denn du speicherst eben auch das Verfallsdatum.
                Die Tabelle wird dann einfach 1mal täglich via Cronjob bereinigt.
                Anderseits kannst du sie ja bei jedem Schreibzugriff bereinigen.

                mfg Beat

                --
                ><o(((°>           ><o(((°>
                   <°)))o><                     ><o(((°>o
                Der Valigator leibt diese Fische
                1. Hallo,

                  Das ist auch nicht nötig, denn du speicherst eben auch das Verfallsdatum.
                  Die Tabelle wird dann einfach 1mal täglich via Cronjob bereinigt.
                  Anderseits kannst du sie ja bei jedem Schreibzugriff bereinigen.

                  Jetzt macht das ganze Sinn! Vielen Dank!

                  Gruß

    2. Grüße,

      Definiere zunächst, was "momentan eingeloggt" bedeutet. Bedenke dabei, dass HTTP ein zustandsloses Protokoll ist.

      da war doch mal ein gespinne mit dem websocket, bei aller Unsicherheit - warum ist es noch mal nicht durchgegangen?
      MFG
      bleicher

      --
      __________________________-

      FirefoxMyth
  3. Wow... Zig Diskussionen und keine geht darauf ein, wie man das "in der Regel" löst...

    Also:

    Binde ein Script in ALLE Seiten Deines Projektes ein (z.B. im Header oder per include), das folgendes tut:

    • Speichere in einer Tabelle die Benutzernamen + User-ID + aktuellen Timestamp ab
    • Lösche direkt danach alle Einträge aus der Tabelle, deren Timstamp älter als z.B. 3-5 Minuten ist

    Selectiere dann an gewünschter Stelle alle Datensätze aus dieser Tabelle (Distinct) als Liste und Du hast, was Du brauchst. Die Anzahl der Online-Nutzer kannst Du so auch ausgeben.

    "Gerade online" bezieht sich dann auf die letzten 3-5 Minuten. Mehr geht nicht, siehe andere Diskussionen zu Deinem Thema. So machen das in der Regel ALLE anderen Gerade-Online-Anzeigen auch.

    Um es genauer hinzubekommen, kannst Du auch per AJAX oder notfalls in einem iFrame ein Script einbinden, das sich z.B. alle 30-60 Sekunden reloaded und den Datensatz aktualisiert. Dann hast Du auch noch die als Online, die die Seite zwar geöffnet haben, aber seit mehr als 3-5 Minuten nichts mehr AKTIV gemacht haben.

    Nutzer, die die Seite verlassen haben, werden dann nach 3-5 Minuten aus der Tabelle gelöscht und so lange ggf. noch als online angezeigt. Wenn sie sich AUSLOGGEN, kannst Du ja gleich die Datensätze aus der Tabelle löschen. Beim schließen des Browsers ohne ausloggen, logischerweise nicht.

    Gruß,
    Andreas

      • Speichere in einer Tabelle die Benutzernamen + User-ID + aktuellen Timestamp ab
      • Lösche direkt danach alle Einträge aus der Tabelle, deren Timstamp älter als z.B. 3-5 Minuten ist

      Kleine Ergänzung:
      Dieses Script sollte sich VOR der Ausgabe der Liste befinden, da Nutzer erst gelöscht werden, wenn jemand das Script aufruft. Wenn also ein Nutzer die Seite verlässt und kein anderer Online ist, wird auch nichts aus der Tabelle gelöscht. Wenn dann nach ca. 30 Minuten der nächste kommt, stehen noch Nutzer als "online" drin, die längst weg sind. Die werden erst beim erneuten Scriptaufruf gelöscht. Daher sollte dieses Script VOR der Ausgabe liegen, damit diese stimmt.

      Cronjobs brauchst Du dafür aber nicht.

    1. Hallo Andreas,

      Danke für diese ausführliche Anleitung. Genau in dieser Richtung habe ich mir das vorgestellt. Das hat sich aber gestern Abend in diesem Thread noch herauskristallisiert ;-)

      MfG

  4. Guten Morgen zusammen,

    zu dem o.g. Problem. Ich werde das nun mit einem Cookie mit einer Gültigkeit von 10 Minuten und einem entsprechenden Tabelleneintrag lösen.

    Mein Problem ist, dass das Cookie beim Login erfolgreich gesetzt wird, und der Tabelleneintrag auch richtig geschrieben wird.
    Ebenso wird die Expire-Zeit des Cookies bei jeder User-Interaktion hochgesetzt.
    Aber wenn ich dann print_r($_COOKIE); schreibe, wird das Cookie nicht mit angezeigt. Die Cookie-Übersicht des Browsers zeigt aber eindeutig, dass das Cookie angenommen wurde und auch die Expire-Zeit in der Zukunft liegt.
    Demnach kann ich natürlich nicht Cookie-abhängig die zusätzlichen Funktionen anzeigen lassen.

    Hier ist die Stelle, an der das Cookie gesetzt wird:

      
    setcookie('tmp_session_id', session_id(), time() + (10 * 60), "/", "sub.domain.de") or $elements[]="Cookie konnte nicht gesetzt werden";  
    
    

    Und hier die Stelle, an der das Cookie hochgesetzt wird:

      
    unset($_COOKIE['tmp_session_id']);  
    setcookie('tmp_session_id', session_id(), time() + (10 * 60), "/", "sub.domain.de");  
    
    

    Habe schon viel mit dem vierten und fünften Parameter der setcookie-Funktion herumexperimentiert. Egal wie, ob mit Expire-Zeit oder ohne, ob mit Pfadangabe und Domain oder ohne - das Cookie wird von PHP nicht erkannt oder akzeptiert.

    Gruß

    1. Hallo,

      Mein Problem ist, dass das Cookie beim Login erfolgreich gesetzt wird, und der Tabelleneintrag auch richtig geschrieben wird.
      Ebenso wird die Expire-Zeit des Cookies bei jeder User-Interaktion hochgesetzt.
      Aber wenn ich dann print_r($_COOKIE); schreibe, wird das Cookie nicht mit angezeigt.

      ist dir vielleicht nicht bewusst, dass das Cookie ja erst beim nächsten Request wieder beim Server ankommt?

      Demnach kann ich natürlich nicht Cookie-abhängig die zusätzlichen Funktionen anzeigen lassen.

      Doch, normalerweise schon.

      setcookie('tmp_session_id', session_id(), time() + (10 * 60), "/", "sub.domain.de") or $elements[]="Cookie konnte nicht gesetzt werden";

      Das setzt noch nicht wirklich ein Cookie; da wird nur der HTTP-Header Set-Cookie "vorgemerkt", der mit dem Dokument an den Client ausgeliefert wird. Erst beim nächsten Request zeigt der Client das Cookie wieder vor.
      Unmittelbar nach dem setcookie() musst du dir den Status also entweder anderweitig merken (z.B. den damit korrelierenden Datenbankeintrag sofort vornehmen), oder ein Redirect auslösen und so den Client zu einem erneuten Request "überreden". Letzteres ist weniger schön, weil es unnötig Traffic erzeugt.

      Ciao,
       Martin

      --
      Frage an Radio Eriwan: Kann man eigentlich ein guter Kommunist und gleichzeitig ein guter Christ sein?
      Radio Eriwan antwortet: Im Prinzip ja - aber warum sollte man sich das Leben doppelt schwer machen?
      Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
      1. Hallo,

        ist dir vielleicht nicht bewusst, dass das Cookie ja erst beim nächsten Request wieder beim Server ankommt?

        Doch, ist es mir. Dann müsste ein Refresh reichen, und das Cookie sollte "da" sein. Ist es aber nicht. Die Cookie-Anzeige im Browser sagt dagegen schon, dass das Cookie akzeptiert wurde.

          
        if(isset($_POST['login']) AND $_POST['login']=="Einloggen")  
        {  
        	//Wenn Login-Button geklickt  
        	$sql = "SELECT * FROM ".SQL_PRE."users WHERE name=\"".htmlspecialchars($_POST['u_name'])."\" AND password=\"".md5(htmlspecialchars($_POST['u_pw']))."\"";  
        	$res = $db->query($sql);  
        	if($res == false)  
        		$elements[]=$formular[0]."<p class=\"red\">Datenbank-Fehler: ".$db->error."</p>".$formular[1];  
        	elseif($db->num_rows($res)!=1)  
        		$elements[]=$formular[0]."<p class=\"red\">Falscher Username oder Passwort</p>".$formular[1];  
        	else  
        	{  
        		//Wenn Login-Daten passen  
        		unset($_SESSION['current_user']); $_SESSION['current_user']=$db->fetch_assoc($res);  
        		$db->query("INSERT INTO ".SQL_PRE."online (`user_id`, `session_id`, `expire_time`) VALUES (".$_SESSION['current_user']['ID'].", '".session_id()."', '".date("Y-m-d H:i:s", time() + (10 * 60))."')") or $elements[]=$db->error;  
        		setcookie('tmp_session_id', session_id(), time() + (10 * 60), "/", "sub.domain.de") or $elements[]="Cookie konnte nicht gesetzt werden";  
        		$elements[]=$formular[0]."Erfolgreich. <a href=\"index.php\">Weiter &gt;&gt;</a></form>";  
        	}  
        }  
        else  
        {  
        	//Login-Maske anzeigen  
        	$elements[]=implode($formular);  
        }  
        
        

        $elements ist nachher das Array, das durch implode() angezeigt wird.

        Gruß

        1. Hi,

          ist dir vielleicht nicht bewusst, dass das Cookie ja erst beim nächsten Request wieder beim Server ankommt?
          Doch, ist es mir.

          dann ist Dir also klar, dass jeder Code, der den setcookie()-Befehl enthält, für Deine Fragestellung irrelevant ist.

          Dann müsste ein Refresh reichen, und das Cookie sollte "da" sein. Ist es aber nicht.

          Der von Dir genannte Code enthält nichts, woran sich diese Behauptung festmachen ließe.

          Cheatah

          --
          X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
          X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
          X-Will-Answer-Email: No
          X-Please-Search-Archive-First: Absolutely Yes