Online Users-System [Wie viele Personen verwenden das Programm]

    • VB.NET

    Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von J.Herbrich.

      Online Users-System [Wie viele Personen verwenden das Programm]

      Hi Liebe Community,

      Ich möchte Euch hier mal eine Variante präsentieren, wie man sich die Anzahl der Online User anzeigen lassen kann.
      Nach Fertigstellung bekommt man dann ein String (bzw. Integer), welcher die aktuelle Online Users Anzahl beinhaltet.

      Benötigt:
      • Server mit MySQL und phpMyAdmin

      -----------------------------------------------------------------------------------------------------------------------------------------------
      1) Server-Seite
      Spoiler anzeigen

      Schritt 1:
      • Loggt euch bei phpMyAdmin ein und klickt auf "Datenbanken":



      Schritt 2:
      • Als Datenbankname "usersdb" eintragen, anschließend auf "Anlegen" klicken:



      Schritt 3:
      • Nach erfolgreicher Erstellung der Datenbank klickt Ihr die zuvor erstellte Datenbank im linken Auswahlfenster aus:


      • Nun wählt Ihr oben den SQL-Tab aus:


      und fügt folgenden SQL-Befehl ein (anschließend mit OK bestätigen):

      SQL-Abfrage

      1. CREATE TABLE `usersdb`.`users` (
      2. `IP` VARCHAR( 255 ) NOT NULL ,
      3. `lastPing` INT( 10 ) NOT NULL ,
      4. UNIQUE (
      5. `IP`
      6. )
      7. ) ENGINE = InnoDB;


      Schritt 4:
      • Erstellt eine Textdatei mit folgendem Inhalt (bitte Benutzernamen und Passwort entsprechend editieren):

      PHP-Quellcode

      1. <?php
      2. $host = "localhost";
      3. $user = "root";
      4. $pass = "x01";
      5. $db = "usersdb";
      6. mysql_connect($host,$user,$pass);
      7. mysql_select_db($db);
      8. $ip = getenv("REMOTE_ADDR") ;
      9. $time = time();
      10. $query = "REPLACE INTO users (IP, lastPing)
      11. VALUES ('$ip', '$time' )";
      12. mysql_query($query);
      13. $query = "SELECT IP FROM users WHERE lastPing >= $time - 30";
      14. $result = mysql_query($query);
      15. echo mysql_num_rows($result);
      16. ?>

      und benennt die Endung von .txt in .php um.

      Nun platziert diese Datei auf euren Server und merkt euch den Link (brauchen ihn gleich für die VB-Seite)


      2) VB-Seite
      Spoiler anzeigen

      Schritt 5:
      • Zieht einen Timer auf eure Form und setzt den Interval auf 25000 (≙ 25 sek.)
      • Zieht ein Label auf eure Form
      • Öffnet das Tick-Event des Timers (Doppelklick unten auf den Timer) und fügt dort folgenden Code ein:

      VB.NET-Quellcode

      1. Label1.Text = New System.Net.WebClient().DownloadString("Hier den Link der erstellten php-Datei einfügen !!!")

      Wenn dieser String nach 30 Sekunden nicht erneut heruntergeladen wird, wird der User automatisch nicht mehr berücksichtigt.


      Hoffe es war soweit ausführlich genug :D

      Verschoben. ~Thunderbolt

      Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „TRiViUM“ ()

      Könnte nur ein Problem mit dem Datenschutz werden, weil du die IP-Adresse speicherst.
      Wenn dieser String nach 30 Sekunden nicht erneut heruntergeladen wird, wird der User (IP-Adresse) automatisch aus der Datenbank gelöscht.
      Wo passiert das? In deinem Code sehe ich dazu nichts.
      @slice
      Das mit dem Datenschutz kann man "einfach" lösen, indem man angibt, dass die IP-Adresse eben nur für diesen Zweck gennutzt wird.
      Ebenfalls wird die IP-Adresse nicht weitergegeben etc...
      Wüsste auf die Schnelle nicht, wie man es sonst lösen könnte, wenn keine IP...

      Zum String, der Satz hat sich auf den VB-Code bezogen:

      VB.NET-Quellcode

      1. Label1.Text = New System.Net.WebClient().DownloadString("Hier den Link der erstellten php-Datei einfügen !!!")

      Der Code soll in dem Tick-Event des Timers stehen und wird somit alle 25 Sekunden ausgelöst, wenn man es wie beschrieben befolgt.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

      Du schreibst das die IP gelöscht wird, das passiert aber nirgends, der entsprechende Eintrag wird nur bei deiner Abfrage nicht mehr mit einbezogen.

      Edit:
      Zum Datenschutz:
      Es gäbe da eine andere Möglichkeit: Eine GUID im Client generieren und unter AppData abspeichern und diese als Identifier an den Server übergeben.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „slice“ ()

      slice schrieb:

      Du schreibst das die IP gelöscht wird, das passiert aber nirgends, der entsprechende Eintrag wird nur bei deiner Abfrage nicht mehr mit einbezogen.

      Äh ja, so war's auch gemeint, hab mich falsch ausgedrückt, habs oben editiert.

      Gäbe es denn eine Möglichkeit, die Tabelle automatisch löschen zu lassen? z.b. 1 x pro Tag?
      Zunächst das mit den IP-Adressen.
      mysql_query: Mittlerweile gibt es mysqli für sowas zum Benutzen und außerdem solltest Du lieber auf Prepared Statements setzen, denn die sind einfach besser in der Performance und zudem gegen einen Typ von Injections sicher.

      Ich weiß nicht, inwiefern man da an der Umgebungsvariable rumspielen kann, aber wenn Du z. B. das mit der GUID in Erwägung ziehst, dann sei vor bspw. a5a55134-e181-4b82-9fd2-1331e715fc0a; DROP DATABASE usersdb; gewarnt und validiere die Eingaben. ;)

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      Trade schrieb:

      lieber auf Prepared Statements setzen

      Was genau meinst du damit?

      Auch wenn es für den Einen oder Anderen simpel erscheint, habe ich mir das mühselig zusammengebaut.
      Bin froh, dass es überhaupt funktioniert hatte :)

      Naja der Datenschutz-Punkt ist mittlerweile sowieso so eine Sache...
      Und das mit dem mysqli müsste ich mich auch mal drüber Informieren.
      Habe sonst so gut wie nix damit am Hut.

      Wurde der Thread aufgrund des Datenschutzes gemeldet? 8|
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Wenn Du einen Parameter über die URL an das PHP-Script übergibst und dann dieser in die SQL-Query kommt bzw. dort verwendet wird, dann kann dieser, wenn er modifiziert ist SQL-Befehle ausführen, d. h. ich kann zum Beispiel ;DROP DATABASE usersdb; an den Parameter anhängen und die Datenbank ist weg. Daher ist es wichtig seine Daten zu validieren bzw. die Parameter zu escapen. Afaik machen das Prepared Statements automatisch, falls Du diese aber aus irgendeinem Grund nicht nutzen willst oder auf Nummer sicher gehen willst, dann schau Dir mal mysqli_real_escape_string an.
      Grade wenn Du z. B. an das Script eine GUID übergibst, die der Nutzer lokal ändern kann, weil sie z. B. in einer Textdatei liegt, dann ist das sehr wichtig.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      @Trade
      Okay.
      Naja warum denn nicht die prepared Statements nutzen, wenns automatisch geht.
      Das mit den GUID sieht mir nach etwas unsicher, und somit auch nach mehr Arbeit aus...
      Ich würde mich freuen, wenn du dich da evtl. ein wenig mit einbringen könntest, da ich, wie gesagt, noch nicht so erfahren bin, was das angeht.

      Um dem Thread auch eine vollendete Lösung zu verpassen.
      Von mir aus, Du kannst mir mal eine PN senden, ich werde dann, wenn ich mal zwischendrin Zeit habe, antworten. ;)
      Aber dann BTT.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Hi,

      hatte auch eine PN bekommen mit einer Anfrage zu möglichen Lösungswegen.
      Als ich das PHP-Skript gesehen hatte, dachte ich mir zuerst nur, wie man es schafft, in so wenig Zeilen Code so viele Fehler einzubauen. Ist mir unbegreifbar, wie das von der Moderation durchgewunken werden konnte - hinsichtlich Tutorial-Niveau will ich da von "oberer Stelle" aber dann wirklich keinen mehr meckern hören ... Und andere Leute die's nicht besser wissen, denken ja, dass das was hier im Tutorials-Forum steht, richtig sein muss..

      PHP-Quellcode

      1. <?php
      2. /**
      3. * - Bitte in extra config.php oder ähnliches auslagern
      4. * - Mit define deklarieren
      5. */
      6. $host = "localhost";
      7. $user = "root";
      8. $pass = "x01";
      9. $db = "usersdb";
      10. /**
      11. * - Bitte nicht die ranzigen mysql_* Funktionen verwenden
      12. * - Woher weiß ich, dass die Verbindung zur DB erfolgreich aufgebaut wurde?
      13. * - Woher weiß ich, dass die Datenbank richtig ausgewählt wurde?
      14. */
      15. mysql_connect($host,$user,$pass);
      16. mysql_select_db($db);
      17. /**
      18. * - Bitte das $_SERVER-Array verwenden
      19. */
      20. $ip = getenv("REMOTE_ADDR") ;
      21. /**
      22. * - Wozu die extra Variable $time, wenn du hier weder Validierung noch Maskierung vornehmen musst?
      23. */
      24. $time = time();
      25. /**
      26. * - Datenbank-, Tabellen- und Spaltennamen bitte immer in Backticks setzen!
      27. */
      28. $query = "REPLACE INTO users (IP, lastPing) VALUES ('$ip', '$time' )";
      29. /**
      30. * - Wieso wird nicht geprüft, ob das Statement erfolgreich ausgeführt wurde?
      31. */
      32. mysql_query($query);
      33. /**
      34. * - Auch hier wieder die Backticks
      35. */
      36. $query = "SELECT IP FROM users WHERE lastPing >= $time - 30";
      37. $result = mysql_query($query);
      38. echo mysql_num_rows($result);
      39. ?>


      Eine Kollation für die anzulegende MySQL-Tabelle wird auch nicht gewählt. Und wieso InnoDB? Wieso nicht MyISAM? Oder hast du das random entschieden?

      (In meinem Fall erledigt dies mein Raspberry Pi)

      Cool story, bro. Aber was tut das zur Sache?

      Und was soll das überhaupt, hier eine "Anleitung" zu posten, wenn du -wie du mir ja geschrieben hast- das Ganze eh nur aus anderen Foren hast?

      Zu deinen Fragen:
      - ob du es mit GUID oder IP machst, ist vollkommen egal und macht nur datenschutzrechtlich nen Unterschied.
      - Die GUID könnte theoretisch ein Hash aus dem Hostnamen der lokalen Maschine und dem aktuellen Timestamp zumr Zeitpunkt der "Installation" deiner Anwendung sein (oder wenn sie das erste mal geöffnet wurde). Damit wäre die Eindeutigkeit relativ sichergestellt.
      - Ja, man kann Datensätze nach einer bestimmten Zeit leeren - löschen ist wieder was anderes (DROP TABLE > TRUNCATE TABLE > DELETE FROM).
      Für dich kurz erklärt:
      - DROP TABLE -> Tabelle in einer Datenbank löschen -> die Tabelle gibt's dann nicht mehr
      - TRUNCATE TABLE -> Alle Daten(sätze) einer Tabelle löschen (die Tabelle wird geleert) - Struktur der Tabelle bleibt bestehen, sie enthält nur keine Daten mehr
      - DELETE FROM - Bestimmte Datensätze einer Tabelle löschen (kann ohne Angabe von Kriterien die man in der WHERE-Klausel angibt von der Funktionalität gleichbedeutend sein mit TRUNCATE -> DELETE macht somit fast nur mit einer WHERE-Klausel Sinn).

      Zum Leeren der Tabelle an sich - hierfür gibt's mehrere Möglichkeiten:
      - Gut wäre ein Cronjob, der so eingestellt ist, dass er jeden Tag um sagen wir 14 Uhr den entsprechenden Befehl ausführt.
      - Theoretisch kannst du auch bei jedem Aufruf der PHP-Datei prüfen, und wenn Anzahl Datensätze größer als 2.000 ist, die ältesten davon löschen
      - Eine Zeitstempel-Spalte in der Tabelle anlegen (on_update_current_timestamp ggf. ausschalten) und dementsprechend alle Datensätze die älter sind als x Tage löschen.


      Link :thumbup:
      Hello World
      Ich habe den php-Code mal mit mysqli umgesetzt, da mysql() deprecated ist.

      Spoiler anzeigen

      PHP-Quellcode

      1. <?php
      2. $host = "localhost";
      3. $dbname = "usersdb";
      4. $user = "root";
      5. $pass = "passwort";
      6. $verbindung = mysqli_connect($host, $user, $pass, $dbname);
      7. if(!$verbindung)
      8. {
      9. echo("Verbindungsfehler: ".mysqli_connect_error());
      10. }
      11. $ip = getenv("REMOTE_ADDR") ;
      12. $time = time();
      13. $query = ("REPLACE INTO users (IP, lastPing) VALUES ('$ip', '$time' )");
      14. $machen = mysqli_query($verbindung, $query);
      15. $query = ("SELECT IP FROM users WHERE lastPing >= $time - 30");
      16. $result = mysqli_query($verbindung, $query);
      17. echo mysqli_num_rows($result);
      18. ?>



      Ich habe die Variablen im php-Skript ein bisschen verändert, aber das Grundprinzip und die SQL Befehle sind gleichgeblieben. Sollte alles klappen.
      Die beste maschinelle Übersetzung der Welt - DeepL Übersetzer
      Alle Zitate, die ich seit dem 1.9.2017 übersetzt habe, wurden vollautomatisch mit DeepL übersetzt.



      Hier das ganze dann nochmal mit Prepared Statements und mysqli im Objektorientierten Stil. Hoffe ich habe nichts vergessen.

      PHP-Quellcode

      1. <?php
      2. // Zugang zur Datenbank
      3. define("DB_HOST", "localhost");
      4. define("DB_USER", "root");
      5. define("DB_PASS", "");
      6. define("DB_NAME", "your_product");
      7. // GUID abfragen
      8. if(!isset($_GET["guid"]))
      9. {
      10. print("No guid given.");
      11. exit;
      12. }
      13. // Verbindung zur Datenbank herstellen
      14. $handle = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
      15. if($handle->connect_error)
      16. {
      17. print("Connection failed.");
      18. exit;
      19. }
      20. // Prepared Statement erstellen
      21. $statement = $handle->prepare("REPLACE INTO users (guid, lastPing) VALUES (?, ?)");
      22. if(!$statement)
      23. {
      24. print("Preparation failed.");
      25. exit;
      26. }
      27. // GUID escapen.
      28. $guid = $handle->real_escape_string($_GET["guid"]);
      29. // Zeit speichern
      30. $time = time();
      31. // Statement binden
      32. if(!$statement->bind_param("si", $guid, $time))
      33. {
      34. print("Bind failed.");
      35. exit;
      36. }
      37. // Statement ausführen
      38. if(!$statement->execute())
      39. {
      40. print("Execution failed.");
      41. exit;
      42. }
      43. else
      44. $statement->close();
      45. // Statement für die Abfrage der Anzahl
      46. $statement = $handle->prepare("SELECT COUNT(guid) FROM users WHERE lastPing >= ?");
      47. if(!$statement)
      48. {
      49. print("Preparation failed.");
      50. exit;
      51. }
      52. // Zeit minus 30
      53. $time = $time - 30;
      54. // Statement binden
      55. if(!$statement->bind_param("i", $time))
      56. {
      57. print("Bind param failed.");
      58. exit;
      59. }
      60. // Statement ausführen
      61. if(!$statement->execute())
      62. {
      63. print("Execution failed.");
      64. exit;
      65. }
      66. if(!$statement->bind_result($result))
      67. {
      68. print("Bind result failed.");
      69. exit;
      70. }
      71. if(!$statement->fetch())
      72. {
      73. print("Fetch result failed.");
      74. exit;
      75. }
      76. else
      77. $statement->close();
      78. // Ergebnis ausgeben.
      79. print($result);
      80. // Verbindung schließen
      81. $handle->close();
      82. ?>
      Gepriesen sei das Rauhe Haus,

      Also wo fange ich an. Zuerst mal kann eine IP von mehreren Usern verwendet werden (NAT). Hinzu kommt noch das man alle 24 Stunden (Zwangstrennung) eh eine neue IP bekommt. Das macht es schon mal nicht wirklich einfach die IP als User Kennung zu verwenden.

      Besser währe wenn man einfach eine GUID nimmt die auf jeden Fall einzigartig ist, und diese dann irgendwo online registriert. Dann kann man einfach die Zahl der registrierten GUIDs ausgeben lassen und fertig.

      Weiter kann man dann alle x minuten oder sekunden die Guid an ein Webdienst oder Server (Raw TCP / Eigenes Protokoll) übermitteln und sieht wie viele User (die Online sind^^) das Programm gerade verwenden.

      Sollte es nur ums Ego gehen, ist es technisch wesendlich einfacher den Download Button der Homepage mit einen Google Analytics oder Facebook Analytics Event zu tracken und so sieht man auf einen wunderschönen Dashboard mit Diagram wann wie viele User dein Programm heruntergeladen haben.

      LG. J Herbrich