Mozilla Community

< Stats Tracking

Proposed PHP scripts[]

Kincera's Script[]

This is the code donated by the wonderful Kincera.

<?php
  //*************************
  //
  // Browser Detection
  //
  //*************************

  $Name = "Unknown";
  $Version = "Unknown";
  $Platform = "Unknown";
  $UserAgent = "Not reported";
  $AOL = false;

  $agent = $_SERVER['HTTP_USER_AGENT'];

  // initialize properties
  $bd['platform'] = "Unknown";
  $bd['browser'] = "Unknown";
  $bd['version'] = "Unknown";
  $UserAgent=$agent;

  // find operating system
  if (eregi("win", $agent))
    $bd['platform'] = "Windows";
  elseif (eregi("mac", $agent))
    $bd['platform'] = "MacIntosh";
  elseif (eregi("linux", $agent))
    $bd['platform'] = "Linux";
  elseif (eregi("OS/2", $agent))
    $bd['platform'] = "OS/2";
  elseif (eregi("BeOS", $agent))
    $bd['platform'] = "BeOS";

  // test for Opera        
  if (eregi("opera",$agent)){
    $val = stristr($agent, "opera");
  if (eregi("/", $val)){
    $val = explode("/",$val);
    $bd['browser'] = $val[0];
    $val = explode(" ",$val[1]);
    $bd['version'] = $val[0];
  }else{
    $val = explode(" ",stristr($val,"opera"));
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];
  }

  // test for WebTV
  }elseif(eregi("webtv",$agent)){
    $val = explode("/",stristr($agent,"webtv"));
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];
        
  // test for MS Internet Explorer version 1
  }elseif(eregi("microsoft internet explorer", $agent)){
    $bd['browser'] = "MSIE";
    $bd['version'] = "1.0";
    $var = stristr($agent, "/");
    if (ereg("308|425|426|474|0b1", $var)){
      $bd['version'] = "1.5";
    }

  // test for NetPositive
  }elseif(eregi("NetPositive", $agent)){
    $val = explode("/",stristr($agent,"NetPositive"));
    $bd['platform'] = "BeOS";
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];

  // test for MS Internet Explorer
  }elseif(eregi("msie",$agent) && !eregi("opera",$agent)){
    $val = explode(" ",stristr($agent,"msie"));
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];
        
  // test for MS Pocket Internet Explorer
  }elseif(eregi("mspie",$agent) || eregi('pocket', $agent)){
    $val = explode(" ",stristr($agent,"mspie"));
    $bd['browser'] = "MSPIE";
    $bd['platform'] = "WindowsCE";
    if (eregi("mspie", $agent))
      $bd['version'] = $val[1];
    else {
      $val = explode("/",$agent);
      $bd['version'] = $val[1];
    }
            
  // test for Galeon
  }elseif(eregi("galeon",$agent)){
    $val = explode(" ",stristr($agent,"galeon"));
    $val = explode("/",$val[0]);
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];
            
  // test for Konqueror
  }elseif(eregi("Konqueror",$agent)){
    $val = explode(" ",stristr($agent,"Konqueror"));
    $val = explode("/",$val[0]);
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];
            
  // test for iCab
  }elseif(eregi("icab",$agent)){
    $val = explode(" ",stristr($agent,"icab"));
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];

  // test for OmniWeb
  }elseif(eregi("omniweb",$agent)){
    $val = explode("/",stristr($agent,"omniweb"));
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];

  // test for Phoenix
  }elseif(eregi("Phoenix", $agent)){
    $bd['browser'] = "Phoenix";
    $val = explode("/", stristr($agent,"Phoenix/"));
    $bd['version'] = $val[1];

  // test for Firebird
  }elseif(eregi("firebird", $agent)){
    $bd['browser']="Firebird";
    $val = stristr($agent, "Firebird");
    $val = explode("/",$val);
    $bd['version'] = $val[1];
            
  // test for Firefox
  }elseif(eregi("Firefox", $agent)){
    $bd['browser']="Firefox";
    $val = stristr($agent, "Firefox");
    $val = explode("/",$val);
    $bd['version'] = $val[1];
            
  // test for Mozilla Alpha/Beta Versions
  }elseif(eregi("mozilla",$agent) && 
    eregi("rv:[0-9].[0-9][a-b]",$agent) && !eregi("netscape",$agent)){
    $bd['browser'] = "Mozilla";
    $val = explode(" ",stristr($agent,"rv:"));
    eregi("rv:[0-9].[0-9][a-b]",$agent,$val);
    $bd['version'] = str_replace("rv:","",$val[0]);
            
  // test for Mozilla Stable Versions
  }elseif(eregi("mozilla",$agent) &&
    eregi("rv:[0-9]\.[0-9]",$agent) && !eregi("netscape",$agent)){
    $bd['browser'] = "Mozilla";
    $val = explode(" ",stristr($agent,"rv:"));
    eregi("rv:[0-9]\.[0-9]\.[0-9]",$agent,$val);
    $bd['version'] = str_replace("rv:","",$val[0]);
        
  // test for Lynx & Amaya
  }elseif(eregi("libwww", $agent)){
    if (eregi("amaya", $agent)){
      $val = explode("/",stristr($agent,"amaya"));
      $bd['browser'] = "Amaya";
      $val = explode(" ", $val[1]);
      $bd['version'] = $val[0];
    } else {
      $val = explode("/",$agent);
      $bd['browser'] = "Lynx";
      $bd['version'] = $val[1];
    }
        
  // test for Safari
  }elseif(eregi("safari", $agent)){
    $bd['browser'] = "Safari";
    $bd['version'] = "";

  // remaining two tests are for Netscape
  }elseif(eregi("netscape",$agent)){
    $val = explode(" ",stristr($agent,"netscape"));
    $val = explode("/",$val[0]);
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];
  }elseif(eregi("mozilla",$agent) && !eregi("rv:[0-9]\.[0-9]\.[0-9]",$agent)){
    $val = explode(" ",stristr($agent,"mozilla"));
    $val = explode("/",$val[0]);
    $bd['browser'] = "Netscape";
    $bd['version'] = $val[1];
  }
        
  // clean up extraneous garbage that may be in the name
  $bd['browser'] = ereg_replace("[^a-z,A-Z]", "", $bd['browser']);
  // clean up extraneous garbage that may be in the version        
  $bd['version'] = ereg_replace("[^0-9,.,a-z,A-Z]", "", $bd['version']);

  // check for AOL
  if (eregi("AOL", $agent)){
    $var = stristr($agent, "AOL");
    $var = explode(" ", $var);
    $bd['aol'] = ereg_replace("[^0-9,.,a-z,A-Z]", "", $var[1]);
  }
        
  // finally assign our properties
  $Name = $bd['browser'];
  $Version = $bd['version'];
  $Platform = $bd['platform'];
  $AOL = $bd['aol'];

  $ip_addr=$HTTP_SERVER_VARS["REMOTE_ADDR"];

  //*************************
  //
  // Insert Database Connection Information
  //
  //*************************

  $username="your_username";
  $password="your_password";
  $database="your_database";

  mysql_connect(localhost,$username,$password);
  @mysql_select_db($database) or die( "Unable to select database");
        
  //Update stats
  $sql = "INSERT INTO `your_table_name` ( `id` , `date` , `time` , `browser` , `os` , `ip` ) "
        . " VALUES ( '', CURDATE( ) , CURTIME( ) , '" . $Name . " " . $Version . "', '" . $Platform
	. "', '" . $ip_addr . "' )";
        mysql_query($sql);
?>

Any alterations, please leave the original code intact and format your proposed alterations so as to keep them obvious. Any discussion, please use the discussion page.

Thanks must go out again to Kincera.

A-dead-trousers' Script[]

This script has been submitted by A-dead-trousers. A working version of it can bee seen in action at http://universe.dotgeek.org/counter/index.php

The source code can also been downloaded from there as well.

This script includes images which may be used by webmasters. Feel free to comment. --awrowe 09:39, 2 Apr 2005 (EST)

hi! Just forgot to mention that I used the ua_script by Kincera. I'm going to insert a notice in the readme file! --A-dead-trousers 16:47, 3 Apr 2005 (CEST)

Proposed Additions[]

"Transparent" script behind image[]

The following would be added to the top of any script that doesn't return information to the browser. This would prevent the user from having to waste precious miliseconds while the rest of the script executes.

<?php
  //*************************
  //
  // Place image
  //
  //*************************

  $imgname=$_GET['q'];                        //get the value of "q" from URL
                                              //ie: ...php?q=imagename

  $file_ext = array_pop(explode(".",$imgname));  //Gets the file extension

  //NOTE: Whenever you change the header, you MUST ensure that there are 
  //no extra characters being sent to the user agent.  This includes whitespace
  //before and after the php opening and closing tags.

  header("Content-type:  image/".$file_ext);  //Changes whether the browser
                                              //expects text or an image.

  include($imgname);                          //sends the image to the user agent

...rest of script follows

Submitted by Adam A. (Ghedipunk)

This addition would allow the script to be processed every time that the selected image is loaded.

An example of how a webmaster would include this into a page is as follows:

<img src="ua_script.php?q=logo.gif" alt="My Logo">

Sorry, but absolutely useless, cause php won't send anything before it is done! The stream output of php isn't recommended yet because of side effects and is deactivated by default! (Don't know any Webhoster where it is activated) --A-dead-trousers 13:57, 4 Apr 2005 (CEST)

Proposed Changes[]

Change $database variable for compatibility[]

I propose to change "$database" to something that wouldn't be confused as a different global variable found in different server configurations... for example, "$sfx_statcount_db" or more simply, "$db", since people have had problems with the original variable name. (Submitted by Ghedipunk before he learned how to timestamp)

Agreed. Perhaps we should go through to find any other variables which CMS' might find confusing also.--awrowe 10:47, 1 Apr 2005 (EST)

Use switch() instead of if() where possible[]

To make the code cleaner, perhaps faster (I don't know the specific speeds of the code), a main "switch" statement should be used instead of bunches of "if" statements.

  switch($agent){
    case "opera":
     $val = stristr($agent, "opera");
     if (eregi("/", $val)){
      $val = explode("/",$val);
      $bd['browser'] = $val[0];
      $val = explode(" ",$val[1]);
      $bd['version'] = $val[0];
    }else{
      $val = explode(" ",stristr($val,"opera"));
      $bd['browser'] = $val[0];
      $bd['version'] = $val[1];
    }
    break;

   case "webtv":
    $val = explode("/",stristr($agent,"webtv"));
    $bd['browser'] = $val[0];
    $bd['version'] = $val[1];
    break;

   /* and so on */
  }
I'm not sure if this code is any faster, although I have known it to be more manageable rather than using tons of if statements.--codyrockx 16:07, 1 Apr 2005 (PST)
This looks fantastic. If you wouldn't mind, would it be possible for you to complete it, or if not, would you mind if anyone else did? Thanks very much for putting it in! --awrowe 07:46, 2 Apr 2005 (EST)
I don't think this will work, cause $agent will be set during the if-statments and can't be checked by a switch structure --A-dead-trousers 13:30, 4 Apr 2005 (CEST)

Proposed Alternatives[]

File storage instead of database[]

This is a possible alternative that could be presented to webmasters who do not have MySQL available, or who do not want one of their databases used up. This script is meant to replace the database access method in Kincera's script, and all of the changes that I made fall right under the AOL detection block of code.

Please note that I'm assuming the script will be placed in the document root of the web server, and referencing a file that is one directory above the document root... this way, people can't just type out "www.yourserver.com/stats.txt", and see your stats... they'd already need administrative privileges to your site before viewing this file.

        
  // get date and time
  $d = getdate();
  $secs = time();
  $t = seconds_to_time($secs);
        
  // finally assign our properties
  $Name = $bd['browser'];
  $Version = $bd['version'];
  $Platform = $bd['platform'];
  $AOL = $bd['aol'];
  $thisdate = $d['month'] . "-" . $d['mday'] . "-" . $d['year'];
  $thistime = $t['hours'] . ":" . $t['minutes'] . ":" . $t['seconds'];

  $ip_addr=$HTTP_SERVER_VARS["REMOTE_ADDR"];

  //********************
  //
  // Write to file
  //
  //********************
  
  if (file_exists('../stats.txt') ) {
    $statfile = fopen('../stats.txt', r);
    $filecontents = fread($statfile, filesize('../stats.txt'));
    fclose($statfile);
    $filecontents = $filecontents . "
" . $thisdate . " " . $thistime . " " . $Name . " " . $Version . " " . $Platform . " " . $ip_addr;
  
  } else {
    $filecontents = "Unconfigured UA Stats datafile -- For a Spread Firefox project

" . $thisdate . " " . $thistime . " " . $Name . " " . $Version . " " . $Platform . " " . $ip_addr;
  }
  
  $statfile = fopen('../stats.txt', w);
  fwrite($statfile, $filecontents);
  fclose($statfile);
  
  //********************
  //
  // Function to make time more human readable
  //
  //********************

function seconds_to_time ($seconds) {
   $retArr['years'] = floor ($seconds / 31536000);
   if ($retArr['years'] > 1) $seconds -= $retArr['years'] * 31536000;

   $retArr['days'] = floor ($seconds / 86400);
   if ($retArr['days'] > 1) $seconds -= $retArr['days'] * 86400;
  
   $retArr['hours'] = floor ($seconds / 3600);
   if ($retArr['hours'] > 1) $seconds -= $retArr['hours'] * 3600;

   $retArr['minutes'] = floor ($seconds / 60);   
   if ($retArr['minutes'] > 1) $seconds -= $retArr['minutes'] * 60;
  
   $retArr['seconds'] = $seconds;

   return $retArr;
}
?>

Here is the output from my tests so far: (I'd include AOL, but the AOL client ignores the hosts file, and I haven't uploaded this file to a live server for testing yet)

Unconfigured UA Stats datafile -- For a Spread Firefox project

April-2-2005 16:12:29 Firefox 1.0.2 Windows 127.0.0.1
April-2-2005 16:12:33 Firefox 1.0.2 Windows 127.0.0.1
April-2-2005 16:12:35 Firefox 1.0.2 Windows 127.0.0.1
April-2-2005 16:12:52 MSIE 6.0 Windows 127.0.0.1
April-2-2005 16:12:57 MSIE 6.0 Windows 127.0.0.1

If anybody is wondering why I placed "Unconfigured UA stats..." on the top line, it is because I eventually want to make an installation script that allows a webmaster to choose their type of storage method (file, MySQL database, some other database, etc.), as well as the method that will be used to push these stats up to the main server (SMTP, RSS, etc.).

All times are GMT because that's why my server runs on.

Ghedipunk 10:32, 2 Apr 2005 (EST)

Will be included in my next version! Will only work at low traffic (not recommended for central servers), cause of concurrent access to the file and filelocks! --A-dead-trousers 13:44, 4 Apr 2005 (CEST)
Possible workaround for filelocks: Using BerkleyDB which runs on a filebase and just post the DB-File --A-dead-trousers 12:25, 7 Apr 2005 (CEST)