Visitors graph

From Miguel Caro's wiki
Jump to: navigation, search

Here I explain how to create a visitors graph for your website, like the one here. Previous knowledge of (basic) PHP and the use of the Gnuplot plotting program and Linux shell commands would be helpful, although the implementation is very simple and straight-forward. This tutorial does not apply to the Windows operating system. If you use Windows, then I invite you to switch to Linux, which comes in many flavors, most of them free.

Contents

What it does

The code described here:

  • Creates/updates a data file with the date and the number of visitors to a website every time there is a new visitor to the site;
  • Generates a graph image with that data that displays the number of visitors as a function of time.

Requirements

The server where you will be executing the PHP script needs:

  • PHP enabled, of course;
  • Permission for PHP to execute external (or shell) commands;
  • Gnuplot must be installed in the server and available to Apache or whatever your web server is;
  • Apache must also have write access to the directory where you are generating the graph and the data or, at least, to the output image and data files.

Creating the data

Basic visit counter

To create the data I use a PHP script written by Klemen Stirn, and that can be freely downloaded form phpjunkyard.com. That script basically updates a file that contains the number of hits to a particular website every time the site is loaded. For more details refer to the documentation or have a look at the script itself. Stirn's script will generate a hit count file within a subdirectory named "logs/".

Generating the data for the graph

This is the part that I wrote. Because we want to plot the number of visits as a function of time, a mere number giving the total hit count is useless to us. We need another script that will write to a file new data every time the website is visited and will keep the old data as well. Basically, what my PHP script does is store in one column the date and in another column the number of hits reached by that date. To avoid having too many entries in the file, the script will only keep a maximum of one entry per day. That is, a new entry will be created for the first hit of any given day, but any further hits occurring during that same day will have the effect of updating that day's entry, rather than creating a new one. In this way, the hit count will be stored for each particular day in which there was at least one hit, days when nobody visited the website will simply not have an entry.

To do that, you must modify Klemen Stirn's hit counter script by adding the following lines after the block entitled "Increase the count by 1":

/*  Print to visits history */
    $datetoday = date("Y m d");
    $hislogfile = "logs/" . "history_" . $page . ".txt";

    $vh = @fopen($hislogfile,"a+");
    $lastdateinfile = exec("tail -1 $hislogfile | cut -c1-10");
    $lastdateinfile2 = trim ($lastdateinfile);
    if ( $datetoday == $lastdateinfile2 ) {
      $numberoflines = exec("cat $hislogfile | wc -l");
      exec("sed '$numberoflines d' < $hislogfile > logs/temp; cp logs/temp $hislogfile");
      fputs($vh, $datetoday."    ".$count."\n");
      fclose($vh);
      }
    else {
      fputs($vh, $datetoday."    ".$count."\n");
      fclose($vh);
    }

If your page name is "pagename", the code above will generate a file named "history_pagename.txt" inside the "logs" directory where the hit count "pagename.txt" is also stored by Klemen Stirn's original script. If you have two entries for the 14th of May 2012 (hit count reached 3 visitors) and the 15th of May 2012 (reached 5 visitors) then your "history_pagename.txt" file will look like

2012 05 14     3
2012 05 15     5

Notes

  • There is a temporary file "temp" written each time the history is updated. Obviously, within the "logs/" directory Apache must have write access to "pagename.txt", "history_pagename.txt" and "temp". The easiest thing to do is to give Apache write access to the whole "logs/" directory.
  • This script executes external Bash commands. In particular, "tail", "cut", "sed" and "cp". The vast majority of Linux distributions will come with these enabled. Remember you may need to change your PHP configuration file so external commands can be executed.

Plotting the graph

My choice program for plotting data is Gnuplot. It is a very powerful line command plotting program. You need to have it installed on your server. Once that is done, you need to create a Gnuplot script that generates a picture with all the options and style that you want. A sample script that generates a PNG file "visits.png" is the following:

set term png size 640,280 enhanced font "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf" 12
set output "visits.png"
#
set xdata time
set timefmt "%Y %m %d"
set format x "%d/%m/%y"
set xtics rotate
#
set grid
#
#
set title "Number of visitors to {//usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf miguelcaro.com.es} since 12/03/2012"
#
plot "../logs/history_mainpage.txt" u 1:4 w l lc 1 lw 2 pt 7 ps 1.2 notitle

You can use the script above if you are happy with the style I chose, changing the data file "../logs/history_mainpage.txt" to whatever your data file is. If you are familiar with Gnuplot or want to learn, you can search the documentation and mess with the basic script above. The time format for the axis tics is tricky in Gnuplot, so leave it to auto unless you know what you are doing.

Finally, you will need to invoke Gnuplot so it can generate the picture every time some body wants to see it. To do that, you can include PHP code in the webpage from which the image is accessed. If your Gnuplot script is in the file "gnuplot.script" then the following PHP script will generate the image:

<?php
exec("gnuplot gnuplot.script");
?>

A more complex PHP script that will create an html document, invoke Gnuplot and load the image is the following:

<?php

/* Remember the webserver running PHP must have write */
/* access to the gnuplot output file or the directory */
/* where it is going to be created */
exec("gnuplot gnuplot.script");

echo "<html>
";

echo "<head>
<title>Miguel Caro's website</title>
<meta name=\"Content-Script-Type\" content=\"text/javascript\">
</head>
";

echo "<body style=\"text-align:justify;width:640;
margin-left:auto;margin-right:auto\">
";

echo "<h1>Evolution of the number of visitors with time</h1>
";

$visitsfile = @fopen("../logs/mainpage.txt", "r");
$numvisits = fgets($visitsfile,1024);

echo "<div>The total number of visitors so far is <b>".$numvisits."</b>.
A \"visitor\" is a hit on the main page <b>miguelcaro.com.es</b>
from any given computer separated by at least one hour
from the previous hit from that computer.</div>
";

echo "<p id=\"graphContainer\"><img id=\"graph\" width=\"640\" height=\"280\"
alt=\"Visits graph should go here... something might be wrong with
your browser.\" style=\"left-margin:0px;right-margin:0px\"
src=\"visits.png?".time()."\" /></p>
";

echo "<script type=\"text/javascript\">
<!--
image = document.getElementById('graph');
container = image.parentNode;
text = document.createTextNode('Please, wait while the graph is generated...');
error = document.createTextNode('Sorry, an error occurred while trying to generate the graph');
container.replaceChild(text, image);
cache = new Image;
cache.onerror = function () {container.replaceChild (error, text)};
cache.onload = function () {container.replaceChild (image, text)};
cache.src = image.src;
// -->
</script>
";

echo "<div><a href=\"/wiki/index.php/Visitors_graph\">Tutorial</a>
on how to implement the above graph in your site.</div>
";

echo "</body>
";

echo "</html>
";

?>

You can customize the code above to your liking.

Terms of use

All the codes above have been originally written by Miguel Caro, except for Klemen Stirn's hit count PHP script. This code is provided without any warranty of any kind and to be used at the user's own risk. I will not accept any liability related to its use or damage to any equipment due to the lack of knowledge of the user. It is also available free of charge provided that it is not used for commercial purposes. If you want to use it for a commercial application, please contact me in advance.

Personal tools
Namespaces

Variants
Actions
Professional
Personal
Miscellaneous
Toolbox