<?php
/**
 * Simpel statistieken systeem.
 *
 * De echte detectie wordt gedaan door de code vanaf detect_os_browser
 * tot aan $table = new table; Als je dus de detectie zelf in een include
 * wilt zetten, heb je die code nodig.
 *
 * Voor het weergeven is de andere code nodig, je kunt als je wilt
 * de mysql queries makkelijk aanpassen.
 *
 * Benodigde MySQL query:
 *
 * CREATE TABLE QS_stats (
 *  date_visit date NOT NULL default '0000-00-00',
 *  ip int(4) unsigned NOT NULL default '0',
 *  hits int(3) unsigned NOT NULL default '0',
 *  browser varchar(255) NOT NULL default '',
 *  os varchar(255) NOT NULL default '',
 *  user_agent varchar(255) NOT NULL default ''
 * ) TYPE=MyISAM;
 *
 * @author JeXuS <jexus@jexus.net>
 * @package JStats
 */

// error reporting omhoog
error_reporting (E_ALL);

// conectie met de mysql server maken
mysql_connect ('', '', '');
// database selecteren
mysql_select_db ('');

/**
 * Statistieken tabel class
 *
 * LET OP: dit is niet bedoeld als echt te gebruiken class
 * ik had geen zin om moeilijk te gaan doen;)
 *
 * @author JeXuS <jexus@jexus.net>
 * @package stats
 */
class stats_table
{
    /**
     * De data uit de tabel
     *
     * @var array
     */
	var $table = array ();

	/**
	 * Voeg data toe aan de tabel
	 *
	 * @param string $title
	 * @param mixed $data
	 */
	function add_data ($title = '', $data = '')
	{
	    // check of er misschien een spacer wordt toegevoegd
		if ($title == '' && $data == '')
		{
		    // als dit zo is, voegen we een 0 toe
			$this->table[] = 0;
		}
		else
		{
		    // anders voegen we de data gewoon toe
			$this->table[$title] = $data;
		}
	}

	/**
	 * Output de tabel
	 *
	 * $need_css moet true zijn als je CSS erbij wilt hebben
	 *
	 * @param boolean $need_css
	 */
	function output ($need_css = true)
	{
	    // initialisatie
		$text = '';

		// indien we CSS willen
		if ($need_css)
		{
		    // voegen we deze toe
			$text .= '<style type="text/css"> body, table, tr, td, th { font: 11px Verdana, Arial; } th { font-weight: bold; } td { width: 50%; } td.value { text-align: right; } </style>' . "\n";
		}

		// begin met de tabel
		$text .= '<table cellpadding="0" cellspacing="2">' . "\n";
		// loop door de data heen
		foreach ($this->table as $title => $data)
		{
		    // indien we een spacer vinden
			if ($data === 0)
			{
			    // een lege rij toevoegen
				$text .= '   <tr><td colspan="2">&nbsp;</td></tr>' . "\n";
			}
			// indien het geen array is
			elseif (!is_array ($data))
			{
			    // het is enkele data, gewoon toevoegen
				$text .= '   <tr><td>' . $title . '</td><td class="value"><i>' . $data . '</i></td></tr>' . "\n";
			}
			// anders ...
			else
			{
			    // header toevoegen
				$text .= '   <tr><th colspan="2">' . $title . '</th></tr>' . "\n";
				foreach ($data as $k => $v)
				{
				    // data toevoegen
					$text .= '   <tr><td>' . $k . '</td><td class="value"><i>' . $v . '</i></td></tr>' . "\n";
				}
			}
		}

		//tabel afsluiten
		$text .= '</table>';
		// en outputten
		echo $text;
	}
}

/**
 * Detectie van OS en browser
 *
 * @return array
 */
function detect_os_browser ()
{
    // include het bestand
	require 'agent.inc.php';
    // we gebruiken de user agent
	$agent = &$_SERVER['HTTP_USER_AGENT'];

	// dit returnen we standaard
	$return = array ('Unknown', 'Unknown');

	// loop door de mogelijk OS's
	foreach ($os as $key => $name)
	{
	    // als we matchen
		if (preg_match ('/' . $key . '/i', $agent))
		{
		    // voeren we het in de return
			$return[0] = $name;
			// en stoppen we de loop
			break;
		}
	}

	// in $m komt het versienummer te staan
	$m = array ();
	// indien we MS IE matchen, en geen van de andere, hebben we Internet Explorer
	// te pakken
	if (preg_match ('~msie[/\sa-z]*([\d.]*)~i', $agent, $m) && !preg_match ('/webtv|omniweb|opera/i', $agent))
	{
		$return[1] = 'MS Internet Explorer ' . $m[1];
	}
	// als we netscape matchen, idem...
	elseif (preg_match ('/netscape.?\/([\d.]*)/i', $agent, $m))
	{
		$return[1] = 'Netscape ' . $m[1];
	}
	// en hetzelfde voor mozilla (ook netscape)
	elseif (preg_match ('/mozilla[\/\sa-z]*([\d.]*)/i', $agent, $m) && !preg_match ('/gecko|compatible|opera|galeon|safari/i', $agent))
	{
		$return[1] = 'Netscape ' . $m[1];
	}
	// anders (voor de andere browsers)
	else
	{
	    // loopen...
		foreach ($browsers as $key => $name)
		{
		    // als we de browser matchen
			if (preg_match ('/' . $key . '.?\/([\d.]*)/i', $agent, $m))
			{
			    // voegen we het in de return
				$return[1] = $name . ' ' . $m[1];
				// en stoppen we de loop
				break;
			}
		}
	}

	// ten slotte returnen we;)
	return $return;
}

// vind de OS en BROWSER
list ($os, $browser) = detect_os_browser ();

// update de tabel voor de huidige bezoeker
$sql = "UPDATE QS_stats SET hits = hits + 1 WHERE date_visit = CURDATE() AND ip = INET_ATON('%s') AND browser = '%s' AND os = '%s'";
// maak het extra veilig met mysql_real_escape_string
$sql = sprintf (
	$sql,
	mysql_real_escape_string ($_SERVER['REMOTE_ADDR']),
	mysql_real_escape_string ($browser),
	mysql_real_escape_string ($os)
);
// voer de query uit
mysql_query ($sql) or die (mysql_error ());
// als we niks hebben geupdate...
if (!mysql_affected_rows ())
{
    // moeten we de bezoeker in het systeem invoeren
	$sql = "INSERT INTO QS_stats (date_visit, ip, hits, browser, os) VALUES(CURDATE(), INET_ATON('%s'), 1, '%s', '%s')";
	$sql = sprintf (
		$sql,
		mysql_real_escape_string ($_SERVER['REMOTE_ADDR']),
		mysql_real_escape_string ($browser),
		mysql_real_escape_string ($os)
	);
	mysql_query ($sql);
}

// initialiseer de stats_table class
$table = new stats_table;

/** VANDAAG */

// haal het aantaal unieke bezoekers van vandaag op (uniek op IP, OS en BROWSER)
$result = mysql_result (mysql_query ('SELECT COUNT(DISTINCT ip, os, browser) FROM QS_stats WHERE date_visit = CURDATE()'), 0);
$table->add_data ('Unieke bezoekers deze dag', $result);

// haal het aantal hits op van vandaag
$result = mysql_result (mysql_query ('SELECT SUM(hits) FROM QS_stats WHERE date_visit = CURDATE()'), 0);
$table->add_data ('Hits deze dag', $result);

// voeg een lege rij toe
$table->add_data ();

/** TOTAAL */

// totaal unieke bezoekers
$totalunique = mysql_result (mysql_query ('SELECT COUNT(DISTINCT ip, os, browser) FROM QS_stats'), 0);
$table->add_data ('Unieke bezoekers totaal', $totalunique);

// totaal aantal hits
$totalhits = mysql_result (mysql_query ('SELECT SUM(hits) FROM QS_stats'), 0);
$table->add_data ('Hits totaal', $totalhits);

// en weer een lege rij
$table->add_data ();

/** DEZE MAAND */

// unieke bezoekers deze maand
$result = mysql_result (mysql_query ('SELECT COUNT(DISTINCT ip, os, browser) FROM QS_stats WHERE date_visit BETWEEN DATE_SUB(CURDATE(), INTERVAL 1 MONTH) AND CURDATE()'), 0);
$table->add_data ('Unieke bezoekers deze week', $result);

// en weer hits deze maand
$totalhits = mysql_result (mysql_query ('SELECT SUM(hits) FROM QS_stats WHERE date_visit BETWEEN DATE_SUB(CURDATE(), INTERVAL 1 MONTH) AND CURDATE()'), 0);
$table->add_data ('Hits deze week', $totalhits);

// lege rij
$table->add_data ();

/** OPERATING SYSTEMS */

// Nu halen we OS's op, per unieke gebruiker telt een OS 1 keer
$sql = 'SELECT COUNT(DISTINCT ip, browser, os) AS total, os FROM QS_stats GROUP BY os ORDER BY total DESC, LENGTH(os) DESC';
$result = mysql_query ($sql) or die (mysql_error ());
$rows = array ();
while ($row = mysql_fetch_row ($result))
{
	$rows[$row[1]] = number_format ($row[0] / $totalunique * 100, 2) . '%';
}

// voer de OS's in
$table->add_data ('Operating systems', $rows);
// en een lege rij
$table->add_data ();

/** BROWSER */

// hier geldt hetzelfde als voor OS's
$sql = 'SELECT COUNT(DISTINCT ip, browser, os) AS total, browser FROM QS_stats GROUP BY browser ORDER BY total DESC, LENGTH(browser) DESC';
$result = mysql_query ($sql) or die (mysql_error ());
$rows = array ();
while ($row = mysql_fetch_row ($result))
{
	$rows[$row[1]] = number_format ($row[0] / $totalunique * 100, 2) . '%';
}

$table->add_data ('Browsers', $rows);

// en hier outputten we;)
$table->output ();

agent.inc.php
<?php
/**
 * Deze lijsten komen uit AWStats
 */

$browsers = array (
    'icab'          => 'iCab',
    'go!zilla'      => 'Go!Zilla',
    'konqueror'     => 'Konqueror',
    'links'         => 'Links',
    'lynx'          => 'Lynx',
    'omniweb'       => 'OmniWeb',
    'opera'         => 'Opera',
    'msie 6\.0'     => 'Microsoft Internet Explorer 6.0',
    'apachebench'   => 'ApacheBench',
    'wget'          => 'Wget',
    '22acidownload' => '22AciDownload',
    'aol\\-iweng'   => 'AOL-Iweng',
    'amaya'         => 'Amaya',
    'amigavoyager'  => 'AmigaVoyager',
    'aweb'          => 'AWeb',
    'bpftp'         => 'BPFTP',
    'chimera'       => 'Chimera',
    'cyberdog' 		=> 'Cyberdog',
    'dillo' 		=> 'Dillo',
    'dreamcast' 	=> 'Dreamcast',
    'downloadagent' => 'DownloadAgent',
    'ecatch' 		=> 'eCatch',
    'emailsiphon' 	=> 'EmailSiphon',
    'encompass'		=> 'Encompass',
    'friendlyspider' => 'FriendlySpider',
    'fresco' 		=> 'ANT Fresco',
    'galeon'		=> 'Galeon',
    'getright' 		=> 'GetRight',
    'headdump' 		=> 'HeadDump',
    'hotjava' 		=> 'Sun HotJava',
    'ibrowse' 		=> 'IBrowse',
    'intergo' 		=> 'InterGO',
    'k-meleon' 		=> 'K-Meleon',
    'linemodebrowser' => 'W3C Line Mode Browser',
    'lotus-notes' 	=> 'Lotus Notes web client',
    'macweb' 		=> 'MacWeb',
    'multizilla' 	=> 'MultiZilla',
    'ncsa_mosaic' 	=> 'NCSA Mosaic',
    'netpositive' 	=> 'NetPositive',
    'nutscrape' 	=> 'Nutscrape',
    'msfrontpageexpress' => 'MS FrontPage Express',
    'phoenix' 		=> 'Phoenix',
    'firebird' 		=> 'Mozilla Firebird',
    'firefox' 		=> 'Mozilla Firefox',
    'safari' 		=> 'Safari',
    'tzgeturl' 		=> 'TzGetURL',
    'viking' 		=> 'Viking',
    'webfetcher' 	=> 'WebFetcher',
    'webexplorer' 	=> 'IBM-WebExplorer',
    'webmirror' 	=> 'WebMirror',
    'webvcr' 		=> 'WebVCR',
    'teleport' 		=> 'TelePort Pro',
    'webcapture' 	=> 'Acrobat',
    'webcopier' 	=> 'WebCopier',
    'real' 			=> 'RealAudio or compatible (media player)',
    'winamp' 		=> 'WinAmp (media player)',
    'windows-media-player' => 'Windows Media Player (media player)',
    'audion' 		=> 'Audion (media player)',
    'freeamp' 		=> 'FreeAmp (media player)',
    'itunes' 		=> 'Apple iTunes (media player)',
    'jetaudio' 		=> 'JetAudio (media player)',
    'mint_audio' 	=> 'Mint Audio (media player)',
    'mpg123' 		=> 'mpg123 (media player)',
    'nsplayer' 		=> 'NetShow Player (media player)',
    'sonique' 		=> 'Sonique (media player)',
    'uplayer' 		=> 'Ultra Player (media player)',
    'xmms' 			=> 'XMMS (media player)',
    'xaudio' 		=> 'Some XAudio Engine based MPEG player (media player)',
    'alcatel' 		=> 'Alcatel Browser (PDA/Phone browser)',
    'ericsson' 		=> 'Ericsson Browser (PDA/Phone browser)',
    'mot-' 			=> 'Motorola Browser (PDA/Phone browser)',
    'nokia' 		=> 'Nokia Browser (PDA/Phone browser)',
    'panasonic' 	=> 'Panasonic Browser (PDA/Phone browser)',
    'philips' 		=> 'Philips Browser (PDA/Phone browser)',
    'sonyericsson' 	=> 'Sony/Ericsson Browser (PDA/Phone browser)',
    'mmef' 			=> 'Microsoft Mobile Explorer (PDA/Phone browser)',
    'mspie' 		=> 'MS Pocket Internet Explorer (PDA/Phone browser)',
    'wapalizer' 	=> 'WAPalizer (PDA/Phone browser)',
    'wapsilon' 		=> 'WAPsilon (PDA/Phone browser)',
    'webcollage' 	=> 'WebCollage (PDA/Phone browser)',
    'up\.' 			=> 'UP.Browser (PDA/Phone browser)',
    'docomo' 		=> 'I-Mode phone (PDA/Phone browser)',
    'portalmmm' 	=> 'I-Mode phone (PDA/Phone browser)',
    'webtv' 		=> 'WebTV browser',
    'csscheck' 		=> 'WDG CSS Validator',
    'w3m' 			=> 'w3m',
    'w3c_css_validator' => 'W3C CSS Validator',
    'w3c_validator' => 'W3C HTML Validator',
    'wdg_validator' => 'WDG HTML Validator',
    'webzip' 		=> 'WebZIP',
    'staroffice' 	=> 'StarOffice',
    'mozilla' 		=> 'Mozilla',
    'libwww' 		=> 'LibWWW',
);

$os = array (
    'windows nt 6\.0' => 'Windows Vista',
    'windows nt 5\.2' => 'Windows 2003',
    'windows nt 5\.2; WOW64' => 'Windows XP 64 bits',
    'windows nt 5\.0' => 'Windows 2000',
    'windows nt 5\.1' => 'Windows XP',
    'winnt'           => 'Windows NT',
    'winnt 4\.0'      => 'Windows NT',
    'windows 98'      => 'Windows 98',
    'win98'           => 'Windows 98',
    'windows 95'      => 'Windows 95',
    'win95'           => 'Windows 95',
    'sunos'           => 'Sun Solaris',
    'freebsd'         => 'FreeBSD',
    'ppc'             => 'Macintosh',
    'mac os x'        => 'Mac OS X',
    'linux'           => 'Linux',
    'debian'          => 'Debian',
    'beos'            => 'BeOS',
    'winnt4\.0'       => 'Windows NT 4.0',
    'apachebench'     => 'ApacheBench',
    'aix'             => 'AIX',
    'irix'            => 'Irix',
    'osf'             => 'DEC OSF',
    'hp-ux'           => 'HP-UX',
    'netbsd'          => 'NetBSD',
    'bsdi'            => 'BSDi',
    'openbsd'         => 'OpenBSD',
    'gnu'             => 'GNU/Linux',
    'unix'            => 'Unknown Unix system'
);