php - current online user/besucher

06/27/2016 20:20 .Barone#1
Hallo, epvp'ler.

Ich hätte nochmal ne Frage bezüglich php.

Ich versuche einen online user counter zu schreiben sowie einen besucherzähler.

Folgendes passiert:
Wenn ein User zb auf die index.php geht wird folgende funktion ausgeführt:
Code:
if(isset($_SESSION['user'])){
$user = $_SESSION['user'];
$visit->visit($user['name']);
$visit->online($user['name']);
}
visit funktion:
Code:
public function visit($username){
$sec = new xss_sec;
$this->name = $sec->clear($username);
$this->ip = $_SERVER['REMOTE_ADDR'];
$this->zeitpunkt = $_SERVER['REQUEST_TIME'];
$this->sprache = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
if(isset($_SERVER['HTTP_REFERER'])){
$this->referer = $_SERVER['HTTP_REFERER'];
}else{
$this->referer = 'nicht angegeben';
}
$this->browser = $_SERVER['HTTP_USER_AGENT'];
$this->url = $_SERVER['REQUEST_URI'];
$this->requestmethode = $_SERVER['REQUEST_METHOD'];
$cn = new mysqli;
$timecheck = time();
$time = $timecheck - 600;
$count = $cn->query("SELECT * FROM `besucher` WHERE ip='".$this->ip."' AND zeitpunkt < '".$time."'");
if($count){
$insert = $cn->query("INSERT INTO `besucher`(`username`, `ip`,`zeitpunkt`,`sprache`, `referer`, `browser`, `url`, `requestmethode`) VALUES ('".$this->name."','".$this->ip."','".time()."','".$this->sprache."','".$this->referer."','".$this->browser."','".$this->url."','".$this->requestmethode."')");
}
}
Mir geht es darum, das nur ein Eintrag gemacht wird, wenn der Besucher schon länger wie ~10 minuten nicht mehr auf der Seite war.
Komme gerade nicht auf den punkt, was da falsch ist. Es wird jedesmal ein Eintrag gemacht.
Code:
$count = $cn->query("SELECT * FROM `benutzer` WHERE last_activity < '".$time ."'");
Gibt auch 0 aus. Ich denke mal ich habe hier einfach einen Denkfehler bei $time, oder?
06/27/2016 22:05 Bgzocker#2
Du machst eine Abfrage mit einer Bedingung bzgl. last_activity setzt diesen Wert aber nicht.
06/28/2016 00:57 #Metho#3
Ich verstehe ebenfalls nicht wieso du zuerst das ganze in ein Eigenschaften packst und dann erst ausgibst. Hat das seinen Sinn?
06/28/2016 07:56 FlyffServices#4
$count = $cn->query("SELECT * FROM `besucher` WHERE ip='".$this->ip."' AND zeitpunkt < '".$time."'");

Was ist davon der Return wert? Ich glaube das returnt eine Resource-ID zum query weswegen immer true ausgegeben wird.
Mach ne weitere funktion $cn->querycount(); die dann mittels mysql_num_rows den Counter der zeilen zurückgibt.

function querycount($qry)
{
return mysql_num_rows(mysql_query($qry));
}

Außerdem hoffe ich das du mittels mysql_escape_real_string() die einzelnen Strings filterst da du ansonsten jetzt schon einige SQL-Inejctionen hast (z.B Referer).
06/28/2016 09:46 #Metho#5
Quote:
Originally Posted by FlyffServices View Post
$count = $cn->query("SELECT * FROM `besucher` WHERE ip='".$this->ip."' AND zeitpunkt < '".$time."'");

Was ist davon der Return wert? Ich glaube das returnt eine Resource-ID zum query weswegen immer true ausgegeben wird.
Mach ne weitere funktion $cn->querycount(); die dann mittels mysql_num_rows den Counter der zeilen zurückgibt.

function querycount($qry)
{
return mysql_num_rows(mysql_query($qry));
}

Außerdem hoffe ich das du mittels mysql_escape_real_string() die einzelnen Strings filterst da du ansonsten jetzt schon einige SQL-Inejctionen hast (z.B Referer).
Das mit dem Resource stimmt, der Rest ist Quatsch, es geht hier um mysqli, dabei kann er prepared statements nutzen.

Generell braucht er zwei Querys

Eine um einen Benutzer zu speichern:
Code:
'INSERT INTO visitor (ip, last_activity) VALUES ("' . $_SERVER['REMOTE_ADDR'] . '", NOW()) ON DUPLICATE KEY UPDATE last_activity = NOW();';
Und eine um alle Benutzer aufzurufen

Code:
'SELECT COUNT(*) FROM visitor WHERE last_activity < NOW() - INTERVAL 600 MICROSECONDS;';
Alles andere als Ip zu speichern ist unschlüssig und sinnlos. Selbst die Ip würde ich noch mal hashen damit sich der Besucher auf der sicheren Seite fühlt.

Dann halt beim Query noch ->fetch benutzen
06/28/2016 11:17 .Barone#6
Habe das Problem gelöst.

Code:
$timecheck = time();
$time = $timecheck - 15;
$count = $cn->query('SELECT COUNT(*) FROM `besucher` WHERE ip="'.$this->ip.'" and zeitpunkt > "'.$time.'"');
$count = $count->fetch_assoc();
if($count['COUNT(*)'] > 0){
$update = $cn->query("UPDATE `besucher` SET zeitpunkt = '".$timecheck."' WHERE ip = '".$this->ip."' and zeitpunkt > '".$time."'");
}else{
$insert = $cn->query("INSERT INTO `besucher`(`username`, `ip`,`zeitpunkt`,`sprache`, `referer`, `browser`, `url`, `requestmethode`) VALUES ('".$this->name."','".$this->ip."','".time()."','".$this->sprache."','".$this->referer."','".$this->browser."','".$this->url."','".$this->requestmethode."')");
}
Danke ;)
06/28/2016 17:13 Waschbaerfell#7
Wenn du ein noch genaueres Tracking haben willst empfiehlt es sich auch Cookies einzubeziehen. Denn in einem Haushalt mit mehreren Endnutzern/Geräten wird auf IP Basis nur ein Nutzer gezählt werden.

Und mit Cookies kann man noch nette andere Spielereien anstellen... und die wenigen Nutzer die Cookies deaktiviert haben oder am Ende der Session löschen können dir egal sein. Für die lohnt es sich meistens nicht extra Aufwand zu betreiben ... aber auch dafür gibt es diverse Lösungen ...
06/28/2016 20:05 .Barone#8
@Waschbaerfell bis jetzt habe ich mich n wenig von Cookies distanziert da ich, wenn ich mich nicht gerade irre, gelesen habe das diese "manipuliert" werden können.

Edit: Erledigt
06/28/2016 20:14 False#9
Quote:
Originally Posted by .Barone View Post
@Waschbaerfell bis jetzt habe ich mich n wenig von Cookies distanziert da ich, wenn ich mich nicht gerade irre, gelesen habe das diese "manipuliert" werden können.

Edit: Erledigt
Das ist richtig, Cookies können erstellt, gelöscht und bearbeitet werden.
Wobei das bei einen "Online Cookie" egal sein sollte(Da irrelevant was drin steht).
06/28/2016 20:38 .Barone#10
Ich musste gerade etwas ziemlich komisches feststellen.
Beim Ausloggen wird der User auf die logout.php weitergeleitet mit folgendem inhalt:

Code:
$offline = $cn->query("UPDATE `benutzer` SET status='Offline' WHERE username='$username'");
session_destroy();
echo "<meta http-equiv='refresh' content='0, url=index.php'>";
Das klappt so wunderbar, der Status wird auch auf Offline gesetzt.

Wenn der User sich einloggt, wird er kurz auf die login.php weitergeleitet und dort soll der Status dann auf "Online" gesetzt werden.
Wenn ich auf die login.php weitergeleitet wurde und danach auf der login.php bleibe, ist und bleibt der Status auf "Online".
Wenn ich von der login.php aber wieder zur index.php gehe, dann wird der Status auf "0" gesetzt.

Code:
 $logverb=$cn->query("SELECT * FROM `benutzer` WHERE username = '$usernamed' AND passwort = '$passwortdb1'");
    $row = $logverb->fetch_assoc();
    if(!$row)
        {
       echo" <br /><div class='alert alert-danger' role='alert'>
       Benutzername und/oder Passwort waren falsch.</div>";
        }
    else
        {
        $username = array("name"=>$row["username"],"email"=>$row["email"]);
        $ins = $cn->query("UPDATE `benutzer` SET status='Online' WHERE username='".$username['name']."'");
        $_SESSION["user"] = $username;
        }

    $cn->close();
Theoretisch ist es 2mal der selbe Befehl. Der eine funktioniert, der andere nicht... ich kapiers nicht.
Mysqli gibt keinen error aus.
06/28/2016 21:07 False#11
Quote:
Originally Posted by .Barone View Post
Ich musste gerade etwas ziemlich komisches feststellen.
Beim Ausloggen wird der User auf die logout.php weitergeleitet mit folgendem inhalt:

Code:
$offline = $cn->query("UPDATE `benutzer` SET status='Offline' WHERE username='$username'");
session_destroy();
echo "<meta http-equiv='refresh' content='0, url=index.php'>";
Das klappt so wunderbar, der Status wird auch auf Offline gesetzt.

Wenn der User sich einloggt, wird er kurz auf die login.php weitergeleitet und dort soll der Status dann auf "Online" gesetzt werden.
Wenn ich auf die login.php weitergeleitet wurde und danach auf der login.php bleibe, ist und bleibt der Status auf "Online".
Wenn ich von der login.php aber wieder zur index.php gehe, dann wird der Status auf "0" gesetzt.

Code:
 $logverb=$cn->query("SELECT * FROM `benutzer` WHERE username = '$usernamed' AND passwort = '$passwortdb1'");
    $row = $logverb->fetch_assoc();
    if(!$row)
        {
       echo" <br /><div class='alert alert-danger' role='alert'>
       Benutzername und/oder Passwort waren falsch.</div>";
        }
    else
        {
        $username = array("name"=>$row["username"],"email"=>$row["email"]);
        $ins = $cn->query("UPDATE `benutzer` SET status='Online' WHERE username='".$username['name']."'");
        $_SESSION["user"] = $username;
        }

    $cn->close();
Theoretisch ist es 2mal der selbe Befehl. Der eine funktioniert, der andere nicht... ich kapiers nicht.
Mysqli gibt keinen error aus.
Vorabl empfehle ich dir mal nach SQL Injection zu googeln, den mit deinen Aktuellen SQLS könnte Jeder deine ganze Datenbank leeren bzw sich einfach ohne Passwort einloggen ;)

Wir das SQL überhaupt ausgeführt? (Wenn ja wäre es komisch, da wenn man sich ausgeloggt hat sollte nicht sofort ein Login SQL ausgeführt werden).
Wenn dieser nicht ausgeführt wird kann man natürlich auch nicht in das else kommen.
06/28/2016 21:19 .Barone#12
Bezüglich der SQL Injection bin ich mir nicht ganz sicher, wie ich vorgehen kann, um das "100%" zu schützen.
Die Variablen werden vorher durch folgendes gejagt:
Code:
$cn = new mysqli($servername,$db,$pw,$userdb);
$data = $cn->real_escape_string($data);
$data = htmlentities($data, ENT_QUOTES | ENT_HTML5, 'utf-8');
$return_str = str_replace( array('<','>',"'",'"',')','('), array('<','>','&apos;','&#x22;',')','(','&sem','&bso','&so','&bs','&eq'), $data );
$return_str = str_ireplace( '%3Cscript', '', $return_str );
$data = $return_str;

return $data;
Aber wenn ich das so richtig lese ist es sinnvoller auf prepared statements umzusteigen, da diese "100%" sql injection sicher sind? stimmt das?


Also, du scheinst etwas falsch verstanden zu haben. Bleiben wir einfach mal bei dem Einloggen und lassen das ausloggen weg, da funktionierts ja.

Das Login script funktioniert so wunderbar, die Session ist danach gesetzt und der User ist "eingeloggt", der Status von dem User ist aber nur "Online" solange er sich auf der login.php befindet, wird er weitergeleitet oder verlässt die login.php, so wird der Status direkt auf 0 gesetzt.
06/28/2016 22:25 False#13
Quote:
Originally Posted by .Barone View Post
Bezüglich der SQL Injection bin ich mir nicht ganz sicher, wie ich vorgehen kann, um das "100%" zu schützen.
Die Variablen werden vorher durch folgendes gejagt:
Code:
$cn = new mysqli($servername,$db,$pw,$userdb);
$data = $cn->real_escape_string($data);
$data = htmlentities($data, ENT_QUOTES | ENT_HTML5, 'utf-8');
$return_str = str_replace( array('<','>',"'",'"',')','('), array('<','>','&apos;','&#x22;',')','(','&sem','&bso','&so','&bs','&eq'), $data );
$return_str = str_ireplace( '%3Cscript', '', $return_str );
$data = $return_str;

return $data;
Aber wenn ich das so richtig lese ist es sinnvoller auf prepared statements umzusteigen, da diese "100%" sql injection sicher sind? stimmt das?


Also, du scheinst etwas falsch verstanden zu haben. Bleiben wir einfach mal bei dem Einloggen und lassen das ausloggen weg, da funktionierts ja.

Das Login script funktioniert so wunderbar, die Session ist danach gesetzt und der User ist "eingeloggt", der Status von dem User ist aber nur "Online" solange er sich auf der login.php befindet, wird er weitergeleitet oder verlässt die login.php, so wird der Status direkt auf 0 gesetzt.
Würde jetzt nicht umbedingt 100% sicher sein, eher so 99%.Würde generell auf die neuere Variante PDO wechseln, da es besser ist und mysqli in PHP7 deprecated ist.


Okay, dann sind wir ja ein Schritt weiter.
Da der Status ja nicht von selber auf Offline springen kann musst du das SQL irgendwo feuern.
Geh auf eine Seite wo das passiert und guck wieso das "OFFLINE SQL" gefeuert wird.
Wenn du dort nicht weiter kommst schick das komplette Script mal (Wenn includes drin sind die auch).
06/29/2016 11:52 .Barone#14
Okay, ich habe gerade festgestellt das ich niewieder, während ich ein script schreibe , mich unterbrechen lasse..
Das script, welches den status jedesmal auf 0 gesetzt hat, habe ich gefunden.
Jetzt wird der Status beim einloggen aber nicht mehr auf 'Online' gesetzt.

Code:
$stmt=$cn->prepare("UPDATE `benutzer` SET status='Online' WHERE username=:username");
    $stmt->bindParam(':username',$result['name'],PDO::PARAM_STR);
    $stmt->execute();
06/29/2016 17:34 #Metho#15
Quote:
Originally Posted by .ƒaℓsє. View Post
Würde jetzt nicht umbedingt 100% sicher sein, eher so 99%.Würde generell auf die neuere Variante PDO wechseln, da es besser ist und mysqli in PHP7 deprecated ist.


Okay, dann sind wir ja ein Schritt weiter.
Da der Status ja nicht von selber auf Offline springen kann musst du das SQL irgendwo feuern.
Geh auf eine Seite wo das passiert und guck wieso das "OFFLINE SQL" gefeuert wird.
Wenn du dort nicht weiter kommst schick das komplette Script mal (Wenn includes drin sind die auch).
Woher hast du den das aufgeschnappt. PDO und MySQLi können fast gleich viel, nur ist das eine spezifisch und schnell und das andere generell und allgemein gehalten, aber prepared Statements können beide und es wäre mir ebenfalls neu, dass dies in PHP 7 veraltet sein soll... ^^