Non-obstrusive Hit Counter

Sometimes you want to measure hits in a non-obstrusive way. In my case I wanted to track how often handbooks which are delivered as hardcopy HTML files at work are actually viewed.

The (old) but still good solution for that is the combination of appending an image via Jquery to the DOM of the document. Adding an image instead of doing a AJAX-call prevents the potential issue of security restrictions like cross-domain calls. Being called when the original document is already loaded doesn’t impact the usability and loadtimes of the page.

That’s how the Javascript call looks like:

$(document).ready(function() {
$("body").append("<img src='http://www.sebastian-hodapp.de/index.php/count_hit/"+$uid+"'>");
}

The source-URL is actually the URL of a webservice including an ID parameter to identify the document. At server side I’m often using the micro PHP framework SLIM. Based on that I’ve written my own platform for easy webservice provisioning and database access via the database abstraction library ADOdb.

The trick here is to return an image asap to again minimize latency and do the database work of storing the access information later. To minimize traffic only a transparent GIF of 1×1 pixel is being returned. To minimize server load/operations the image is returned „on-the-fly“.

$app->get("/count_hit/:uid", function ($uid) use ($app, $DB) {
  ignore_user_abort(true); 
  set_time_limit(20); 
  ob_end_clean(); 
  header('Connection: close');
  ignore_user_abort();
  ob_start();
  header('Content-Type: image/gif');
  header("Content-Length: 49");
  echo pack('H*', '47494638396101000100910000000000ffffffffffff00000021f90405140002002c00000000010001000002025401003b');
  ob_end_flush();
  flush();
  
  $sql = "INSERT INTO system_hits VALUES (CURRENT_TIMESTAMP, ?)";
  $DB->execute($sql, array($uid));
});

See this as insperation an snippet. Of cause there should be some error handling etc. on server side. I left this out here to show the basic principle.