Free, tested & ready to use examples!

AJAX web-counter for widgets

Modern widget engines (Apple Dashboard, Yahoo!Widgets, Windows Vista Sidebar) use XML transport (AJAX) to constantly update various information(like weather, stocks, etc) from web. In this article there is a source of trivial php web-counter which collects stats and outputs number of page views(hits) and visitors(in fact, unique hosts) since midnight as XML file. There is also our special AeCounter Dashboard Widget (and it's sources) which receive these xml-statistics (with the help of XmlHttpRequest object) and displays numbers on a little nice panel.
  • Counter: any hosting with any sane version of PHP and MySQL
  • Widget: Apple Dashboard (Mac OS X 10.4)

First you need in set up server part: our xml-based php web-counter.

The counter uses two MySQL tables: ae_counter_day ( stores number of hits and current day ), ae_counter_hosts (stores all hosts for a current day). These tables are quite trivial. In fact, we could use only one table(ae_counter_hosts), but since we wanted our counter to remove old unnecessary data (for previous day) we created table which stores current day value.

Execute this SQL queries to create statistics tables:

source code: SQL / MySQL
CREATE TABLE `ae_counter_day` (

  `day` date NOT NULL DEFAULT '0000-00-00',
  `hits` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY  (`day`)

CREATE TABLE `ae_counter_hosts` (
  `day` date NOT NULL DEFAULT '0000-00-00',
  `ip` char(16) NOT NULL DEFAULT '',
  KEY `ip` (`ip`),
  KEY `day` (`day`)


PHP web-counter has two modes of operation: counter (add +1 hit to hits to ae_counter_day row and IP address to ae_counter_hosts table) and 'xml results output' which provides output to XmlHttpRequest-based application (widget).

source code: PHP

$db_host 'localhost';     // don't forget to change 
$db_user 'db-username';   // to your database 
$db_pwd 'db-password';    // settings 
$database 'database name';

if (!
"Can't connect to database");

if (!
"Can't select database");

if (isset(
// Sending results to Widget

$result mysql_query("SELECT count(DISTINCT ip) 
                             FROM ae_counter_hosts 
                            WHERE day = CURDATE()"

// count(*) function will always return at least one row 
list($hosts) = mysql_fetch_row($result);

$result mysql_query("SELECT hits  
                             FROM ae_counter_day 
                            WHERE day = CURDATE()"

    if (
mysql_num_rows($result) == 0// no stat for current day
$hits 0;
$hits) = mysql_fetch_row($result);


// Turn off any caching 
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
// Turn off any caching 

header("Content-type: text/xml");
// XML Content-type
echo '<?xml version="1.0"?>';

// START counter
// you may copy this code directly to your site scripts to collects stats
$add_host 0;

mysql_query("INSERT INTO ae_counter_hosts SET day=CURDATE(), ip='$ip'");

mysql_query("UPDATE ae_counter_day SET hits=hits+1 WHERE day=CURDATE()");
if (
mysql_affected_rows() == 0// no rows affected, no record for CURDATE()
mysql_query("INSERT INTO ae_counter_day SET hits=1, day=CURDATE()");
mysql_query("DELETE FROM ae_counter_day WHERE day <> CURDATE()");
// clean up: remove above line if you want to keep stats 
mysql_query("DELETE FROM ae_counter_hosts WHERE day <> CURDATE()");
// clean up: removing old hosts
// END counter 

if (isset($_GET['gif']))
// outputting transparent 1x1 gif
header('Content-type: image/gif');

Don't forget to create sql-tables (execute CREATE TABLE queries above) and change variables ($db_host, $db_user, $db_pwd, $database) to your MySQL / database settings.

There are two techniques of embedding this counter to your web-pages:

  • Easy: Embed as image. As you may note, there is a code for blank 1x1 gif outputting at the end of script. So, you may embed it as an image in <IMG... tag.
source code: HTML
<!-- change /path/to/saved/counter.php to real path of counter script -->
<img src="/path/to/saved/counter.php?gif=1" width="1" height="1" border="0" alt="" />
  • Expert: Embed counter as PHP code. Use include "script-file-name.php"; in your code(we assume that you're already using PHP in your site pages). You can also remove database connection code (mysql_connect and mysql_select_db) if your php code has it's own database connection. In fact, you should better copy to your scripts code between // START counter and // END counter (only collecting stats) to avoid reaction to 'show' and 'gif' GET-queries.

To check your web-counter installation, visit web-page where you've embedded web-counter. Then navigate to http://your-web-site-url/path/counter.php?show=1 (place at your web site where you've saved counter script) and check it's output. The script should output XML file like:

source code: XML


Try visiting your site again and checking counter statistics afterwards.

If everything is fine, you may download our Apple Dashboard Widget, insert your counter url at it's preferences(widget back) and see your web-page statistics at dashboard. 'AeCounter' widget will update statistics every 15 minutes.

Mac OS X 10.4 Tiger is required. If you're using Safari, click the download link. When the widget download is complete, show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it. If you're using a browser other than Safari, click the download link. When the widget download is complete, unarchive it and place it in /Library/Widgets/

Additionally, we provide sources of this widget as a Dashcode project.

You may also download PHP and MySQL sources for this article.

Feedbacks on this article are gladly accepted.

  • Counter xml statistics is not password protected. Anyone who known your counter URL will be able to get number of hits/hosts since midnight. Keep your counter-url secret.
  • AnyExample's counter at http://www.anyexample/files/ajax/counter.php is not really counter ;-)
  • Counter :: PHP 4.4.4 :: MySQL 4.10
  • Counter :: PHP 5.2 :: MySQL 5
  • Widget :: Mac OS X 10.4.8 Apple Dashboard

© AnyExample 2010-2013
License | Privacy | Contact