Hello,
Das ganze Script sieht so aus:
Das Script ist nicht sehr sauber geschrieben. Abgesehen davon, bedeutet eine IP nicht 'ein Client', denn manche Clients wechseln mit jedem Request ihre IP, aber das wusstest Du sicherlich schon.
<?php
// Konfiguration
$besucher_online_konfiguration = array (
// in welcher Datei soll es gespeichert werden
'datei' => 'txt/useron/user_ips.txt',
Diese Datei ist bei Dir auch direkt über HTTP erreichbar.
Das kannst Du bei Standardeinrichtungen von Apache verhindern, indem
Du einfach den Namen der Datei mit '.ht' beginnen lässt.
'datei' => 'txt/useron/.htuser_ips.txt',
// wie lange soll es dauern, bis ein Eintrag verfällt
'zeitlimit' => 300 // 5 Minuten = 300
);// zählt den aktuellen Besucher
function zaehle_besucher ($ident)
{
// hole die Liste
$liste = hole_besucher_liste ();// fuege das aktuelle Identifikationskriterium mit aktuellem Datum hinzu
$liste[$ident] = time ();// schreibe die Liste
schreibe_besucher_liste ($liste);
}
Das Holen der Liste und das anschließende Schreiben muss gemeinsam durch ein LOCK_EX geklammert werden, wenn das Script ordentlich arbeiten soll. Sonst fängst Du Dir ein TOCTOU-Problem ein [link:http://en.wikipedia.org/wiki/Time-of-check-to-time-of-use], da ja im Normalfall auch mehrere verschiedenen Clients gleichzeitig Requests senden können, die dann nebenläufig abgehandelt werden.
Das Öffnen und Locken der Datei sollte daher außerhalb der Teilfunktionen stattfinden und diese sollten das Handle übergeben bekommen.
// holt die Liste aus einer Datei
function hole_besucher_liste () {
// importiere die Konfiguration
global $besucher_online_konfiguration;
Das Arbeiten mit globalen Variablen führt die Nutzung von Funktionen i.d.R. ad absurdum.
Übergebe den Funktionen die Werte als Argumente oder Referenzen auf die Werte.
// initialisiere Array
$zeilen = array ();// öffne datei
$fh = fopen ($besucher_online_konfiguration['datei'], 'r');// fehler?
if (!is_resource ($fh)) {
return array ();
}// sperre datei
$res = flock ($fh, LOCK_SH);// gehe Zeilen durch
while (!feof ($fh)) {
$zeilen[] = fgets ($fh);
}// entsperre Datei und schließe sie
flock ($fh, LOCK_UN);
Das Entsperren ist überflüssig, wenn Du die Datei gleich anschließend schließt.
Es kann sogar zu Fehlern führen. Wenn Du explizit entsperren willst, musst Du vorher die Buffers der Datei leeren, damit auch wirklich alles Weggescchrieben wird. fflush($fh);
[link:http://de3.php.net/manual/en/function.fflush.php]
fclose ($fh);
$ergebnis = array ();
// gehe die Zeilen durch
foreach ($zeilen as $zeile)
{
// trenne Identifikationskriterium von Zeitstempel
list ($ident, $stempel) = explode ('|', $zeile, 2);
// wenn Identifikationskriterium leer ist, dann übergehen
if (empty ($ident))
{
continue;
}// wenn stempel zu alt ist
if ($stempel < time() - $besucher_online_konfiguration['zeitlimit']) {
// übergehen
continue;
}// füge zum Ergebnis hinzu
$ergebnis[$ident] = (int)$stempel;
}
return $ergebnis;
}// gibt die Anzahl der Besucher zurück
function anzahl_besucher ()
{
return count (hole_besucher_liste ());
}// schreibe die Liste zurück
function schreibe_besucher_liste ($liste)
{
// importiere die Konfiguration
global $besucher_online_konfiguration;$ergebnis = '';
// gehe die Liste durch
foreach ($liste as $ident => $stempel) {
$ergebnis .= "$ident|$stempel\n";
}// öffne datei
$datei = fopen ($besucher_online_konfiguration['datei'], 'w');
// sperre datei
flock ($datei, LOCK_EX);// Fehler?
if (!is_resource ($datei)) {
return false;
}
Diese beiden Statements sind zusätzlich zum TOCTOU-Problem in der falschen Reihenfolge
öffnen
Öffnung prüfen
sperren
Sperre prüfen
arbeiten
schließen
// schreibe das ergebnis
$cnt = fwrite ($datei, $ergebnis);// fehler?
if ($cnt === false) {
// entsperren und schließen
flock ($datei, LOCK_UN);
fclose ($datei);
return false;
}// schließe die Datei
flock ($datei, LOCK_UN);
fclose ($datei);// wir sind fertig
return true;
}?>
Außerdem dauern die Aufgaben in diesem Script ein paar Millisekunden und die Liste der IPs könnte etwas länger werden. Was ist, wenn ein User mittendrin, kurz nachdem er geklickt hat, die Lust verliert, auf die Response zu warten und sein Browserfenster schließt.
Dann gibt es einen User-Abort, der das Script sofort beendet. Es könnte passieren, dass die Datei dann noch nicht vollständig zurückgeschrieben worden ist. Damit wäre sie kaputt.
<http://de3.php.net/manual/en/function.ignore-user-abort.php>
HTTP ist zwar normalerweise verbindungslos, wenn aber die Verbindung zum Client mitten in der Abarbeitung des Besuches (genauer: während der Erzeugung der Response) gekappt wird, bekommt PHP das doch mit. Die Scripte liegen in der "Responsetime" des Dialoges.
Tom vom Berg
![](http://selfhtml.bitworks.de/Virencheck.gif)
--
Nur selber lernen macht schlau
<http://bergpost.annerschbarrich.de>