<?
///////////////////////////////////////////////////////////////////////////////
// GCount CopyRight 2000 Scott Baker (muerte@web-ster.com)
// 
// I wrote GCount with the intention of making a standalone graphical counter 
// program 100% in PHP.  I decided to use a MySQL backend to store counter 
// information because of it great speed and tremendous flexibility
//
// Installation instructions: simply extract gcount.php and gcountinfo.php to
// a location readable by your webserver.  Make sure PHP functionality is 
// enabled and available in this location.  Make sure you have created the 
// necessary tables to hold the counter information in MySql, and created the
// appropriate user rights to those tables.  Specify the user information below
// that has access to those tables.  See the mysql.txt file included with 
// this distribution for the SQL commands necessary to create and give 
// permissions to these tables
//
// Make sure that the included counter1.gif through counter10.gif files are 
// in a readable path by the HTTP server and that the are specified in the 
// configuration options below.
// 
// Once that is done simply reference your counter as follows:
// http://your.domain.com/path/gcount.php?name=gctest&digits=5&typeface=7 
// in your HTML documents.  Change name= digits= and typeface = to whatever 
// you would like your individual counter to display.
//
// To view information that your counter has recieved view that by opening
// the page: http://your.domain.com/path/gcountinfo.php?name=gctest
// This works well if you insert gcount.php as an <img src> and make a link 
// of that image to gcountinfo.php 
//
// I would welcome any advice or criticism of this script at the email address
// mentioned above.  Please don't hesitate to contact me.  I will not however
// offer technical support at this time.  This product is beta, if you feel
// that it is not working the way it should please email me.
//
///////////////////////////////////////////////////////////////////////////////
// Set some global variables that will affect how the counter works without
// specific data for each counter
///////////////////////////////////////////////////////////////////////////////
$default_counter_name = "default";
$default_num_digits = 4;
$default_typeface = 4;
///////////////////////////////////////////////////////////////////////////////
// Database Variables
///////////////////////////////////////////////////////////////////////////////
require('mysql.php');
$dbtable = "webcounter";
///////////////////////////////////////////////////////////////////////////////
// Image format options.  Currently this will ONLY return PNGs files, but in 
// future releases I will modify it to return .GIF and .JPG
// Maxlength is the maximum number of digits you will ever want a counter to 
// return, I recommend leaving it at 10, anything beyond that is frivilous
// Valid options are: 'png' 'jpg' or 'gif'
// Note: relative path to counter strips, must have the trailing '/'
///////////////////////////////////////////////////////////////////////////////
$image_format = "png";
$strip_path = "counters/"; 
$maxlength = 10;
///////////////////////////////////////////////////////////////////////////////
// Addresses to ignore, these addresses with neither be logged or increment the
// counter.  Use this to keep your own visit out of the counter.  This can be
// a full ip address, or partial address (1.2.4 will match anything with that in
// it.)  This format is a regular expression match on the IP  
// Note: This is NOT affected by store format, it will always verify by IP
$ignoreip[0] = '12.111.170.50';
#$ignoreip[1] = '1.2.3.4';
#$ignoreip[2] = '';
///////////////////////////////////////////////////////////////////////////////
// Number of minutes to wait between subsequent visits before increment the 
// visit on the counter.  Setting this option to zero will allow you to 
// increment the counter as much as you'd like.
$visitlimit = 5;
// Would you rather store IP address in the database, or the FQDN of the IP
// address visiting your site.  0 = IP address and 1 = FQDN
$store_format = 1;
///////////////////////////////////////////////////////////////////////////////
// Warning: Actual code begins here, unless you know what you are getting into
// it's probably not a good idea to edit anything beneath here.
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Get the CGI variables
$name = $_GET['name'];
$digits = $_GET['digits'];
$typeface = $_GET['typeface'];
$log = $_GET['log'];
$debug = $_GET['debug'];
$number = $_GET['number'];

if ($_GET['sessiontime']) {
	$visitlimit = $_GET['sessiontime'];
}

$show_all = $_GET['showall'];

$GcountVisit = $_COOKIE['GcountVisit'];

#Get the number of typefaces available in the counter directory
$num_typefaces_installed = num_typefaces($strip_path);
///////////////////////////////////////////////////////////////////////////////

#if ($dir = @opendir("counters/counter??.png")) {
#	print "foo";
#}
#else { die("Sorry couldn't open the counter files"); }

if ($show_all == "true") {
	showall();
	exit;
}

#$digits || $digits = $default_num_digits;
$typeface || $typeface = $default_typeface;
$name || $name = $default_counter_name;

$visitlimit *= 60;

// If there is a limit involved, AND they don't already have the cookie
// So we don't set the cookie if they already have one, or if they're not using
// visit limits
$debugs .= "Visit Limit: $visitlimit seconds<br>\n";
if (!$GcountVisit && $visitlimit != 0) {
	$debugs .= "Cookie not set, setting cookie: $name for $visitlimit seconds<br>\n";
	setcookie('GcountVisit',$name,time()+$visitlimit);
}
elseif ($visitlimit == 0) { $debugs .= "Visit Limit is 0, so we shouldn't ignore this<BR>\n"; }
else { $debugs .= "Cookie is set for '$GcountVisit'<BR>\n"; }

// print "Visit: $GcountVisit<BR>";

// Get the number for this counter, if there is no number it will create the
// counter and return 1
$number || $number = GetCount($name);
$digits || $digits = strlen($number);
$debugs .= "According to GetCount() '$name' has $number hits<br>\n";

if (!$debug) {
	// Create (return) the image, and then send it to the browser appropriately
	$img = CreateCountImg($number,$digits,$typeface);
	SendImage($img);
}
else { 
	print "<code>$debugs</code>";
	$cn = ConnectDB($server,$username,$password,$database) or die("cannot connect to server $server<br> " . mysql_error());
	print "<br>" . explain_table("counterlog",$cn) . "<br>";
	print explain_table("webcounter",$cn) . "<br>";
}

function CreateCountImg($number,$digits,$typeface) {
	global $strip_path;
	global $maxlength;
	global $num_typefaces_installed;
	global $default_typeface;
    
	srand ((double) microtime() * 1000000);
    
	#print "Typeface: $num_typefaces_installed<br>Typeface Selected: $typeface<br>"; 
	#die;

	// Check the typeface for random
	if ($typeface == -1) {
		$typeface = rand(1,$num_typefaces_installed);
	}
	// make sure that it's beween our valid typeface specs 
	else if ( ($typeface < 1) || ($typeface > $num_typefaces_installed) ) {
		// default typeface
		$typeface = $default_typeface;
	}

	#die("|$typeface|");
    
	// Could be used for a random counter
	if ($number == -1) {
		$number = rand(1,9999);
	}
       
	$len = strlen($number);
    
	if ( $len > $maxlength ) {
		Fail(45);
	}
    
	// Make sure the digits and the number are ok together
	if ($len > $digits) {
		$digits = $len;
	}
	elseif ($digits > $maxlength) {
		$digits = $maxlength;
	}
	
	// If there are more digits then the number, pad it with 0s
	if ($len < $digits) {
		// Get the difference (the number of 0s to pad it with)
		$zeropad = $digits - $len;
		$number = str_repeat('0',$zeropad) . $number;
	}
    
	// Create the path to the image and open it for manipulation later
	$pathtoimage = $strip_path . "counter" . $typeface . ".png"; 
    
	#print $pathtoimage;
	#die;

	// Load the counter images to a temp img for later use
	$src_image = ImageCreateFromPNG($pathtoimage);
	if (!$src_image) { die("<P><b><FONT COLOR=\"RED\">NOTE:</FONT></b> It looks like you may not have GD support compiled into PHP") ; }

	// Width in x and height in y
	$width=ImageSX($src_image);
	$height=ImageSY($src_image);
	
	// Width of one digit
	$char_width = $width / 10;
	// Width the total new image is going to be
	$newwidth = $char_width * $digits;
	
	// Create the new (empty) image with given proportions
	$new_image=ImageCreate($newwidth,$height) or Fail(20);

	// Loop through for each digit.  Each digit getting assigned $digit and 
	// being processed accordingly
	for ($i = 0;$i < $digits;$i++) {
		#print "$i";
		$digit = substr($number,$i,1);

		// The X value of where to copy the original char from
		$source_x = $digit * $char_width;
		// Should always be zero because we're only dealing with two dimensional
		// number strips
		$source_y = 0;
		
		// The X value of the destination character
		$dest_x = $i * $char_width;
		$dest_y = 0;
		
		//int ImageCopy (int dst_im, int src_im, int dst_x, int dst_y, int src_x, int src_y, int src_w, int src_h)
		ImageCopy($new_image,$src_image,$dest_x,$dest_y,$source_x,$source_y,$char_width,$height) or Fail(30);
		#print "$new_image,$src_image,$dest_x,$dest_y,$source_x,$source_y,$char_width,$height";
	}

	// free the memory used by the image
	ImageDestroy($src_image);
    
	return($new_image);
}

function Fail($errornum) {
    // Create a blank image 150 x 30
    $new_img = ImageCreate(150,30);
    // Colors for background, and text
    $bg_color = ImageColorAllocate($new_img,255,255,255);
    $text_color = ImageColorAllocate($new_img,0,0,0);
    
    // File the whole thing with a black rectangle
    ImageFilledRectangle($new_img,0,0,150,30,$bg_color);
    // Put this text over the top of it
    ImageString($new_img,1,5,5,"Error: # $errornum",$text_color);
    
    SendImage($new_img);
    // die so we don't continue executing any PHP and mess up the image
    die;
}

// Function currently only sends PNGs, need to modify it to allow it to send
// .GIF of .JPG
function SendImage($img) {
    // We use an expired headed so that the image will not be cached
	Header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");  
	Header("Content-type: image/png");
    // die($img);
	ImagePNG($img);
    // free the memory used by the image
	ImageDestroy($img);
}

function GetCount($CounterName) {    
	include('dbfunction.inc');

	// server variables (should be defined above)
	global $server;
	global $username;
	global $password;
	global $database;
	global $dbtable;
	global $store_format;
	global $log;
	global $visitlimit;
	
	global $name;
	global $GcountVisit;
	global $debug,$debugs;

	// Get the environment variables for log purposes
	$host = getenv('REMOTE_ADDR');
	$agent = getenv('HTTP_USER_AGENT');

	$refer = $_GET['ref'];
	$refer || $refer = getenv('HTTP_REFERER');

	#$fp = fopen('foo.txt','a');
	#fwrite($fp,"Ref: '" . $_GET['ref'] . "'\n");
	#fwrite($fp,"HTTP Ref: '" . getenv('HTTP_REFERER') . "'\n");
	#fwrite($fp,"Chose: '" . $refer . "'\n");
	#fclose($fp);

	// Connect or die
	$cn = ConnectDB($server,$username,$password,$database) or die("cannot connect to server $server<br> " . mysql_error());

	// Check to see whether or not we should log this hit
	$ignore = IgnoreCheck($host,$name,$GcountVisit);
    
	// Return the count if there is one
	$sql = "SELECT CntCount,CntID FROM $dbtable WHERE CntName = '$CounterName'";
	#print "$sql<br>";

	$debugs .= "Getting count for '$CounterName'<BR>\n";
		
	$result = mysql_query($sql);
	$numrows = mysql_num_rows($result);

	// If you return any records there is a count    
	if ( $numrows ) {
		$result = mysql_fetch_array($result);
        
		// Get the ID for this "name" to be used to put in the detailed log
		$logNameID = $result['CntID'];
        
		$counter = $result['CntCount'];

		$debugs .= "'$CounterName' is id #$logNameID and has $counter hits<br>\n";
	}
	// There is no count, lets create one
	else {
		$sql = "INSERT INTO $dbtable (CntCount,CntName) VALUES (0,'$CounterName')";
		#print "$sql<br>";
        
		$debugs .= "'$CounterName' is not in the database, adding the first hit<br>\n";

		mysql_query($sql);
        
		// Get the name id for logging purposes
		$logNameID = mysql_insert_id($cn);

		$debugs .= "First record added: '$CounterName' now has id #$logNameID<br>\n";
        
		// This is the first count (we just created it) make it 1
		$counter = 1;
		// Since this is the first hit we have to log it no matter what
		$ignore = false;
	}
	
	// Update the count with the newer (incremented) count
	$sql = "UPDATE $dbtable SET CntCount = CntCount + 1 WHERE CntName = '$CounterName'";

	#If we're not ignoring the hit (cookie, or known ip) and the visit limit is zero
   if (!$ignore || $visitlimit == 0) {
		@mysql_query($sql) || die(mysql_error()); 
		$debugs .= "Incrementing the number counter by 1<br>\n";
	}
	else { $debugs .= "Ignoring incrementing the number counter<br>\n"; }

	$ip_addr = $host;
	$debugs .= "IP Address of requesting body: $ip_addr<br>\n";
	
	// Convert it to a FQDN if they request it, otherwise it will just stay
	// an IP address.
	if ($store_format != 0) {
		// Convert host to a domain name if possible
		$host = strtolower(gethostbyaddr($ip_addr));
		$debugs .= "Converting to a FQDN for logging purposes: $host<br>\n";
	}

	// If they go directly to the counter (it's not on it's own page);
	if ( $refer == "" ) {
		$refer = "none";
		$debugs .= "There was no referring page (someone viewed the counter raw)<br>\n";
	}
	else { $debugs .= "Referring page: $refer<br>\n"; }

	include("agent.inc");
	list($os,$os_version,$browser,$browser_version) = parseagent($agent);
	//print "$os,$os_version,$browser,$browser_version<P>";

	$debugs .= "Browser detection: '$browser' version: '$browser_version'<br>\n";
	$debugs .= "OS detection: '$os' version: '$os_version'<br>\n";

	// If we get a version, make it part of the OS
	// if ($os_version) { $os = "$os $os_version"; }

	#$sql = "INSERT INTO counterlog (CntID,logHost,logRefer,logBrowser,logBrowserVersion,logOS) VALUES ($logNameID,'$host','$refer','$browser','$browser_version','$os')";
	$sql = "INSERT INTO counterlog (CntID,logHost,logRefer,logBrowser,logBrowserVersion,logOS,logOSVersion) VALUES ($logNameID,'$host','$refer','$browser','$browser_version','$os','$os_version')";

	#die($sql);

	if (!$ignore || $visitlimit == 0) { 
		$debugs .= "Record was not ignored because of a cookie<br>\n";
		if ($log) {
			mysql_query($sql) || die(mysql_error()); 
			$debugs .= "Logged a record in <a href=\"gcountinfo.php?name=$name\">CounterLog</a> for their specific agent<br>\n";
		}
		else { $debugs .= "Logging is off so the record detail (agent) will not be logged<br>\n"; }
	}
	else { $debugs .= "Ignoring inserting the agent record<br>\n"; }
	
	// print "browser: |$browser| version: |$bversion| OS: |$os| |$ie|";
	// die;
		
	return $counter;
}

function IgnoreCheck($compareip,$countername,$cookievalue) {
	global $debugs;
	if ( ( IgnoreIP($compareip) == true ) || ( IgnorePastVisit($countername,$cookievalue) == true ) ) {
		return true;
	}
	return false;
}

function IgnoreIP($compareip) {
	global $ignoreip;
	global $debugs;

	foreach ($ignoreip as $ipaddr) {
		if ($ipaddr != '') { $count++; } 
	}

	$debugs .= "IgnoreIP: comparing against $count known IPs<br>\n";
	if ($count == 0) { return 0; }
	
	$debugs .= "IgnoreIP List: ";
	// Go through all the IPs to ignore and see if it matches
	foreach ($ignoreip as $ipaddr) {
		if (!$ipaddr) { continue; }

		$debugs .= "'$ipaddr' ";
		
		$regexp = preg_quote($ipaddr);
		$regexp = "/$regexp/i";
		// print "Does $compareip match the regexp: $regexp<BR>";
		if ( preg_match($regexp,$compareip) == true ) {
			$debugs .= "<br>\n";
			$debugs .= "IgnoreIp: You are from a known IP address '$ipaddr'<br>\n";
			return true;
		}
	}
	// die("Counted");	
	$debugs .= "<br>\n";
	return false;
}

function IgnorePastVisit($countername,$cookievalue) {

	if ($countername == $cookievalue) {
		$debugs .= "IgnorePastVisit: Cookies were found<br>\n";
		return true;
	}
   return false;
}

function showall() {
	global $num_typefaces_installed;

	print "<span style=\"font-size: 16pt; font-weight: bold; \">Showing: $num_typefaces_installed</span>\n";

	print "<table border=\"1\" cellpadding=\"3\" cellspacing=\"1\">\n";
	for ($i=1;$i<=$num_typefaces_installed;$i++) {
		print "<tr>\n\t<td><b>#$i</b></td><td><img src=\"counters/counter$i.png\"></td>\n</tr>\n";
	}
	print "</table>\n";
}

function explain_table($table,$cn) {
	if (!$cn || !$table) { return 0; }

	$sql = "EXPLAIN $table";
	$rs = mysql_query($sql,$cn);

	if (!@mysql_num_rows($rs)) {
		return "No table by that name: $table";
	}

	$ret .= "<table border=1 cellspacing=1 cellpadding=1 style=\"font-size: 10pt; font-family: verdana;\">\n";
	$ret .= "<tr>
	<td><b>Field</b></td>
	<td><b>Type</b></td>
	<td><b>Null</b></td>
	<td><b>Key</b></td>
	<td><b>Default</b></td>
	<td><b>Extra</b></td>
</tr>\n";
	while ($data = mysql_fetch_array($rs)) {
		$data[0] || $data[0] = "&nbsp;";
		$data[1] || $data[1] = "&nbsp;";
		$data[2] || $data[2] = "&nbsp;";
		$data[3] || $data[3] = "&nbsp;";
		$data[4] || $data[4] = "&nbsp;";
		$data[5] || $data[5] = "&nbsp;";

		$ret .= "<tr>\n\t<td>$data[0]</td>\n\t<td>$data[1]</td>\n\t<td>$data[2]</td>\n\t<td>$data[3]</td>\n\t<td>$data[4]</td>\n\t<td>$data[5]</td>\n</tr>\n";
	}
	$ret .= "</table>";

	return $ret;
}

function num_typefaces($strip_dir) {
	global $debugs;

	$i = 1;
	$spath = dirname($_SERVER["PATH_TRANSLATED"]);
	$path = "$spath/$strip_dir/counter$i.png";


	#print "$path<br />";
	while (is_readable($path)) {

	
		$path = "$spath/$strip_dir/counter$i.png";
		$i++;

		#print "$path<br />";
	}

	#return one less because $i is incremented without the last check
	$ret = $i - 2;

	$debugs .= "There are $ret typefaces installed in '$spath'<br />";

	return ($ret);
}

?>
