I will introduce on this page a meter system, which is light and relatively reliable. It is programmed with PHP, using the HTTP cache and conditional requests mechanism.
This example generates a PNG picture.
Estimated amount of visitors of this page:
The installation procedure consist in downloading the script and one library, to put them in one same directory,
on a Web server running PHP, and to change their extension to .php
It is now needed to ensure that PHP is allowed to read and write in the directory where those two files have been places.
In particular, the script will save the amount of visitors in the file meter.txt
,
and create during each execution a temporary file mutex2.txt
that is erased as soon as the script ends, some milliseconds later.
In order to test that everything is working, use your Web browser to see the file meter.png.php
If testing locally, the address will look like http://localhost/test/meter.png.php
If it does not work, comment temporarily the two lines error_reporting(E_ERROR);
and header('Content-type: image/png');
in order to see some possible error messages.
When doing that, it is normal to see some strange text beginning by ‰PNG
or similar.
Once the meter is working, alone, it is time to include it in a Web page. This is done simply by adding a picture, whose address is the one of the meter script.
<html> ... <img src="meter.png.php" height="18" alt="[Meter]" title="Number of visitors" /> ... </html>
The width of the picture is automatic, and will increase when needed.
Here is the code of the script for the meter.
meter.png.php <?php $session=1800; //In seconds $fmeter='meter.txt'; error_reporting(E_ERROR); header('Content-type: image/png'); require_once('http-conditional.php'); //Details about this library on https://alexandre.alapetite.fr/doc-alex/php-http-304/ $begin=time(); $lastModif=max($begin-$session,filemtime($fmeter)); if (httpConditional($lastModif,$session,0,true,true)) exit(); //Cache 30 minutes, private, compression ignore_user_abort(true); //<aquire_mutex> $mutexFile1='mutex1.txt'; //File to use for mutex method#1 $mutexFile2='mutex2.txt'; //File to use for mutex method#2 $mutexOK=false; $mutexMethod=0; if (file_exists($mutexFile1)) {//Mutex method#1 (best, but does not work on many systems) $mutexMethod=1; $fp=fopen($mutexFile1,'w+'); $mutexOK=flock($fp,LOCK_EX); } else {//Mutex method#2 (assumes fopen() is atomic) $mutexMethod=2; if (file_exists($mutexFile2)&&($begin-filemtime($mutexFile2)>30)) {//In case a previous old execution failed to clean the mutex file. //Resistant on concurrent processes @chmod($mutexFile2,0666); unlink($mutexFile2); } $attempt=1; while (($attempt<50)&&(@fopen($mutexFile2,'x')===false)) { $begin2=time(); usleep($attempt*5000); //Sleep in milliseconds $usleep2=1000000; while (($usleep2>0)&&(time()-$begin2>$attempt*5000)) $usleep2--; //If usleep() does not work $attempt++; } $mutexOK=($attempt<50); } //</aquire_mutex> if ($mutexOK) { if($myMeter=fopen($fmeter,'r')) {//Read curent meter $meter=trim(fgets($myMeter,12)); $lastIP=trim(fgets($myMeter,36)); fclose($myMeter); if (!is_numeric($meter)) $meter=0; } else { $meter=0; $lastIP=md5('127.0.0.0'); } $IP=md5($_SERVER['REMOTE_ADDR']); if (((time()-$clientCacheDate)>$session)&& !(($clientCacheDate<632003440)&&($IP==$lastIP))) //Small protection against multiple refresh {//If the session has expired, increment the meter $meter++; if($myMeter=fopen($fmeter,'w')) { fputs($myMeter,$meter."\n"); fputs($myMeter,$IP."\n"); fclose($myMeter); } clearstatcache(); //Update HTTP headers with new "Last-Modified" and "ETag" httpConditionalRefresh(filemtime($fmeter)); } } else $meter='?'; //<release_mutex> switch ($mutexMethod) { case 1: flock($fp,LOCK_UN); fclose($fp); break; case 2: @chmod($mutexFile2,0666); unlink($mutexFile2); break; } //</release_mutex> $font=5; $im=imagecreate(5+2*$font*strlen($meter),18); $bg=imagecolorallocate($im,255,255,255); imagecolortransparent($im,$bg); $tc=imagecolorallocate($im,0,0,0); imagestring($im,$font,4,2,$meter,$tc); imagepng($im); imagedestroy($im); ?>
This content is protected by a licence
Creative Commons Attribution-ShareAlike 2.0 France "BY-SA (FR)"