Compter le nombre de visiteurs simultanés sans base de données

Compter le nombre de visiteurs sans base de données, avec un simple fichier texte peut paraitre simplet et inutile. Outre l’aspect ludique, ce programme offre l’avantage de fonctionner même lorsque votre base de données est ‘down’. Il peut enfin être associé à une boucle conditionnelle -> Si la base ne répond pas, alors…passer en manuel, en fichier texte.

Description, mode d’emploi :

  • 1 – créer un répertoire /stats/
  • 2 – créer 3 fichiers :
    • 2.1 fichier texte /list.cnx qui contiendra l’heure au format UNIX et l’adresse IP
    • 2.2 fichier /class.php qui contiendra l’objet simulta_stats
    • 2.3 fichier /index.php qui contient pour l’instant le jeu de test, mais à l’avenir, qui doit contenir une ligne : die(« accès interdit ») ; (en effet, il faut toujours créer un fichier index pour bloquer un repertoire.
  • 3 – on installe les 3 fichiers dans le répertoire /stats/, on fait un include sur le fichier class.php et on instancie la classe simulta_stats :
    $stat = new simulta_stats($REMOTE_ADDR,10,15) ;
    On a alors accès aux méthodes et propriétés de la classe à travers l’obj stat.
  • 4 – on peut voir ce que donne le programme en essayant le fichier index.php, puis on l’effacera. (au profit d’un header ou d’un die() ). les exemples sont dans le fichier index.php.

Fichier index.php

 <?

include("class.php");

// on considere que le 'temps de simultané' est égal à 10 minutes par défaut, la valeur est de 5 minutes).
// donc le deuxieme parametre est 10.

// on considère qu'un internaute 'moyen' demande 200 pages MAXIMUM pendant ce temps de xx minutes
// donc on mets 200 pages max. 
// au dessus de 200 pages, la fonction max_hits renvoie TRUE;

// on instancie la classe simulta_stats.


for ($a=0;$a<200;$a++){

// on fait tourner les adresses IP pour voir si ca marche ...
$REMOTE_ADDR="125.255.255.".rand(150,200);

$stat = new simulta_stats($REMOTE_ADDR,10,15);

}

//----------------------------------------------------
//----------------------------------------------------
// Pour dépiler le tableau des données :
ksort($stat->liste_total);
echo"-------- IP ------------------ nb ---------------------- derniere ----------";
echo"<br>-------------------------- connections ------------- connection ----";
foreach ($stat->liste_total as $k => $v){
echo "<br><b><font color='red'>".$k."</font></b>";
foreach ($v as $k2 => $v2){echo".................   ".(($v2>1)?"<font color='red'>".$v2."</font>":$v2)." ";}
}
//---------------------------------------------------

//---------------------------------------------------
echo"<p>Nombre de visiteurs uniques pendant les ".$stat->period()." dernières minutes : <b>".$stat->nb_user_uniq()." visiteurs</b>";
//---------------------------------------------------
echo "<p> Nombre de hits pendant les ".$stat->period()." dernières minutes : <b>".$stat->nb_visite_uniq()." hits</b>";

//---------------------------------------------------
echo"<p> Vous etes le visiteur ip n°".$stat->ip_user;
if ( ! $stat->max_hits()){
echo"<br> Vitesse normale pour vous !!"; 
$nb= $stat->nb_connections_user;
echo" Vous en etes à <b>".$stat->nb_connections_user."</b> pages demandées pour la période de référence de <b>".$stat->period()."</b> minutes";}
else {  
echo"<br> <b>VOUS DEMANDEZ TROP DE PAGES !!</b>";  
die("<br>header: surcharge du serveur... fatigue ?");
}

//---------------------------------------------------
echo"<p> Liste des personnes présentes :";
while ($temp=array_shift($stat->liste_ip())){
echo $temp.", ";
}
//---------------------------------------------------

die("<p>merci...");

?>

fichier class.php

<?php

class simulta_stats{

//---------------------------------------------------
//      par Anonymus ( nicolasgalle )
//---------------------------------------------------
// INSTANCIATION
// $stat = new simulta_stats($REMOTE_ADDR,10,30);
//
//echo"<p>Nombre de visiteurs uniques pendant les ".$stat->period()." dernières minutes : <b>".$stat->nb_user_uniq()." visiteurs</b>";
//
//echo "<p> Nombre de hits pendant les ".$stat->period()." dernières minutes : <b>".$stat->nb_visite_uniq()." hits</b>";
//
// if ( $stat->max_hits($REMOTE_ADDR)){ echo"<br> <b>VOUS DEMANDEZ TROP DE PAGES !!</b>";}
//
//---------------------------------------------------

 var $fp;        // pointeur de fichier
 var $liste_total;     // liste des secondes et des IP des visiteurs.
 var $liste_ip;      // liste des ip du fichier.
 var $ip_user;      // adresse ip du visiteur, du style  127.0.0.1

 var $now;       // maintenant. On enregistre la variable pour que le 'maintenant' ne change pas de valeur en cours de route;)

 var $time_simult=5;    // durée de temps de la simultanéité : 10 visiteurs visitent le site simultanément, soit en .. 2 minutes.
 var $text_file;     // le fichier list.cnx en entier

 var $nb_visite_uniq;    // compte le nombre d'utilisateurs connectes sumultanément.
 var $max_hits_allowed;   // valeur maximum de pages pouvant etre vues pendant la période de 'simultanéité'.
 var $nb_connections_user;  // nombre de connections de l'internaute pendant le temps de référence.
 var $an_ip;

function simulta_stats($REMOTE_ADDR,$time_simult=5,$max_hits_allowed){

 // constructeur de l'objet, porte donc le meme nom que sa classe.
 // Le premier parametre est l'adresse IP du visiteur. de 1.1.1.1 à 255.255.255.255
 // le deuxieme parametre ($time simult), un INTEGER est optionnel. Par défaut, est égal à 5 (cinq) minutes.

 // Initialisation des variables
 $this->ip_user=STRVAL($REMOTE_ADDR);

 if ($time_simult>0 && $time_simult<6000)$this->time_simult=$time_simult;
 $this->max_hits_allowed=$max_hits_allowed;
 $this->nb_connections_user = 0;
 // initialiser l'heure (timestamp UNIX en secondes) permet d'avoir une valeur stable perdant le déroulement du programme.
 $this->now = time();

 // on enregistre le visiteur dans le fichier list.cnx
 $this->enreg_visit();

 // on extrait la liste du fichier list.cnx
 $this->extract_liste();

 // on réécrit la liste dans le fichier list.cnx
 $this->reecrit_liste();

 }


function extract_liste(){
//  echo"<br><b>extrait liste</b>";     // on écrit la ligne à l'écran : debuggage

 // init des variables
 $this->text_file="";
 $this->liste_ip=array();

 // on comptera le nombre d'utilisateurs connectés ici. C'est plus simple.
 $this->nb_visite_uniq=0;

 // on ouvre le fichier
 $this->fp=fopen("list.cnx","r");

 // tant que c'est pas la fin du fichier ( ou tant qu'il n'y a pas d'erreurs)
 while (!feof($this->fp)){

  // on dépile la ligne
  $line=fgets($this->fp,32);

  // et si la ligne n'est pas vide
  if (!empty($line)){

   // on 'explode' la ligne $line, On la coupe en deux, la séparation etant l'espace.
   // on en profite pour séparer les $sec (timestamp UNXI) et les $an_ip (adresses IP). 
   (list($sec,$this->an_ip) = explode(" ",$line));

   // si les ip des visiteurs du fichier sont egales au visiteur actuel, 
   // alors le nombre de connections du visiteur actuel augmentent.

   $this->an_ip=trim($this->an_ip);

   if ($this->an_ip ==  $this->ip_user){

       $this->nb_connections_user ++;
       }
   
   // on verifie si les visiteurs n'ont pas dépassé le temps de 'simultanéité'.
   if ($sec>($this->now)-($this->time_simult*60)){

    // si 'non', alors on les compte dans les users connectés
    $this->nb_visite_uniq++;

    // on garde leur ligne pour l'insert dans le fichier list.cnx
    $this->text_file.=$line."";

    // on verifie si l'on a déjà eue affaire à cette adresse ip : Donc, si elle est ou non dans le tableau :

    if (! in_array($this->an_ip,$this->liste_ip)){
     
     array_push($this->liste_ip,$this->an_ip);
     $this->liste_total[$this->an_ip]['nb_connection'] = 0;
  
     }     

    // on construit un tableau avec les donnees fournies : ip, derniere connection, nb de connections.
    $this->liste_total[$this->an_ip]['dern_connection'] = $sec;
    $this->liste_total[$this->an_ip]['nb_connection'] +=1;


    } 

   }  

  }
 // ferme le fichier 
 fclose($this->fp);
 }
 

function reecrit_liste(){

 // réécrit la liste dans le fichier list.cnx
//  echo"<br><b>reecrit liste</b><br><i>et efface les ip périmées</i>";     // on écrit la ligne à l'écran : debuggage

 // le strlen est une sécurité. Si la variable est vide, c'est qu'il y a un probleme. Pas la peine d'effacer le fichier.
 if (strlen($this->text_file)>10){

  // on ouvre le fichier en 'ecriture', mais le fait de mettre "w" fait que le fichier est réduit à 0 (zéro). D'où la sécurité du dessus .
  $this->fp=fopen("list.cnx","w");

  // on ecrit dans le fichier le texte importé de 'extract list'
  fwrite($this->fp,$this->text_file);

  // on ferme le fichier.
  fclose($this->fp);
  }  
 }
 

function enreg_visit(){

 // permet d'enregistrer un visiteur.

//  echo "<b>enreg visit</b>";     // on écrit la ligne à l'écran : debuggage

 // ouvre le fichier
 $this->fp=fopen("list.cnx","a");

 // construit la ligne destinée à etre insérée dans le fichier
 // et ecrit dans le fichier
 fwrite($this->fp,$this->now." ".$this->ip_user."\n");

 // ferme le fichier
 fclose($this->fp);

 }

function nb_visite_uniq(){

 // retourne le nombre de visites ayant eu lieu pendant le temps $time_simult.

 return $this->nb_visite_uniq;

 }

function nb_user_uniq(){
 
 // retourne le nombre de visiteurs uniques pendant la période $time_simult.
 
 return count($this->liste_total);

 }
 
function period(){
 // retourne la période de simultanéité.
 return $this->time_simult;
 }


function liste_total($REMOTE_ADDR){
 
 // retourne un tableau accessible sous la forme :
 //
 // $obj->liste_total[ip]['nb_connection']
 // $obj->liste_total[ip]['dern_connection ']
 //
 // pour le visualiser :
 //  ksort($obj->liste_total);
 //  foreach ($stat->liste_total as $k => $v){
 //   echo "<p><b>".$k."</b>";
 //   foreach ($v as $k2 => $v2){echo"<br>.......... $k2 : $v2 ";}
 //   }

 return $this->liste_total;

 }

function max_hits(){
 // fonction qui retourne TRUE si le visiteur a fait trop de hits pendant la période ::
 //
 // exemple : le visiteur 255.255.255.255 effectue 50 appels de page pendant la dernière minute 
 // la fonction renverra FALSE.
 // S'il effectue 100 appels de page, la fonction renverra TRUE.
 // Compris ?
 // Essayez. Vous appelez le programme une centaine de fois, il répondra : Trop de pages demandées;)

 // Il est alloué un max de hits à chaque visiteur, qu'il peut consommer pendant la période de référence.
 // s'il dépasse cette valeur, la fonctio nrenvoie TRUE.


 if ($this->nb_connections_user > $this->max_hits_allowed){
  // ca retourne // Oui, il dépasse la vitesse max.
  return TRUE;
  }

 else{
  
  // Sinon // ca retourne : non, ca va, il roule normal;)
  return FALSE;
  }  
 }


function liste_ip(){
 // retourne la liste des IP 

 return $this->liste_ip;
 }

function nb_connections_user(){
 // retourne le nombre de connections de l'internaute actuel.

 return $this->nb_connections_user;
 }
function ip_user(){
 // retourne l'ip de l'internaute actuel.

 return $this->ip_user;
 }



}
?>

fichier list.cnx

Le fichier list.cnx est vide, évidement.
pourquoi .cnx ? Mettre un nom d’extension ‘non courant’ à un fichier texte permet d’éviter que des personnes mal intentionnées ne cherchent à le lire. Une petite protection supplémentaire.

Une petite chose ::
Le fait de dire à un internaute qu’il a fait 250 requetes en 2 minutes n’a qu’un intéret limité. Ce dispositif permet par contre de bloquer les aspirateurs de site et autres moteurs de recherche qui vous pompent sauvagement votre site.