Articles: 843 | Categories: 148   
   
   
Home Articles Contact Us
 
 
 
 
Periodical visitor counter or live update with Ajax and Prototype (0 Comments)
Admin: Posted Date: April 4, 2010

Prototype is a Javascript framework that aims to ease development of dynamic web applications. Among other things that this framework can offer, what really interests us here is that the guys at Prototype have an excellent and easy-to-use toolkit for developing Ajax applications.

Periodical visitor counter or live update with Ajax and Prototype

Introduction

What is Prototype?

Prototype is a Javascript framework that aims to ease development of dynamic web applications. Among other things that this framework can offer, what really interests us here is that the guys at Prototype have an excellent and easy-to-use toolkit for developing Ajax applications. Furthermore, we can elaborate on Prototype by using Scriptaculous which adds even more functionality and some interesting special effects.

2.2. You will need:

  1. to download the Prototype Javascript framework.
  2. to have a basic understanding of PHP/MySQL. As I will not explain the code in elaborate detail. Since it's not the purpose of this guide.

3. Javascript for our Ajax periodical visitor counter

Before reading on. I should point out that I made this piece of javascript so we can reuse it. This means, insert the updater.js in every file where you need to have some kind of live updating. Then call the javascript by writing:
  1. <script type="text/javascript" src="updater.js"></script>  
  2. <script type="text/javascript">  
  3.     // <![CDATA[  
  4.     document.observe('dom:loaded'function() {  
  5.         /* 
  6.         first arg   : div to update 
  7.         second arg  : interval in seconds 
  8.         third arg   : file to get data from 
  9.         */  
  10.         var visitorCounter = new updater('counter', 1, 'countVisitors.php');  
  11.           
  12.         // Make first call so we get an immediate update after the page is loaded   
  13.         visitorCounter.getUpdate();  
  14.     });  
  15.     // ]]>  
  16. </script>  
  17.           
We'll explain the updater.js later on. For now remember that the file stands alone and can be used for all kinds of live polling.

save following snippet as updater.js

  1. var updater = Class.create({  
  2.     initialize: function(divToUpdate, interval, file) {  
  3.         this.divToUpdate = divToUpdate;  
  4.         this.interval = interval;  
  5.         this.file = file;  
  6.         new PeriodicalExecuter(this.getUpdate.bind(this), this.interval);  
  7.     },  
  8.       
  9.     getUpdate: function() {  
  10.         var div = this.divToUpdate;  
  11.         var interval = this.interval;  
  12.         var file = this.file;              
  13.         var oOptions = {  
  14.             method: "POST",  
  15.             asynchronous: true,  
  16.             parameters: "intervalPeriod="+interval,  
  17.             onComplete: function (oXHR, Json) {  
  18.                 $(div).innerHTML = oXHR.responseText;  
  19.             }  
  20.         };  
  21.         var oRequest = new Ajax.Updater(div, file, oOptions);  
  22.     }  
  23. });  
  24.           
Alright folks. This is our core javascript class. our class is called updater. The very first method (a method is the name used for a function inside a class) is called initialize: function(). That's similar to the PHP5 initialiser method: __construct(). This means that this method is always called when the class is instantiated.

initialize: function()

You can see that the initialize method takes three arguments:

  • divToUpdate: that is the div element we want to update, in our example: counter
  • interval: when the system should check for new visitors measured in seconds. In our code I use 30 seconds: our back-end (the php code) will do a check for new visitors every 30 seconds.
  • file: the file we want to poll, that's our php file, which does the actual checking and gives us the output

We assign the arguments to global variables (within the class scope that is). Next we instantiate the built-in (in Prototype) object called PeriodicalExecuter(), which in its turn takes 2 arguments:

  • the method to execute
  • the interval measured in seconds to execute function
getUpdate: function()

Next we define a method that we can name as we like (in our example that is getUpdate: function()).

In the first three lines var div = this.divToUpdate; var interval = this.interval; var file = this.file; of this method we store the variables that were passed to us by our initialization method initialize: function(), which is only called one time of course (when we load the page). We store them so we can use them later on every time the getUpdate: function() is called.

The oOptions object (the little o stands for object, just a good coding convention) contains the following properties:
  • method: "get" or "post" (update: IE6 seems to have problems with the GET method, use POST instead.)
  • asynchronous: which can be true or false and determines if the AJAX call to the server will be made asynchronously (the default value is true.)
  • parameters: the data to be sent to the URL. Typically, a URL-encoded string of name-value pairs. The combining of the URL and the parameters is handled by Prototype behind the scenes (it could look like this: visitorCounter.php?intervalPeriod=30). The value of the intervalPeriod is passed on to our back-end.
  • onComplete: function to call when the call is complete. The code within updates our container div (this.divToUpdate) with the standard oXHR.responseText.
  • onSuccess: function to call when the response has been successfully received
  • onFailure: function to call when the response has failed
  • onLoading: function to call when the response is loading. Not necessary I believe since we're updating very frequently. Seeing a 'loading' message every time can get quite annoying
The onComplete(), onSuccess() and onFailure() methods are functions that are passed 2 arguments: the XHR object used to make the request and an optional JSON object with additional information about the request. Nothing to worry about in this tutorial.

new Ajax.Updater()

After we declared our options to pass along, we're going to send the request. This will be done with the following code: Ajax.Updater(element_id, url, options). It takes an HTML element's ID as its first argument. So when a response is received (our number of visitors in this case) Ajax.Updater puts the response into the HTML element with the given ID we provided. We have written new Ajax.Updater(this.divToUpdate, this.file, oOptions); So the response will be displayed in the div element we passed along as an argument in the initialize: function();.
this.file is a variable where we stored our third argument of the initialize: function(); in.

Voilà, that's it. The logic is fairly simple. We call our method (it gets our data) and we execute that method every x seconds, where x is the second argument in the initialize: function();.

PeriodicalExecuter VS PeriodicalUpater

For those wondering why I use PeriodicalExecuter instead of PeriodicalUpater: PeriodicalUpdater has some problems. Memory leaks. I found my browser grinding to a halt after about 600 requests with PeriodicalUpdater. The leaks were fixed a while ago (check for the patch: http://dev.rubyonrails.org/changeset/8152) For compatibility's sake we could use the clearInterval / setInterval combo. A warm and fuzzy solution. Instead I opted for PeriodicalExecuter. Documentation says: "This is a simple facility for periodical execution of a function. This essentially encapsulates the native clearInterval/setInterval mechanism found in native Window objects." Clean and simple. Also fuzzy.

Special thanks goes out to Josef Wendel who pointed out a bug in my code. The code in the example has been updated.

4. PHP for our periodical live update visitor counter

Fire up good ol' phpmyadmin and execute following sql code:

  1. CREATE TABLE `visits` ( `visitor_ip` int(10) NOT NULL default '0', `visitor_time` int(10) NOT NULL default '0', KEY `visitor_time` (`visitor_time`) ) TYPE=MyISAM;  
save as countVisitors.php.
  1. <?php  
  2. header('Content-Type: text/html; charset=UTF-8');  
  3. header('Cache-Control: no-cache');  
  4. header('Pragma: no-cache');  
  5. // visitor counter  
  6. // by: Nico Beekhuijs  
  7. // date: 03-11-2006  
  8. // This script counts the number of visitors on the website  
  9. // for the last x minutes.  
  10. // Visitors are tracked by their IP address making several  
  11. // visitors from the same IP (ie a proxy) count as one.  
  12. // Tracking by IP is good enough in most cases  
  13.   
  14. // config variables  
  15. $timeframe = $_POST['intervalPeriod'];    // time frame (seconds) to count active users  
  16.   
  17. // database connection details  
  18. $db_host = "localhost";     // hostname of your MySQL server. You most likely don't have to change this  
  19. $db_name = "your_db_name";  // database name  
  20. $db_user = "your_username";         // database user  
  21. $db_pass = "your_password";     // database password  
  22. $db_table"visits";        // table name  
  23.   
  24. // Lets open up a connection to the database  
  25. $connection = mysql_connect($db_host$db_user$db_pass);  
  26. mysql_select_db($db_name$connectionor die("Error. Cannot connect to database");  
  27.   
  28. // generates an IPv4 Internet network address from its Internet standard format (dotted string) representation.  
  29. $visitor_ip = ip2long($_SERVER['REMOTE_ADDR']);  
  30.   
  31. // time() returns INT  
  32. $time = time();  
  33.   
  34. // set Flag to TRUE, if we got a new visitor  
  35. $new_visitor = true;  
  36.   
  37. // update database for returning visitor  
  38. $get_ip = mysql_query("SELECT * FROM " . $db_table . " WHERE visitor_ip=" . $visitor_ip . " LIMIT 1");  
  39. while ($row = mysql_fetch_object($get_ip)) {  
  40.     mysql_query("UPDATE " . $db_table . " SET visitor_time=" . $time . " WHERE visitor_ip=" . $visitor_ip . ""or die(mysql_error());  
  41.     $new_visitor = 0;  
  42. }  
  43.           
  44. // add to database for new visitor  
  45. if ($new_visitor === true) {  
  46.     mysql_query("INSERT INTO " . $db_table . " (visitor_ip, visitor_time) VALUES ('$visitor_ip','$time')"or die(mysql_error());  
  47. }  
  48.   
  49. // done processing the visit, now lets see how many total visitors are online  
  50. $tcheck = time() - $timeframe// (30 = 30 seconds)  
  51. // select visitors that visited our page the last 30 seconds.  
  52. $query = mysql_query("SELECT * FROM " . $db_table . " WHERE visitor_time > $tcheck");  
  53. $onlinenow = mysql_num_rows($query);  
  54.   
  55. // show number of visitors on screen  
  56. if($onlinenow == 1) {  
  57.     echo "currently $onlinenow visitor online";  
  58. else {  
  59.     echo "currently $onlinenow visitors online";  
  60. }  
  61. ?> 


5. HTML for our Ajax periodical visitor counter

save as index.html.
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
  2.     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="nl">  
  4.     <head>  
  5.         <title>Ajax with Prototype: Live update</title>  
  6.         <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />  
  7.         <script type="text/javascript" src="prototype.js"></script>  
  8.         <script type="text/javascript" src="updater.js"></script>  
  9.         <script type="text/javascript">  
  10.         // <![CDATA[ 
  11.         document.observe('dom:loaded', function() { 
  12.             /* 
  13.             first arg   : div to update 
  14.             second arg  : interval to poll in seconds 
  15.             third arg   : file to get data 
  16.             */ 
  17.             var visitorCounter = new updater('counter', 1, 'countVisitors.php'); 
  18.             visitorCounter.getUpdate(); 
  19.         }); 
  20.         // ]]>  
  21.         </script>  
  22.     </head>  
  23.     <body>  
  24.         <h2>Live update current visitor number</h2>  
  25.         <div id="counter">  
  26.           
  27.         </div>  
  28.     </body>  
  29. </html>  
Two things.

1. We call our class by putting a new keyword before it. If you want multiple instances write (var livestock = new updater() and var liveguestbook = new updater()). It takes 3 arguments:

  • divToUpdate: that is the div element we want to update: in our example: counter
  • interval: when the system should check for new visitors measured in seconds
  • file: the file we want to poll, that's our php file, which does the actual checking and gives us the output

2. We make our container div <div id="counter"></div>, where the content can be placed in.

 

 

 
 
Add a Comment:
 
(You must be signed in to comment on an article. Not a member? Click here to register)
   
Title:

Comments: