Online users med PHP og MySQL

Tags:    php
Skrevet af Bruger #1 @ 05.06.2003
Der er efterhånden flere personer, der har spurgt mig hvordan jeg har lavet funktionen med Online brugere her på Udvikleren.dk, så nu må det være på tide at skrive en artikel om det :). Da jeg selv stod og skulle lave sådan et system, var min største undren nok hvordan man kunne se at en bruger ikke var online mere. Hemmeligheden er, at det kan man ikke :). Der findes JavaScript, der muligvis kan aktivere noget PHP kode, når en bruger surfer videre, men det er på mange måder ikke en optimal løsning (jeg har dog aldrig forsøgt mig med den, skal det så siges). Så hvad gør vi så? Vi lader da brugerne gøre arbejdet for os! Det fungerer således:

Hver gang en bruger kigger på en side, registrerer vi brugeren ud fra IP adressen, med det nuværende tidspunkt. Næste gang denne bruger loader en side, ligger IP adressen der, og så sætter vi bare tidspunktet igen. På den måde har vi altså hele tiden det tidspunkt hvor en bruger (eller besøgende om man vil), sidst har været “aktiv”. Nu forestiller vi os så at en bruger kigger på en side, og derefter forlader sitet. Det seneste tidspunkt er sat, men vi får ikke af vide at brugeren smutter, og kan derfor ikke slette personen fra databasen. Det er så her det geniale kommer ind, for hver gang en bruger registreres, så kigger vi da lige om der er nogen der ikke har været aktive i de sidste X minutter, og sletter dem. På den måde er systemet altid opdateret – en bruger kan sagtens ligge i databasen i flere dage, og dermed være registeret online, hvis der ingen besøgende er, men lige så snart der kommer en besøgende, så er systemet opdateret, og vil derfor altid fremstå sådan. Jeg håber at min forklaring var til at forstå, men hvis ikke, så giv ikke op endnu. Nu kommer der lidt db-struktur og lidt kode, som naturligvis også bliver forklaret :)

Databasestrukturen



Vi får brug for en enkel tabel i vores database, der holder styr på de besøgende der registreres. Her følger et dump af tabellen, klar til at smide igennem fx PHPMyAdmin, samt en forklaring:

Fold kodeboks ind/udKode 


Lad os starte fra en ende af, med vores ID. Det er fortløbende, og i øvrigt tabellens primær nøgle – det er der ikke så meget i. De næste 2 felter tjener lidt det samme formål, og har man lyst til at skrive lidt mere kode, kan de godt slåes sammen. I denne artikel bruger jeg dog begge to, da jeg selv synes at det er lettere. Den første, lastseen_stamp, er et såkaldt timestamp, der gemmes som et 10 eller 11-cifret tal – et timestamp er god til at lave beregninger med, og det får vi brug for når vi fx skal slette inaktive besøgende. Næste hedder bare lastseen, og er af typen time – time er rigtig god til at vise frem for besøgende, da det, i modsætning til et timestamp, er et tidspunkt angivet som mennesker også ville angive det (fx 14:34:43 – altså time, minutter og sekunder). Man kan naturligvis skrive en funktion der kan konvertere et timestamp til en time-lignende streng, men det tager vi ikke med denne gang.

IP feltet skal indeholde den besøgendes IP adresse, og hostmask personens hostmask (en IP adresse består af 4 tal, adskilt med et punktum, hvorimod en hostmask som regel er tekst – jeg har fx kasper.tsw.dk som hostmask). Det kan være sjovt at have personens hostmask, da den tit siger noget om hvor en bruger kommer fra, og derudover er den som regel lidt “pænere” at vise end en IP adresse. Derudover gemmer vi adressen som personen kigger på, samt en eventuel titel. Dette gør jeg fx på Udvikleren.dk, da en titel som regel siger lidt mere end adressen gør, men det er naturligvis ikke et krav. Lad os komme i gang med at skrive lidt kode!

At registrere besøgende



Det første vores system skal kunne, er at registrere vores besøgende. Dette gøres ved at include en fil der gør netop dette, på alle de sider der skal registrere online besøgende (og hvis dette tal skal være præcist, bør det være på alle offentlige sider). Lav en fil og kald den fx for register_onlineusers.php. Indholdet skal være noget i stil med følgende:

Fold kodeboks ind/udKode 


Det var så lige ca. 30 linier kode, og en masse kommentarer :). Jeg vælger ellers normalt at kommentere al kode efter eksemplet, men denne gang virkede det faktisk mere overskueligt at gøre det sådan her. Jeg håber at det er til at forstå!

At bruge vores data



Hvis du ellers har gjort det rigtigt, så skulle du nu gerne være i stand til at registrere info om dine brugere. Du kan teste det ved at hoppe ind på din side, og så kigge i databasen om du ikke er dukket op :). Nu vil jeg kort vise hvordan vi kan hive info ud fra databasen – uden det er det hele jo ikke meget værd. Jeg viser et mindre eksempel på hvordan du hiver antallet af online brugere ud, samt et lidt større, hvor du kan udskrive en simpel liste over de online brugere.

Fold kodeboks ind/udKode 


Egentlig rimeligt simpel kode. I de første par linier, laver vi en hurtig forespørgsel. Vi bruger COUNT til let og hurtigt at få antallet af rækker, og udskriver det derefter. Så simpelt er det :)

Derefter laver vi et select query, hiver de relevante ting ud, og sorterer efter hvornår personen sidst er set. Der udskrives en simpel tekststreng med de data vi hiver ud, for hver person i databasen.

Over & out



Det var alt for denne gang. Håber at du kan bruge artiklen til noget, og har fået dig et fint online-users system til din hjemmeside :)


Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (38)

User
Bruger #714 @ 05.06.03 17:46
Den database struktur du viser i starten og den du bruger i koden er ikke den samme, så hvis man ikke ved hvordan sådan en opgave her skal løses, ved jeg ikke om artiklen skaber mere kaos end forståelse, ellers fin artikel
User
Bruger #1 @ 05.06.03 18:25
Det er rettet nu. Jeg har kode og database struktur fra mit eget site, kasper.tsw.dk (der har det her fra udvikleren.dk), hvor jeg bruger de feltnavne der stod i koden. Jeg ændrede på db-strukturen for at gøre den mere forståelig, men glemte desværre at rette det alle steder i koden til denne artikel. Det skulle gerne være fixet nu, ellers må i lige sige til :)
User
Bruger #2330 @ 06.06.03 19:50
Jeg fik en Parse error: parse error, unexpected T_STRING in /disk2/users/laslego/register_online.php on line 8
da jeg kørte det første script
User
Bruger #3271 @ 08.06.03 16:47
Den kan jeg godt nok ikke få til at virke... jeg har ændret linie 8, og tabelnavnene... der kommer bare hvid side...
Jeg inkluderer det i min "top.php"
User
Bruger #2397 @ 10.06.03 13:36
Jeg vil nok anbefale at bruge mysql_num_rows funktionen istedet for at lave endnu et query. Ikke alene udfører man 1 query mindre, men man undgår også uoverenstemmelser mellem antallet of "online" brugere og antallet af brugere på den udskrevne liste.

Det er ikke utænkeligt at en ny bruger kommer forbi sitet mellem de 2 queries og listen derfor indeholder 1 bruger mere, eller mindre, end angivet.
User
Bruger #3143 @ 10.06.03 20:11
Du har to kolonner i tabellen for tiden. Du skriver godt nok:

"Man kan naturligvis skrive en funktion der kan konvertere et timestamp til en time-lignende streng, men det tager vi ikke med denne gang."

Men denne funktion vil jeg nu lige nævne:

$tid = date("H:i:s",$r["lastseen_stamp"]);

Den kan bruges i stedet for '$tid = $r["lastseen"];' i sidste kodeeksempel, og så behøver man ikke at gemme det læselige tidsformat.
User
Bruger #1 @ 12.06.03 19:43
Erik: Det var ikke min mening at de to skulle bruges sammen, nærmere som to eksempler på hvordan dataene kunne bruges. Jeg ville bestemt også bruge mysql_num_rows, eller evt. tælle antallet af felter med COUNT direkte i forespørgslen og hive det ud som værdi :)

Jesper: Mange tak for det :)
User
Bruger #4071 @ 13.06.03 01:28
Nogen der har lagt det ned i 3 filer som jeg kan downloade fra jer? for mig virker ikk... msn sune17@msn.com tak
User
Bruger #1454 @ 19.06.03 18:23
hmm.. kasper, det virker jo ikke! din hat.. :/
Den første del af koden skriver ikke til databasen og i del to skal man lige huske at “ ikke er det samme som ", så det skal altså lige ændres..

Kasper, jeg håber du kan/gider lave det..
User
Bruger #3530 @ 19.06.03 18:43
Hmm det kan godt være det bare er mig men hvorfor er det lige at du, KasperTSW, har sat @ foran nogle af mysql funktionerne ?
User
Bruger #2397 @ 23.06.03 14:52
Xyber: @ anvendes foran udtryk (eng: expression) som kan komme med en fejl man ikke ønsker at vise brugeren.

Skulle et SQL query derfor fejle skrives der ikke nogen fejlbesked til brugeren. Det er god programmeringsskik, idet fejlbeskeder fra SQL queries indeholder en masse informationer om databasen, som man ikke ønsker at en potentiel hacker får at se.
User
Bruger #3572 @ 26.06.03 10:58
jeg har ventet på noget i denne her stil, så super! Jeg kan bare ikke få lortet til at virke.. den sidste klump kode... hvordan skal den fingereres så den virker?
User
Bruger #3143 @ 29.06.03 16:44
" fejlbeskeder fra SQL queries indeholder en masse informationer om databasen, som man ikke ønsker at en potentiel hacker får at se."

Det er nok derfor der ikke vises sql-fejl automatisk uden at man bruger mysql_error(). Så det er ligegyldigt om man bruger @ eller ej.
User
Bruger #3530 @ 15.07.03 21:56
enig Jesper
User
Bruger #3530 @ 09.09.03 16:06
Jeg synes ikke det her lever op til udvikler niveau...Koden er ikke-komplet og så skal man nøjes med en linjes forklaring per 4 linjer kode. Måske kan inkarnerede PHP udviklere se logik i det her men ikke jeg.
User
Bruger #3530 @ 14.09.03 22:18
ovenstående kommentar er IKKE jeg gentager _IKKE_ fra mig. En "ven" lånte min computer mens jeg var væk og skrev den i mit navn. Vær rar ikke at dømme mig på det !

Jeg mener selv at artiklen er en af de MEGET bedre artikler KasperTSW har skrevet. Så bare: Keep up the good work TSW!
User
Bruger #2034 @ 05.10.03 10:52
En udemærket artikel, der giver et godt og hurtigt inblik i, hvordan det i princippet kan gøres.
User
Bruger #3530 @ 09.10.03 21:14
Du har glemt alt for mange ting bla: url=pageurl, $title=er der ikke osv. :(
User
Bruger #3353 @ 28.10.03 21:35
ellers en rigtig god artikel (eller endnu en) jeg har ikke prøvet den endnu men jeg håber at du har fået rettet nogle af de fejl de har nævnt!
User
Bruger #4758 @ 31.12.03 23:28
Det er dog den mest fejlfuldte Artikel jeg nogen sinde har set...
Utroligt at du over hovdet kan have sådan en liggende.. den er langt under jeres level..
SKUFFENDE.. og btw. jeg har rettet alt men får stadig probs med mySQL_fetch_Array.. den giver fejl hjælp mig..
User
Bruger #1 @ 09.01.04 23:01
Jeg er ked af at nogen af jer ikke bryder jer om artiklen, fordi der ikke er en komplet source listing, men det var altså ikke pointen med denne artikel. Den er skrevet i håb om at folk vil læse den, og lære noget af den - ikke i håb om at folk vil undlade at læse den, scrolle ned i bunden, og copy/paste en fuldt fungerende source kode til deres site. Dem der gerne vil det sidste, kan passende finde og downloade et af de mange færdige scripts der findes rundt omkring på nettet. Jeg har muligvis glemt at skrive det, men denne artikel er ikke umiddelbart rettet mod dem der aldrig har arbejdet med PHP og/eller MySQL før. Der findes gode begynder artikler her på sitet, som man helt sikkert bør læse før denne artikel, hvis man ikke har det store kendskab til emnet. Håber at nogen har fået glæde af artiklen alligevel :)
User
Bruger #3951 @ 05.02.04 22:52
Hvad med en DB-connection, for det kan jeg godtnok ikke finde nogen steder???
User
Bruger #5426 @ 29.03.04 14:40
Jeg synes det var en okay artikel, selvom der skulle ændres på en del før den virkede... men jeg fik det til at lykkes... hvis i vil vide nærmere om hvordan så skriv til mig på emil@bjerglundpedersen.dk
User
Bruger #4265 @ 12.04.04 17:56
Jeg kan godt nok heller ikke se jeres klager, jeg rodet med koden i meget kort tid, og så virkede det. Og jeg er da enig med Kasper, at det ikke er en copy'n'paste artikel, men faktisk en artikel man lærer en del af (kan jeg udtale mig om!)

Michael: Jeg så at du manglede en connection, og jeg har en du kan bruge hvis du stadig mangler den:
---------------
$connection = mysql_connect("Server", "Brugernavn", "Password");
mysql_select_db("Database-navn", $connection);
---------------

- Pelle Ravn
User
Bruger #4265 @ 17.05.04 00:12
the-gEeK: Du siger du har problemer med mySQL_fetch_Array, og jeg gætter på at det er når du vil se hvem der har været online.

Prøv at rette:
$getusers = mysql_query("select IP, hostmask, url, tid, title from onlineusers order by last desc");
til:
$getusers = mysql_query("select IP, hostmask, pageurl, lastseen, pagetitle from onlineusers order by lastseen desc");

- Pelle Ravn
User
Bruger #8217 @ 30.09.05 22:52
hvis man ellers selv kan oprette databasen virker denne kode fint.
<?
//thanks to Joseph Miller


include("dbinfo.inc.php");


//-div VARiable -----------
// Variabler der skal bruges
// Vi starter med at finde IP adressen for brugeren
// Denne kode er testet på flere sites, og i øvrigt taget fra PHP’s online dokumentation
$IP = $_SERVER['REMOTE_ADDR'];
$FIP = $_SERVER['HTTP_X_FORWARDED_FOR']; //Vi finder IPen hvis brugeren har brugt en ikke-anonym proxy server

//Vi checker så om det lykkedes. Gjorde det det erstatter vi den direkte fundne IP med den vi fandt igennem proxy'en
if (($FIP != "") && ($FIP != "unknown")) $IP = $FIP;
$IP = explode(",", $IP);
$IP = $IP[0];

// Vi finder brugerens hostmask, ud fra IP adressen
$hostmask = gethostbyaddr($IP);

// Vi bruger time() til at få et slags timestamp for lige nu
// Det er antallet af sekunder siden 1. januar 1970 (UNIX epoch)
$timenow = time();
// Vi sætter deletetime til 10 minutter før “lige nu” :)
$deletetime = $timenow-(600);
// Vi finder adressen på den nuværende side
$onlineurl = "http://".$_SERVER[HTTP_HOST].$_SERVER[REQUEST_URI];

// Vi får lige et rigtigt menneskeligt tidspunkt, til at smide i databasen
// Til det bruger vi date, med en parameter der fortæller hvilket format det skal være i
$tidnu = date("H:i:s");

//------------------------------------------

mysql_connect(localhost,$username,$password);
@mysql_select_db($database) or die( "Unable to select database");

// Vi sletter brugere der ikke har været online de sidste $deletetime
// dvs. 10 minutter (600 sekunder / 60)
$query = "DELETE FROM onlineusers WHERE lastseen_stamp < '$deletetime'";
$result=mysql_query($query);


// Vi tjekker, ud fra IP adressen, om brugeren allerede er i tabellen
$query = "SELECT id FROM onlineusers WHERE ip LIKE '$IP'";
$tjek=mysql_query($query);
if(mysql_num_rows($tjek) == 0) {
// Brugeren var der ikke, vi indsætter “ham” lige
$query = "INSERT INTO onlineusers (ip, lastseen_stamp, url, title, lastseen, hostmask) values
('$IP','$timenow', '$onlineurl','$title','$tidnu','$hostmask')";
$result2=mysql_query($query);
} else {
// Brugeren var der skam allerede, så vi opdaterer “hans” tid data
// samt sideadresse, titel
$query = "UPDATE onlineusers SET lastseen_stamp='$timenow', url='$onlineurl',
title='$title', lastseen='$tidnu' WHERE ip LIKE '$IP'";
$resultc=mysql_query($query);
}


mysql_close();

//------------------------------------------
User
Bruger #8217 @ 01.10.05 01:40
Iøvrigt lige den artikel jeg søgte så rigtig mange tak.
User
Bruger #8306 @ 16.10.05 22:26
Den er okay - Men kan ikke få mit til at virke http://www.nielas.frac.dk/test/Online/register_onlineusers.php - Nogen der ved hvad jeg skal gøre
User
Bruger #5319 @ 05.06.06 22:01
Synes det er en helt okay artikel...
Også fint at det ikke er et "template" så man selv kan opbygge koden ved hjælp af artiklen, men stadig selv lære noget nyt
User
Bruger #8985 @ 26.07.06 01:44
Linie 8 mangler en "kommentar-start" (//) ellers får man en fejl :) God artikel
User
Bruger #9674 @ 27.07.06 20:38
Syntes faktisk det er en gangske udemærket artikkel... Den er nem at forstå, dog med lidt kendskab til PHP og MySQL først...

Jeg fik den til at virke med det samme bare ved selv at rette koden igennem... SO stop BITCHING... heh...

Men burde nok rettes til folk uden så meget kendskab til sproget i forvejen...
User
Bruger #5903 @ 17.03.07 13:50
Super fed artikel!

Har længe tænkt over hvordan jeg skulle få lavet noget ordentligt.

Efter at ha rodet i lidt tid så jeg da endelig hva fejlen var :P
Fold kodeboks ind/udKode 

skal rettes til:
Fold kodeboks ind/udKode 

Og nu dur det jubiii :D
User
Bruger #11220 @ 01.10.07 19:52
er jeg den eneste der ikke kan finde hvor man skal skrive sine mysql oplysninger

altsår adgangen til databasen
User
Bruger #13239 @ 31.01.08 22:11
Pen artikel, men brug ikke LOCK TABLES

Kommenter ut med //
Fold kodeboks ind/udKode 

User
Bruger #13239 @ 31.01.08 22:14
kristian, brug:

Fold kodeboks ind/udKode 
User
Bruger #8199 @ 08.11.08 10:21
Hmmm super artikel, men hos mig gider den ikke at opdatere tabellen. Der står hele tiden 0 online gæster. Hvis jeg selv indtaster data via phpmyadmin så kan jeg godt få den til at sige 1 online, men den gør det ikke selv :-/

Hvad kan jeg gøre? Jeg har kigget koderne igennem, jeg kan ikke finde rettelser :-/
User
Bruger #10410 @ 04.04.10 23:48
Kermit: ved godt at det er 2 år for sent, men havde du husket at angive rigtige oplysninger ved dit connect til din database?
User
Bruger #8985 @ 08.06.11 01:17
Hvorfor skal man ikke bruge LOCK TABLES? Gjorde det det ikke hurtigere?
Du skal være logget ind for at skrive en kommentar.
t