PHP visitor tracking script with jQuery and Raphael javascript library
This simple PHP visitor tracking script uses jQuery and Raphael javascript library to display daily hits to your page. The class features:
- IP filter (for IP’s you don’t want to track)
- Unique visits counter
- Raphael analytics (example on the bottom of the page)
- No search engine robots tracking
- Total hits counter
- Visitor IP’s info
- Visitor host info
- Referring pages info
- Visited pages info
- MySQL log table creation
Dependencies
MySQL Table
This table could be expanded as needed. For example, you could add “browser” field to collect visitor browser information.
CREATE TABLE IF NOT EXISTS logger (
logid INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
ip VARCHAR( 16 ) NOT NULL ,
host VARCHAR( 100 ) NOT NULL ,
visitdate DATETIME NOT NULL ,
visitedpage VARCHAR(255) NOT NULL ,
referring VARCHAR( 255 ) NOT NULL
)
PHP Class (class.logger.php)
IMPORTANT: Make sure to fill in the database info. See comments for the details.
<?php
//start session
class logger {
//database setup
var $hostname_logon = 'localhost'; //Database server LOCATION
var $database_logon = ''; //Database NAME
var $username_logon = ''; //Database USERNAME
var $password_logon = ''; //Database PASSWORD
//table fields
var $tablename = ''; //logger table name
var $filter = array(); //array of ip's you don't want tracked
//connect to database
function dbconnect(){
$connections = mysql_connect($this->hostname_logon, $this->username_logon, $this->password_logon) or die ('Unabale to connect to the database');
mysql_select_db($this->database_logon) or die ("Error in query: $qry. " . mysql_error());
}
//log visit
function logvisit($ip, $host, $filename, $referring){
//check if ip is filtered
if(!in_array($ip,$this->filter)){
$qry = "INSERT INTO ".$this->tablename." (ip, host, visitdate, visitedpage, referring)VALUES('".$ip."','".$host."',NOW(), '".$filename."', '".$referring."' )";
$result = mysql_query($qry) or die ("Error in query: $qry. " . mysql_error());
}
}
//show total uniqe visitors to date(parameter: (int) number of months). For example: 3 will start counting from 3 monhts before today.
function totalunique($month){
$lastmonth = mktime(01, 01, 01, date("m")-$month, date("d"), date("Y"));
$from = date("Y-m-d H:i:s", $lastmonth);
$to = date("Y-m-d H:i:s");
$qry = "SELECT DISTINCT ip, visitdate, host FROM ".$this->tablename." WHERE visitdate BETWEEN '".$from."' AND '".$to."' GROUP BY ip";
$result = mysql_query($qry) or die ("Error in query: $qry. " . mysql_error());
$totalunique = mysql_num_rows($result);
return $totalunique;
}
//show total visits to date(parameter: (int) number of months). For example: 3 will start counting from 3 monhts before today.
function totalhits($month){
$lastmonth = mktime(01, 01, 01, date("m")-$month, date("d"), date("Y"));
$from = date("Y-m-d H:i:s", $lastmonth);
$to = date("Y-m-d H:i:s");
$qry = "SELECT ip, visitdate, host FROM ".$this->tablename." WHERE visitdate BETWEEN '".$from."' AND '".$to."'";
$result = mysql_query($qry) or die ("Error in query: $qry. " . mysql_error());
$totalhitsmonth = mysql_num_rows($result);
return $totalhitsmonth;
}
//show daily visits for a specific month / year and div in which to laod the graph
function dailyhits($month, $year, $div, $tableid){
//current month and year
if($month == ""){
$month = date("m");
}
if($year == ""){
$year = date("Y");
}
//get number of days
$numdaysinmonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
echo '<table cellpadding="0" cellspacing="0" border="0" class="'.$tableid.'" >
<tfoot>
<tr>';
for($x=1;$x<=$numdaysinmonth;$x++){
echo '<th>'.$x.'</th>';
}
echo '</tr>
</tfoot>
<tbody>
<tr>';
$totalhits = 0;
for($y=1;$y<=$numdaysinmonth;$y++){
if($y < 10){
$b = '0'.$y;
}else{
$b = $y;
}
$current_month = date('Y-m').'-'.$b;
$qry = "SELECT DISTINCT ip FROM ".$this->tablename." WHERE visitdate LIKE '$current_month%' GROUP BY visitdate";
$result = mysql_query($qry) or die ("Error in query: $qry. " . mysql_error());
$numrows = mysql_num_rows($result);
echo '<td>';
echo $numrows;
$totalhits = $totalhits + $numrows;
echo '</td>';
}
echo '</tr>
</tbody>
</table>
<div id="'.$div.'"></div>';
}
//display visit details (parameter (int) number of last visits to display
function visitdetails($num){
$qry = "SELECT * FROM ".$this->tablename." WHERE visitdate!='' ORDER BY logid DESC LIMIT 0, ".$num."";
$result = mysql_query($qry) or die ("Error in query: $qry. " . mysql_error());;
if (mysql_num_rows($result) != 0){
echo '<table cellpadding="0" cellspacing="0" border="0" class="visitdetails">';
echo '<thead><tr><th>IP</th><th>Host</th><th>Referring Page</th><th>Page Visited</th><tr></thead>';
echo '<tbody>';
while ($row = mysql_fetch_object($result)){
$nowww = ereg_replace('www.','',$row->referring);
$domain = parse_url($nowww);
if(!empty($domain["host"])) {
$host = $domain["host"];
}
echo '<tr><td>'.$row->ip.'</td>
<td>'.$row->host.'</td>
<td><a href="'.$row->referring.'" target="_blank">'.$host.'</a></td>
<td><a href="..'.$row->filename.'" target="_blank">'.$row->filename.'</a></td>
</tr>';
}
echo '</tbody>';
echo '</table>';
}
}
//raphael stuff(depends on including raphael.js library
function loadraphael($tableid, $div, $month_year, $width, $height, $leftgutter, $bottomgutter, $topgutter,$strokecolor, $fontcolor,$fillcolor,$gridcolor,$raphael_path){
//load latest jquery. Uncomment if you are already using jquery.
echo '<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>';
echo '<script type="text/javascript" src="'.$raphael_path.'"></script><script type="text/javascript">
//raphael.path.methods.js
Raphael.el.isAbsolute = true;
Raphael.el.absolutely = function () {
this.isAbsolute = 1;
return this;
};
Raphael.el.relatively = function () {
this.isAbsolute = 0;
return this;
};
Raphael.el.moveTo = function (x, y) {
this._last = {x: x, y: y};
return this.attr({path: this.attrs.path + ["m", "M"][+this.isAbsolute] + parseFloat(x) + " " + parseFloat(y)});
};
Raphael.el.lineTo = function (x, y) {
this._last = {x: x, y: y};
return this.attr({path: this.attrs.path + ["l", "L"][+this.isAbsolute] + parseFloat(x) + " " + parseFloat(y)});
};
Raphael.el.arcTo = function (rx, ry, large_arc_flag, sweep_flag, x, y, angle) {
this._last = {x: x, y: y};
return this.attr({path: this.attrs.path + ["a", "A"][+this.isAbsolute] + [parseFloat(rx), parseFloat(ry), +angle, large_arc_flag, sweep_flag, parseFloat(x), parseFloat(y)].join(" ")});
};
Raphael.el.curveTo = function () {
var args = Array.prototype.splice.call(arguments, 0, arguments.length),
d = [0, 0, 0, 0, "s", 0, "c"][args.length] || "";
this.isAbsolute && (d = d.toUpperCase());
this._last = {x: args[args.length - 2], y: args[args.length - 1]};
return this.attr({path: this.attrs.path + d + args});
};
Raphael.el.cplineTo = function (x, y, w) {
this.attr({path: this.attrs.path + ["C", this._last.x + w, this._last.y, x - w, y, x, y]});
this._last = {x: x, y: y};
return this;
};
Raphael.el.qcurveTo = function () {
var d = [0, 1, "t", 3, "q"][arguments.length],
args = Array.prototype.splice.call(arguments, 0, arguments.length);
if (this.isAbsolute) {
d = d.toUpperCase();
}
this._last = {x: args[args.length - 2], y: args[args.length - 1]};
return this.attr({path: this.attrs.path + d + args});
};
Raphael.el.addRoundedCorner = function (r, dir) {
var rollback = this.isAbsolute;
rollback && this.relatively();
this._last = {x: r * (!!(dir.indexOf("r") + 1) * 2 - 1), y: r * (!!(dir.indexOf("d") + 1) * 2 - 1)};
this.arcTo(r, r, 0, {"lu": 1, "rd": 1, "ur": 1, "dl": 1}[dir] || 0, this._last.x, this._last.y);
rollback && this.absolutely();
return this;
};
Raphael.el.andClose = function () {
return this.attr({path: this.attrs.path + "z"});
};
//raphael analytics
Raphael.fn.drawGrid = function (x, y, w, h, wv, hv, color) {
color = color || "'.$fillcolor.'";
var path = ["M", x, y, "L", x + w, y, x + w, y + h, x, y + h, x, y],
rowHeight = h / hv,
columnWidth = w / wv;
for (var i = 1; i < hv; i++) {
path = path.concat(["M", x, y + i * rowHeight, "L", x + w, y + i * rowHeight]);
}
for (var i = 1; i < wv; i++) {
path = path.concat(["M", x + i * columnWidth, y, "L", x + i * columnWidth, y + h]);
}
return this.path(path.join(",")).attr({stroke: color});
};
$(function () {
$(".'.$tableid.'").css({
position: "absolute",
left: "-9999em",
top: "-9999em"
});
});
window.onload = function () {
// Grab the data
var labels = [],
data = [];
$(".'.$tableid.' tfoot th").each(function () {
labels.push($(this).html());
});
$(".'.$tableid.' tbody td").each(function () {
data.push($(this).html());
});
// Draw
var width = '.$width.',
height = '.$height.',
leftgutter = '.$leftgutter.',
bottomgutter = '.$bottomgutter.',
topgutter = '.$topgutter.',
colorhue = .6 || Math.random(),
color = "hsb(" + [colorhue, 1, .75] + ")",
r = Raphael("'.$div.'", width, height),
txt = {font: \'12px Fontin-Sans, Arial\', fill: "'.$fontcolor.'"},
txt1 = {font: \'10px Fontin-Sans, Arial\', fill: "'.$fontcolor.'"},
txt2 = {font: \'12px Fontin-Sans, Arial\', fill: "'.$fillcolor.'"},
X = (width - leftgutter) / labels.length,
max = Math.max.apply(Math, data),
Y = (height - bottomgutter - topgutter) / max;
r.drawGrid(leftgutter + X * .5, topgutter, width - leftgutter - X, height - topgutter - bottomgutter, 10, 10, "'.$gridcolor.'");
var path = r.path().attr({stroke: color, "stroke-width": 4, "stroke-linejoin": "round"}),
bgp = r.path().attr({stroke: "none", opacity: .3, fill: color}).moveTo(leftgutter + X * .5, height - bottomgutter),
frame = r.rect(10, 10, 100, 40, 5).attr({fill: "'.$fillcolor.'", stroke: "'.$strokecolor.'", "stroke-width": 2}).hide(),
label = [],
is_label_visible = false,
leave_timer,
blanket = r.set();
label[0] = r.text(60, 10, "24 hits").attr(txt).hide();
label[1] = r.text(60, 40, "22 September 2008").attr(txt1).attr({fill: color}).hide();
for (var i = 0, ii = labels.length; i < ii; i++) {
var y = Math.round(height - bottomgutter - Y * data[i]),
x = Math.round(leftgutter + X * (i + .5)),
t = r.text(x, height - 6, labels[i]).attr(txt).toBack();
bgp[i == 0 ? "lineTo" : "cplineTo"](x, y, 10);
path[i == 0 ? "moveTo" : "cplineTo"](x, y, 10);
var dot = r.circle(x, y, 5).attr({fill: color, stroke: "'.$fillcolor.'"});
blanket.push(r.rect(leftgutter + X * i, 0, X, height - bottomgutter).attr({stroke: "none", fill: "'.$fontcolor.'", opacity: 0}));
var rect = blanket[blanket.length - 1];
(function (x, y, data, lbl, dot) {
var timer, i = 0;
$(rect.node).hover(function () {
clearTimeout(leave_timer);
var newcoord = {x: +x + 7.5, y: y - 19};
if (newcoord.x + 100 > width) {
newcoord.x -= 114;
}
frame.show().animate({x: newcoord.x, y: newcoord.y}, 200 * is_label_visible);
label[0].attr({text: data + " hit" + ((data % 10 == 1) ? "" : "s")}).show().animateWith(frame, {x: +newcoord.x + 50, y: +newcoord.y + 12}, 200 * is_label_visible);
label[1].attr({text: lbl + " '.$month_year.'"}).show().animateWith(frame, {x: +newcoord.x + 50, y: +newcoord.y + 27}, 200 * is_label_visible);
dot.attr("r", 7);
is_label_visible = true;
}, function () {
dot.attr("r", 5);
leave_timer = setTimeout(function () {
frame.hide();
label[0].hide();
label[1].hide();
is_label_visible = false;
// r.safari();
}, 1);
});
})(x, y, data[i], labels[i], dot);
}
bgp.lineTo(x, height - bottomgutter).andClose();
frame.toFront();
label[0].toFront();
label[1].toFront();
blanket.toFront();
};</script>';
}
//function to create Logger table
function createtable($tablename){
$qry = "CREATE TABLE IF NOT EXISTS ".$tablename." (
logid INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
ip VARCHAR( 16 ) NOT NULL ,
host VARCHAR( 100 ) NOT NULL ,
visitdate DATETIME NOT NULL ,
visitedpage VARCHAR(255) NOT NULL ,
referring VARCHAR( 255 ) NOT NULL
)";
$result = mysql_query($qry) or die(mysql_error());
return;
}
}
?>
Usage
Make sure to include and instantiate the class on every page you use it.
include("class.logger.php");
$log = new logger(); //Instentiate the class
$log->tablename = "logger"; //set logger table name
$log->dbconnect(); //connect to the database
Create Logger Table
Run this code only once to create the log on table.
include("class.logger.php"); //path to class.logger.php file
$log = new logger(); //Instentiate the class
$log->dbconnect(); //connect to database
//pass the name of the table as the parameter. I.e. 'logger"
$log->cratetable('logger');
Log visits
Create a file logger.php and place it inside a folder “/logger“.
<?php
header('Content-type: text/javascript');
include("class.logger.php"); //path to class.logger.php file
$log = new logger(); //Instentiate the class
$log->tablename = "logger"; //set logger table name
$log->dbconnect(); //connect to database
//$log->filter = array('00.00.00.000'); //array of IP addresses you don't want to track
//get IP
$ip = $_SERVER['REMOTE_ADDR'];
//get host
$host = gethostbyaddr($_SERVER['REMOTE_ADDR']);
//get fisited page
$filevisited = $_REQUEST['f'];
if($filevisited ==""){
$filevisited = $_SERVER["PHP_SELF"];
}
//get referring page
$referring = urldecode($_REQUEST['r']);
if($referring ==""){
$referring = $_SERVER["HTTP_REFERER"];
}
//log visit
$log->logvisit($ip, $host, $filevisited, $referring);
?>
To ensure bot’s are not logged add Disallow directive to the robots.txt.
robots.txt (example)
User-Agent: * Allow: / Disallow: /logger/
Next place this code before the end < /body >tag on every page you want to track.
Display Daily Hits with jQuery and Raphael.js
First make sure that you are including jquery.js and raphael.js files.
include(class.logger.php);
$log = new logger(); //Instentiate the class
$log->tablename = "logger"; //set logger table name
$log->dbconnect(); //connect to database
//set date and year text for the info bubble that appears on hover
$date = date('F')." ".date('Y');
//load raphael analytics javascript
//Parameters: "table[class], div[id], text[date], width, height, left gutter, bottom gutter, top gutter,stroke color, fontcolor, fill color, grid color
$log->loadraphael('data','holder',$date, 600, 250, 20, 30, 30,'#474747', '#000', '#eee', '#eee');
//load table hits containing data
//Parameters: month, year, div[id], table[class]
$log->dailyhits(11, 2009, 'holder', 'data');
(Optional) Example CSS file to position and size the “holder”
#holder {
width: 600px;
height: 450px;
left: 10px;
position: absolute;
top: 10px;
}
Display Hits Summary
//show total uniqe visitors to date(parameter: (int) number of months). For example: 3 will start counting from 3 monhts before today. echo $log->totalunique(3); //show total visits to date(parameter: (int) number of months). For example: 3 will start counting from 3 monhts before today. echo $log->totalhits(3); //visit details (parameter (int) number of last visits to display. For example :100 will show last 100 visits //the info is displayed in a table with visitdetails[class] for easy CSS styling. $log->visitdetails(100);
Demo
Download
Do you like this script? Support it by downloading packaged file with an example:

Oscar Marcelo
Hello! I get this error when I tried to run the “Create Logger Table” piece of code:
“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ”logger’ ( ‘log_id’ int(11) NOT NULL auto_increment, ‘ at line 1″.
What should I do?
eplicanic
There was an error in script I fixed. Please use updated script and let me know if that works for you!
KhanhGooner
I have purchased “visitor tracking PHP script with jQuery javascript library and Raphael,” but can not find the download link. Now I have to do what
eplicanic
You should have gotten an email. Check your spam folder, it’s possible it got delivered there.
Bub
I purchased it too and did’t get a link to the download.
Can you send it to me please because when I tried to paste the code from this page it gave me errors like this one on the script line before the end tag :-
Parse error: syntax error, unexpected $end in /home/ruralter/public_html/dugglenet.org/news/test.php on line 18
Thanks.
eplicanic
It’s possible that the download link went to your Junk mail folders. In any case I just emailed you the download link! Thanks for supporting this script!
Carolynne
I have purchased this script and received my email with the link. Thank you!
What would I put into the example.php to show the visitor’s information. I tried entering in this:
$log->visitdetails(100);
after this:
$log->dailyhits(11, 2009, ‘holder’, ‘data’);
but all I get is an error.
Also, what about all the information you told us about, such as:
Total hits counter
Visitor IP’s info
Visitor host info
Referring pages info
Visited pages info
I would like to see that information show up in example.php as well.
Thank you in advance for your help!!!
eplicanic
What’s the error? All that other info is part of the “visitdetails” function.
Bub
Hi there,
I emailed you the same query about adding the extra stats, I didn’t get a reply so I will post it here also.
The error is this :-
Error in query: SELECT * FROM logger WHERE visitdate!=” ORDER BY log_id DESC LIMIT 0, 100. Unknown column ‘log_id’ in ‘order clause’
Thanks !
eplicanic
That was a bug. Replace log_id with logid in the query inside the function “visitdetails”
Carolynne
Thank you, that fixed my problem as well.
Muhammad Qasim
Great work it appsolutely work fine little bugs come but i fix that all. . Any one who want also fix this below statement where you add script line that is:
Just copy nd paste where you want to count page hits:
<script type="text/javascript" src="logger/logger.php?t=&f=&r=<?php echo urlencode($_SERVER['REMOTE_ADDR']);
Muhammad Qasim
$log->loadraphael(‘data’,'holder’,$date, 600, 250, 20, 30, 30,’#474747′, ‘#000′, ‘#eee’, ‘#eee’,'raphael.js’);
correct it also last paremeter to your raphael.js path your file path.
Skrypt odwiedzin w PHP oraz jQuery :: Klocek Blog - Darmowe skrypty
[...] PHP oraz jQuery. Aplikacja posiada filtr na adresy IP oraz działa w oparciu o bazę MySQL. Zobacz Demo Pobierz Skrypt Ajax i jQuery Klocek Dziś Kliknij tutaj, aby anulować [...]
SKRYPT ODWIEDZIN W PHP ORAZ JQUERY : Dumbo Blog
[...] Zobacz Demo [...]
Sebastien
Hi,
What part of the script makes a call to a jQuery function? My client’s application works under Prototype and he’s not ready to change it to jQuery yet. Anyway this script can be used with Prototype instead?
Thanks a lot.
Simon Montaño
Hey I was checking your amazing work and notice that something is missed in this line.
First make sure that you are including jquery.js and raphael.js files.
$log->loadraphael(‘data’,'holder’,$date, 600, 250, 20, 30, 30,’#474747′, ‘#000′,
‘#eee’, ‘#eee’);
Look like your are using 13 Parameters and there are only 12. I guess that the last 1 should be the $raphael_path that should be declared in the source.
Cosmo
I just purchased this script and received no e-mail. How long am I supposed to wait?
Cosmo
Opps junk mail… Got it thanks
cosmo
OK this is not working for me at all. I don’t get any stats. Nothing displays apart from the table. I have sample data in the database. What is the problem?
Please help!
farfaj
Hi
I have a small problem, in the ‘visitedpage’ field in the database the value is ” all the time, and in the ‘referring’ field the value is ‘<?php echo urlencode($_SERVER[' all the time.
Please help
Tartoob
How can I use it for more than one page and one view
And also how can I change the view for a year ?
Jesper
I have recently purchased and all works fine except if there is no data in the logger table. Is it possible to show the graf woth only zero hits if no records?