MorkaLork Development

Interesting stuff I've picked up over the years...

PHP/Visit Counter

2009-04-16 18:13:38 | 181 views | php create visit counter visitors tutorial mysql

Introduction:


Sometimes you want to know how many visitors your site has, either to see for yourself or to show your visitors, for several different reasons. This tutorial shows you how to create your own visit counter.

Not only will this counter count your sites visits, it will also get the date for every visit/pageload and with that information you can see when you had the most visitors and if the new design on your page increased the visitor count or decreased it, when you're most likely to have a visitor on your sit and similar. Well, here it is...!


Prerequisites:


To follow this tutorial it could be a good thing to know about databases and, in this work of art, I'm using MySQL as it is shown in our tutorial "PHP/MYSQL" and you should take a look at that before reading this.

You should also have some basic knowledge about the different image-functions that comes with the GD Library, take a look at our tutorial "PHP/Drawing".


Requirements:


PHP4+ with GD and Freetype Libraries.


Getting the business started:


The MySQL:


First of all we have to create our database tables:


<?php

require_once("Connector.php");
ConnectDB();

$query_counts = "CREATE TABLE visit_counts (

id bigint(20) unsigned NOT NULL auto_increment,
ip varchar(50) NOT NULL,
visits bigint(20) unsigned NOT NULL,
pageloads bigint(20) unsigned NOT NULL,
date date NOT NULL,
PRIMARY KEY (id)

)";

if(mysql_query($query_counts))
{
echo "visit_counts was created!";
}
else
{
echo "Creation of visit_counts failed: " . mysql_error();
}

$query_ips = "CREATE TABLE visit_ips (

id bigint(20) unsigned NOT NULL auto_increment,
ip TEXT NOT NULL,
lastdate datetime NOT NULL,
firstdate date NOT NULL,
PRIMARY KEY (id)

)";

echo "<br /><br /><br />";

if(mysql_query($query_ips))
{
echo "visit_ips was created!";
}
else
{
echo "Creation of visit_ips failed: " . mysql_error();
}

mysql_close();

?>


This file simply creates two tables for storing all the data we need to count our visits. The first table will store the counts of unique visits (count column) and pageloads (pageload column) the ip address being used by the visitor (ip column), an id (id column) and the date when they visited (date column). The second table make storage of an id (id column) visitors ip (ip column), the last date and time they visited (lastdate column) and the first date they visited (firstdate column). You can simply save this as a php-file on your server and run it, and then if no error messages is shown, you are all ready to go.

How we are going to use these tables is what comes next...


The PHP:


Let's start by including our database-connector-file, creating our class, and writing the code to instantiate a new class object and closing the MySQL-connection:


<?php

require_once("Connector.php");
ConnectDB();

class Counter
{
function CountStats()
{
}

function CreateCounter($what)
{
}
}

$counter = new Counter(2, 'visits');
mysql_close();

?>


I don't really think there is so much to explain so far, the $what parameter that CreateCounter() takes is simply a string which should represent what you want the class object to count, if you want to count pageloads you give it the string 'pageloads' if you want to count unique visits you give it the string 'visits'.

Now let's look at the CountStats()-function for a while:


<?php

...

function CountStats()
{
$datetime = date('Y-m-d H:i:s');
$datetime = strtotime($datetime);
$datetimeCheck = $datetime - 3600;

$date = date('Y-m-d');
$date = strtotime($date);

$ip = $_SERVER['REMOTE_ADDR'];
}

...

?>


First we get the date and time in MySQL-format and stores the result in $datetime, then we convert this format to a unix timestamp which is an integer value of the seconds past since January 1 1970 00:00:00 UTC. Then we create a test value by negating 3600 seconds from our timestamp and then we store this new value in $datetimeCheck. Then we do almost the same thing but we only collect the date in MySQL-format and converts it to a timestamp. At last we collect the visitors IP-address and stores it in $ip.

Now we are going to make some good use of all this:


<?php

...

function CountStats()
{
...

$ip = $_SERVER['REMOTE_ADDR'];

$tbCounts = mysql_query("SELECT ip FROM visit_counts WHERE ip = '".$ip."' AND date = FROM_UNIXTIME('".$date."')");

if(mysql_num_rows($tbCounts) == 0)
{
$query = "INSERT INTO visit_counts(ip, visits, pageloads, date) VALUES('".$ip."', 1, 1, FROM_UNIXTIME('".$date."'))";
$result = mysql_query($query);
}
}

...

?>


Here we check if the collected IP already exists in our database table visit_counts where the date column is today. If not we insert it along with todays date and we put the count to one for the count and pageload columns.

Now we have to create the code that will do something if the IP already exists in our table for today:


<?php

...

function CountStats()
{
...

if($rowsExist == 0)
{
...
}
else
{
$result_bf = mysql_query("SELECT lastdate FROM visit_ips WHERE ip = '".$ip."' AND UNIX_TIMESTAMP(lastdate) > '".$datetimeCheck."'");
$rows_bf = mysql_num_rows($result_bf);

if($rows_bf == 0)
{
$query_up = "UPDATE visit_counts SET visits = visits + 1, pageloads = pageloads + 1 WHERE ip = '".$ip."' AND date = FROM_UNIXTIME('".$date."')";
$result_up = mysql_query($query_up);
}
else
{
$query_pl = "UPDATE visit_counts SET pageloads = pageloads + 1 WHERE ip = '".$ip."' AND date = FROM_UNIXTIME('".$date."')";
$result_pl = mysql_query($query_pl);
}
}
}

...

?>


First we check if the collected IP already exists in our database table visit_ips within the range of our $datetimeCheck that means, if the last visit from the same IP was made within the leap of an hour, if not, we update the count and pageload columns in our visit_counts table and increments them by 1. If the Ip exists within the leap of an hour we at least increments the pageload by 1.

Now we continue by checking our visit_ips table:


<?php

...

function CountStats()
{
...

if($rowsExist == 0)
{
...
}
else
{
...
}

$tbIps = mysql_query("SELECT ip FROM visit_ips WHERE ip = '".$ip."'");

if(mysql_num_rows($tbIps) == 0)
{
$query = "INSERT INTO visit_ips VALUES(id, '".$ip."', FROM_UNIXTIME('".$datetime."'), FROM_UNIXTIME('".$date."'))";
$result = mysql_query($query);
}
else
{
$query = "UPDATE visit_ips SET lastdate = FROM_UNIXTIME('".$datetime."') WHERE ip = '".$ip."'";
$result = mysql_query($query);
}
}

...

?>


This code simply checks if the collected ip in $ip exists in visit_ips. If not, we insert it along with the $datetime and $date values. If it does, we simply update the lastdate column to our $datetime value.

Now we are done with our CountStats-function and it's time to code our CreateCounter-function:


<?php

...

function CreateCounter($what)
{
$numberOfDigits = 8;
$fontsize = 12;

$result = mysql_query("SELECT SUM(".$what.") FROM visit_counts");
$count = mysql_fetch_array($result);

$count = $count['SUM('.$what.')'];
$digits = count(str_split($count));
$num = $numberOfDigits - $digits;
}

...

?>


First we define the number of digits we will have in our counter and the fontsize. Then we get the count of unique visits or pageloads from the visit_counts table. We split the count string into a character array and counts it, we place this value in $digits. At last we get how many zeros to put infront of $count to show exactly 8 characters in our counter.

Let's create the new string for our counter to show:


<?php

...

function CreateCounter($what)
{
...

$num = $numberOfDigits - $digits;

$str = "";
for($i = 0; $i < $num; $i++)
{
$str .= 0;
}
$str .= $count;
}

...

?>


We create a new empty string $str and then, in a loop, we add a zero to the string for each iteration, the number of iterations is determined by the previously calculated $num. after the loop we simply add $count.

Now we are going to draw an image with our string:


<?php

...

function CreateCounter($what)
{
...

$str .= $count;

$x = 70;
$y = 20;

$image = imagecreate($x, $y);

$white = imagecolorallocate($image, 255, 255, 255);
$black = imagecolorallocate($image, 0, 0, 0);

$font = "URL";
}

...

?>


Here we simply create an image with the imagecreate()-function in the dimension 100 x 20 pixels. Then because images created with imagecreate simply gets the first defined color as its' background color we define $white. Then we create black which will be our font color and lastly we load in our font where URL represents the path to your ".ttf"-font.


<?php

...

function CreateCounter($what)
{
...

$font = "URL";

$txtbox = imagettfbbox($fontsize, 0, $font, $str);
$xc = ($x - $txtbox[4])/2;
$yc = ($y - $txtbox[5])/2;

imagettftext($image, $fontsize, 0, $xc, $yc, $black, $font, $str);
imagerectangle($image, 0, 0, $x-1, $y-1, $black);

header('Content-Type: image/gif');
imagegif($image);
imagedestroy($image);
}

...

?>


First we find out where to place the text to get it centered in the image, then we write it out, then we draw a rectangle border around the image and finally we send it to the browser and releases the memory.

This is an example of what it could look like:

imagehttp://www.morkalork.com/admin/uploads/WimpySE/images/BILD1_CounterArt.png

Here is the whole code for you who don't have the time, or something, to copy/paste it from the tutorial:


<?php

require_once("Connector.php");
ConnectDB();

class Counter
{
function CountStats()
{
$datetime = date('Y-m-d H:i:s');
$datetime = strtotime($datetime);
$datetimeCheck = $datetime - 3600;

$date = date('Y-m-d');
$date = strtotime($date);

$ip = $_SERVER['REMOTE_ADDR'];

$tbCounts = mysql_query("SELECT ip FROM visit_counts WHERE ip = '".$ip."' AND date = FROM_UNIXTIME('".$date."')");

if(mysql_num_rows($tbCounts) == 0)
{
$query = "INSERT INTO visit_counts(ip, visits, pageloads, date) VALUES('".$ip."', 1, 1, FROM_UNIXTIME('".$date."'))";
$result = mysql_query($query);
}
else
{
$result_bf = mysql_query("SELECT lastdate FROM visit_ips WHERE ip = '".$ip."' AND UNIX_TIMESTAMP(lastdate) > '".$datetimeCheck."'");
$rows_bf = mysql_num_rows($result_bf);

if($rows_bf == 0)
{
$query_up = "UPDATE visit_counts SET visits = visits + 1, pageloads = pageloads + 1 WHERE ip = '".$ip."' AND date = FROM_UNIXTIME('".$date."')";
$result_up = mysql_query($query_up);
}
else
{
$query_pl = "UPDATE visit_counts SET pageloads = pageloads + 1 WHERE ip = '".$ip."' AND date = FROM_UNIXTIME('".$date."')";
$result_pl = mysql_query($query_pl);
}
}

$tbIps = mysql_query("SELECT ip FROM visit_ips WHERE ip = '".$ip."'");

if(mysql_num_rows($tbIps) == 0)
{
$query = "INSERT INTO visit_ips VALUES(id, '".$ip."', FROM_UNIXTIME('".$datetime."'), FROM_UNIXTIME('".$date."'))";
$result = mysql_query($query);
}
else
{
$query = "UPDATE visit_ips SET lastdate = FROM_UNIXTIME('".$datetime."') WHERE ip = '".$ip."'";
$result = mysql_query($query);
}
}

function CreateCounter($what)
{
$numberOfDigits = 8;
$fontsize = 12;

$result = mysql_query("SELECT SUM(".$what.") FROM visit_counts") or die(mysql_error());
$count = mysql_fetch_array($result);

$count = $count['SUM('.$what.')'];

$digits = count(str_split($count));
$num = $numberOfDigits - $digits;

$str = "";
for($i = 0; $i < $num; $i++)
{
$str .= 0;
}
$str .= $count;

$x = 70;
$y = 20;

$image = imagecreate($x, $y);

$white = imagecolorallocate($image, 255, 255, 255);
$black = imagecolorallocate($image, 0, 0, 0);

$font = "URL";

$txtbox = imagettfbbox($fontsize, 0, $font, $str);
$xc = ($x - $txtbox[4])/2;
$yc = ($y - $txtbox[5])/2;

imagettftext($image, $fontsize, 0, $xc, $yc, $black, $font, $str);
imagerectangle($image, 0, 0, $x-1, $y-1, $black);

header('Content-Type: image/gif');
imagegif($image);
imagedestroy($image);
}
}

$counter = new Counter();
$counter->CountStats();
$counter->CreateCounter('visits');
mysql_close();

?>



Stuff to think of:


This is only an example of how you could build a program such as this and therefore I have omitted almost all of the security controls, bugfixes and stuff like that. Check it over!

---

Use a clear font for the counter that is readable even in smaller sizes, there's a lot of sites on the web where you can download free type fonts and free of charge! Google it! Google it! Google it!

I used a font that's called Monofonto that can be downloaded here, for free.


Tutorial by,
WimpySE


Article comments

Feel free to comment this article using a facebook profile.

I'm using facebook accounts for identification since even akismet couldn't handle all the spam I receive every day.