Translate

Archives

Persistent JavaScript Webpage Hit Counter

Recently I wanted to add a simple web page persistent hit counter to one of my websites. You have all seen such counters; there are a bazillion styles and sizes available on the Internet for free. Rather than use one of the external hit counter services such as hitwebcounter or free-counters or use a PHP and HTTP cookies solution, I decided to use JavaScript and XMLHTTPRequest to retrieve an incrementing counter on the website hosting platform and display it in a vcounter div element.

XMLHttpRequest is a JavaScript object which provides the basis mechanism for AJAX (Asynchronous JavaScript and XML) programming. If you do any sort of web programming, you need to become familiar with XMLHttpRequest. With it you can:

  • Update a web page without reloading the web page,
  • Request and receive data from a server after the web page has loaded,
  • Send data to a server in the background.

For more information see Mozilla XMLHTTPRequest.

Consider the following simple XHTML-based web page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Test JavaScript website hit counter</title>
        <script type="text/javascript" src="./counter.js" ></script>
        <script type="text/javascript">
            visitorcount()
        </script>
    </head>
    <body>
        <h1>Test JavaScript website hit counter</h1>

        <div id='vcounter'></div>

     </body>
</html>


The only thing unusual is the inclusion of a JavaScript source code file named counter.js and the empty div element with an ID of vcounter. When this web page is displayed the empty vcounter div is replaced with a string showing the value of the hit counter as shown below:

Hit counter screenshot 1

Here is the JavaScript code which is used by the browser to make the request to the server and insert the returned value into the empty vcounter divelement. The myXMLHTTPRequest function handles the difference between the two different Microsoft implementations of the XMLHttpRequest (XHR) specification and other implementations. By the way, this is a very common wrapper function for XMLHttpRequest; it is not something I developed.

//
//  Copyright 2007 Finnbarr P. Murphy.  All rights reserved.
//

function myXMLHTTPRequest()
{
    var request;

    try {
        request = new ActiveXObject("Microsoft.XMLHTTP");
    } catch(ex1) {
        try {
            request = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(ex2){
            request = null;
        }
    }

    if (!request && typeof XMLHttpRequest != "undefined") {
        request = new XMLHttpRequest();
    }

    return request;
}


function visitorcount() {

   var xmlhttp = myXMLHTTPRequest();
   if (xmlhttp) {
       try {
           xmlhttp.open("GET", 'loadcount.php', true);
       } catch (err) {
           alert ('An error occurred: ' + err.message);
       }
       xmlhttp.onreadystatechange = function (aEvt) {
           if (xmlhttp.readyState == 4) {
               var count     = xmlhttp.responseText;
               var node      = document.getElementById('vcounter');

               var frag      = document.createDocumentFragment();
               var preText   = document.createTextNode("You are visitor ");
               var span      = document.createElement('span');
               var spanText  = document.createTextNode(count);
               var postText  = document.createTextNode(" to this site.");
               var cssString = 'font-size:42px; font-family:Georgia; font-weight:bold;';

               frag.appendChild(preText);
               span.appendChild(spanText);
               span.setAttribute('style', cssString);
               frag.appendChild(span);
               frag.appendChild(postText);
               node.appendChild(frag);
           }
       }
       xmlhttp.send(null);
   }
}


When the callback function in visitorcount receives a suitable response from the server, i.e. when readyState = 4, a new DOM document fragment (frag) is constructed which includes a new span element, text nodes and a styling attribute. The document fragment is then appended to the div element using appendChild.

Here is the same output as previous but this time I use the popular Mozilla FireBug add-on to show how the previously empty div element is now populated.

Hit counter screenshot 2

If you refresh the web page, you will see that the hit counter value has increased by 1.

Hit counter screenshot 3

One of the parameters to the xmlhttp open method was loadcount.php. This is the name of the PHP script that invoked on the server.

<?php
#
#  return incremented value of counter
#
   $File = "counter.sav";

   if (is_readable($File)) {
       $handle = fopen($File, 'r+');
       $data = fread($handle, 512);
       $count = $data + 1;
       fseek($handle, 0);
   } else {
       $handle = fopen($File, 'w');
       $count = 1;
   }

   fwrite($handle, $count);
   fclose($handle);

   echo "$count";
?>


This PHP script is quite simple. It opens a file called counter.sav, reads the stored count, increments it by one and write the new count back out to the file. It then send the new count back to the XMLHTTPRequest callback function using the PHP echo language construct. If counter.sav does not exist, the count is set to 1 and this is what is written to counter.sav.

Well, you should now be able to implement your own persistent self hosted web page hit counter. Good luck!

P.S. I updated this in March 2011 to add the three screenshots.

Comments are closed.