EisFuX: Suche einen Counter

Beitrag lesen

Hallo Silvia,

ich suche einen Counter für meine Webseite. Ich habe jetzt schon mehr als 10 scripts getestet und immer hat eine Funktion gefehlt. Oder es war SQL oder oder oder...

Folgende Funtkionen muss der Counter haben

  • kein SQL (zahlen sollen in txt geschrieben werden)
  • die Zahl muss aus Graphiken bestehen (kein Textcounter)
  • es sollen nur die Besucher gezählt werden (nicht wer z. zt. online ist und auch keine Statistiken o.ä.)
  • freeware
  • sollte serverschonend sein (da ich viele Besucher habe)

Ich finde Counter doof, weil sie keinen praktischen Nutzen haben (weder für den Betreiber einer Website, noch für die Besucher derselben).

Es gibt in den Perl-FAQ einen
Beitrag, der den (Un-)Sinn von Hitcountern kurz und prägnant beschreibt. Den solltest du dir zu Herzen nehmen.

Allenfalls als Programmierübung kann man der Sache etwas abgewinnen. Ein PHP-Anfänger glaubt oft gar nicht, was beim simplen Schreiben in eine Datei alles schiefgehen kann ...

Kann mir jemand ein Script empfehlen?

Probiers mal mit diesem hier -- es ist als Programmierübung entstanden:

<?php /*  
count_hits.php  
  
Hitcounter-Dateiaufbau:  
1111506047,127.0.0.2  // UNIX-Datestamp,IP-Adresse  
...                   // weitere Eintraege der gleichen Art  
3                     //letzter_Zaehlerstand  
*/  
  
function count_hits(  
  $counter_file = 'counter_data.txt'  
) {  
  $hit_time = time(); // time(); unix-sekunden-Datestamp  
  
  // $cycle = 24 * 60 * 60; // in sekunden == eine Erdrotation ;-)  
  $cycle = 50; // nur zum Testen, so vergehen die Tage schneller ;-)  
  $past_time = $hit_time - $cycle; // die heutige Zeit vor einer Erdrotation  
  
  $komma = ',';  
  $nl    = "\n";  
  // Verzeichnispfad ohne abschließenden Slash!  
  $webroot = preg_replace(  
    '/'.preg_quote($_SERVER['SCRIPT_NAME'], '/').'\Z/i',  
    '',  
    $_SERVER['SCRIPT_FILENAME']  
  );  
  
  $elog_file = 'count_hits_error.log'; // auskommentieren, dann werden Fehler im Server-Error-Log ausgegeben  
  if( isset($elog_file) ) {  
    $emsg_type = 3;  
    $elog_nl = $nl; // Im User-Error-Log muessen wir selbst fuer Zeilenumbrueche sorgen  
  }  
  else{  
    $emsg_type = 0;  
    $elog_file = '';  
  }  
  
  $remote_ip = $_SERVER['REMOTE_ADDR']; // IP-Adresse des Besuchers holen  
  if( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ) $remote_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // Besucher mit Proxy unterwegs?  
  
  if( preg_match('|\A\/|', $counter_file) ) {  
    // fängt $counter_pfad mit einem "/" an, kleben wir ihn an den $webroot  
    // ansonsten vermuten wir $counter_file im selben Pfad wie unser PHP-Skript  
    $counter_file = $webroot.$counter_file;  
  }  
  
  $fh = FALSE; // ein File-Handle  
  if(!file_exists($counter_file) ) {  
    $fh = @fopen($counter_file, 'w');  
    if($fh === FALSE ) {  
      error_log('Fehler: Konnte  Datei "'.$counter_file.'" nicht anlegen!'.$elog_nl, $emsg_type, $elog_file);  
      return(0);  
    }  
    fclose($fh);  
  }  
  
  $fh = @fopen($counter_file, 'r+'); // wir wollen lesen und schreiben!  
  if($fh === FALSE) {  
    error_log('Fehler: Konnte Datei "'.$counter_file.'" nicht oeffnen!'.$elog_nl, $emsg_type, $elog_file);  
    return(0);  
  }  
  if( @flock($fh, LOCK_EX) === FALSE ) return(FALSE);  
  $iua = ignore_user_abort(TRUE); //  
  
  fseek($fh, 0); // Filepointer auf Dateianfang setzen  
  
  $list = array(); // ist notwendig, denn die Counter-Datei kann auch leer sein!  
  $xpl = array();  
  // $xpl[0] : timestamp  
  // $xpl[1] : ip-adresse  
  while($buffer = fgets($fh) ) {  
    $xpl = explode($komma, rtrim($buffer) );  
    if( count($xpl) == 1 ) {  
      $last_counter = $xpl[0];  
      break;  
    }  
    if($past_time > $xpl[0]) continue;  
    $list[$xpl[0]] = $xpl[1];  
  }  
  
  if( !isset($last_counter) ) $last_counter = 0;  
  if( !is_numeric($last_counter) ) {  
    error_log('Fehler: $last_counter ('.$last_counter.') ist keine Ganzzahl!'.$elog_nl, $emsg_type, $elog_file);  
    return(0);  
  }  
  
  $buffer = '';  
  $same_user = FALSE;  
  if( count($list) > 0 ) {  
    foreach($list as $key => $val) {  
      $buffer .= $key.$komma.$val.$nl;  
      if($remote_ip == $val) $same_user = TRUE; // Benutzer hat schon mal geklickt  
    }  
  }  
  $list[$hit_time] = $remote_ip;  
  
  if($same_user === FALSE) {  
    $last_counter++;  
    $buffer .= $hit_time.$komma.$remote_ip.$nl;  
  }  
  $buffer .= $last_counter.$nl;  
  
  fseek($fh, 0);  
  @fputs($fh, $buffer);  
  
  ftruncate($fh, strlen($buffer) ); // Datei auf neue Länge kürzen  
  @fclose($fh);  
  ignore_user_abort($iua); //  
  
  return($last_counter);  
}  
?>

Das Script ist deshalb so lang, weil es neben der reinen Zählerei noch versucht, Besucher an ihren IP-Adressen wiederzuerkennen. Die Betonung liegt hierbei auf "versucht" -- das Ergebnis darf man als Schätzung betrachten. Es gibt dabei viele Unwägbarkeiten (Proxy-Server, Wiedereinwahl bei Call-by-Call-Providern usw.).

Eingebunden in ein eigenes PHP-Script könnte das so aussehen:

<?php  
//folgende Zeile auskommentieren, um alle Fehler anzuzeigen  
//error_reporting(E_ALL);  
  
require_once('count_hits.php');  
  
$meldung = 'Ich glaub, der Counter ist kaputt! :(';  
$hits = count_hits('test.txt');  
if($hits > 0) {  
  $meldung = sprintf('Hallo, Besucher Nummer %s!', $hits);  
}  
?>  
<html>  
<head>  
  <title><?php print($meldung) ?></title>  
</head>  
<body>  
<?php  
print($meldung."<br />\n");  
?>  
</body>  
</html>  
<?php  
exit();  
?> 

Eine ausführlichere Erklärung zum Quellcode gibts hier (wenn die Seite nicht mal gerade wieder offline ist).

Wie du siehst, ist dies auch nur ein "text-basierter" Counter. Mit ein bisschen CSS kann man damit durchaus auch schöne Zahlen zaubern. Wenn du unbedingt Grafiken einbinden willst, ist das kein Problem. Du musst nur ein Verzeichnis angeben, in dem die Grafik-Dateien für die Ziffern liegen (bspw. mit den Namen "0.gif" bis "9.gif"). Statt die Zahl mit print() oder echo() auszugeben, muss sie vorher noch mit preg_replace() ein wenig umgebaut werden:

  
$bilder_pfad = 'verzeichnis/';  
  ...  
  $hits = preg_replace('/\d/', '<img src="'.$bilder_pfad.'.gif" />', $hits);  
  $meldung = sprintf('Hallo, Besucher Nummer %s!', $hits);  

MffG
EisFuX

--
Auch meine Hosenträger sind intelligent, in dem Sinne, dass man sie regulieren kann. Sie besitzen ein adaptives Verhalten.
Stanisław Lem