How to implement Heatmap on Websites using PHP, MySQL, jQuery and Ajax?

I was assigned a task when an Interviewer interviewed me and that was a Technical question. I was asked to design a system that can gather click data from a webpage and show it later in form of a Heatmap.

[dfads params=’groups=-1′]

This system can be integrated into any website which records visitor clicks on the page. The goal of of this will be to track visitor’s mouse clicks on various elements of the page and later show them accurately in form a Heatmap. The owner should be able to see aggregated click data in form of an overlay on top of his webpage. The areas in the heatmap that are red more clicks compared to the areas that are white.

After googling through the internet I found some resources which were very interesting. I devoted some time and tried to implement a demo. Please follow the following Steps:

1. Client Code : Create a file index.php and include the following code below. This is the page where users make clicks.

[code]
<script type=’text/javascript’ src="js/jquery-lib.js"></script> <!– jQuery library –>
<script type=’text/javascript’ src="js/hm-dev.js"></script> <!– Log JS –>

<title>99-Websites.com Labs</title>
<body>
<div style="text-align:center">
<img src="99-ws-labs.jpg" />
</div>
</body>

[/code]

2. The Ajax Call : Create a JS file named as hm-dev.js. This file is included in the above index.php page. Add the snippet below:

[code]
/*
Author : Dev
Date : 12/06/2015
*/

jQuery(document).ready(function() {
jQuery(document).click(function(e){
//alert(window.location.href.toString().split(window.location.host)[1]+" — "+e.pageX+" — "+e.pageY);
log_click(window.location.href.toString(), e.pageX, e.pageY);
});
var canvas = document.getElementsByTagName(‘canvas’)[0];
canvas.style.display = "none";
});

function log_click(page, x, y){ // log clicks for heatmap
jQuery.ajax({
type: ‘POST’,
url: ‘log_click.php’,
crossDomain: true,
data: "x_coord="+x+"&y_coord="+y+"&page="+page,
dataType: ‘json’,
success: function(responseData, textStatus, jqXHR)
{
if (responseData== 1){
console.log("Click logged: " + x + ", " + y);

}
else{
console.log("Error – click not logged " + x + ", " + y);
}
},
error: function (responseData, textStatus, errorThrown)
{
console.warn(responseData, textStatus, errorThrown);
alert(‘CORS failed – ‘ + textStatus);
}
});
}
[/code]

3. Log the Clicks : Create a PHP file named with log_click.php and add the following snippet.

[code]

<?php
header(‘Access-Control-Allow-Origin: *’);
header(‘Access-Control-Allow-Methods: POST, GET, OPTIONS’);
header(‘Access-Control-Max-Age: 1000’);
header(‘Access-Control-Allow-Headers: Content-Type’);

//echo json_encode(array("your_request_was" => $_POST[‘page’].$_POST[‘x_coord’].$_POST[‘y_coord’]));

include(‘config.php’); //Create config.php file and define $dbuser, $dbpass & $dbname

if(isset($_POST[‘x_coord’])){
$page = htmlentities($_POST[‘page’]);
if($page == "/"){ $page = "/index.php"; }
$xcoord = htmlentities($_POST[‘x_coord’]);
$ycoord = htmlentities($_POST[‘y_coord’]);
$time = date( ‘Y-m-d H:i:s’);

$conn = mysql_connect(‘localhost’, $dbuser, $dbpass);
mysql_select_db($dbname, $conn);
$page = mysql_real_escape_string($page);
$xcoord = mysql_real_escape_string($xcoord);
$ycoord = mysql_real_escape_string($ycoord);

mysql_query("INSERT INTO clicks (timestamp, page, x, y) VALUES (‘$time’, ‘$page’, $xcoord, $ycoord)");
mysql_close($conn);
echo "1";
}
else
{
echo ‘0’;
}

?>

[/code]

4. Create MySQL Table : Create table with following fields:

[code]

CREATE TABLE IF NOT EXISTS `clicks` (
`timestamp` datetime NOT NULL,
`page` varchar(200) NOT NULL,
`x` int(255) NOT NULL,
`y` int(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

[/code]

That’s it, the first part is over. After implementing the above steps you will be able to log clicks on the MySQL Table. The next and the main part is viewing the heat maps.

5. Create the Admin Page : Create PHP page named with admin.php. This page will lists out all the domains on which the client side code is added. When the links are clicked, their respective heatmaps will be displayed below the same page.  Admin Code is listed below:

[code]

<?php
/*
Author : Dev
Date : 12/06/2015
*/
include("config.php");
$con2 = mysql_connect(‘localhost’, $dbuser, $dbpass);
mysql_select_db($dbname, $con2);
$query = "SELECT distinct page FROM `clicks` WHERE 1";
$result = mysql_query($query);
?>
<html>
<head>
<title>Heatmap Admin</title>
<script type=’text/javascript’ src="js/jquery-lib.js"></script>

<script type=’text/javascript’ src="js/heatmap.js"></script>
<script>
jQuery(document).ready(function(){
var heatmapInstance = h337.create({
container: document.querySelector(‘.display’),
radius: 25
});

jQuery(".showcanvas").click(function(){
//location.reload();
//alert(jQuery(this).attr(‘value’));
var timescale = "day";
var page = jQuery(this).attr(‘value’);
//alert(page);
var postData = "timescale="+timescale+"&page="+page;
jQuery.ajax({
type:"POST",
dataType: "json",
data: postData,
beforeSend: function(x) {
if(x && x.overrideMimeType) {
x.overrideMimeType("application/json;charset=UTF-8");
}
}, url: ‘heatmap.php’,
success: function(data) {

if (data.amount > 0){
for (i=0; i<data.amount; i++){
heatmapInstance.addData({
x: data[i].x,
y: data[i].y,
value: 2
});
}
}
}
});

});
});
</script>
</head>
<body >
<div style="width:100%; border:1px solid; black;">
[Click on the Websites below to View their respective HeatMaps]<br>
<ul style="font-size:12px;">
<?php
while($row = mysql_fetch_assoc($result)){
?>
<li><a href="#" class="showcanvas" value="<?=$row["page"]?>"> <?=$row["page"]?></a></li> <br/>

<?php

}
?>
</ul>
</div>
<div class="display" style="width:100%;height:100%;border:1px solid; black;float:right;">
</div>

</body>
</html>

[/code]

The main logic behind the code is the heatmap.js library. In order to understand in detail you can explore the following references:

1. http://www.patrick-wied.at/static/heatmapjs/example-click-heatmap.html

2. http://rossmarks.co.uk/blog/?p=683

3. http://www.d-mueller.de/blog/cross-domain-ajax-guide/

You can view the Demo here: 

1. Client / Users Page : http://99labs.net where you can make some clicks on the webpage.

2. Admin Page : http://dewendra.com.np/labs/hm/admin.php where you can view the Heatmap.

Also, You can download the whole code from here : Download

[dfads params=’groups=-1′]

PS : The client code can be installed into any website and their logs can be maintained on the remote server. If you go through the client side code you can see the ajax code implemented with CORS (Cross Origing Resource Sharing) using jQuery.

Check whether current time lies between start hour and end hour (PHP)

I started to think of a function in PHP that checks the current time whether it lies between start hour and end hour. This was a task from my boss a couple of weeks ago. He asked this function to write in order to turn down our web application from 900PM to 400AM and display an appropriate message. I googled for a few minutes and compiled the code below:

[dfads params=’groups=-1′]

[code]
function checkTime($current_time, $start, $end){
/* $current_time = "9:00 pm";
$start = "9:00 pm";
$end = "4:00 am"; */

$date1 = DateTime::createFromFormat(‘H:i a’, $current_time);
$date2 = DateTime::createFromFormat(‘H:i a’, $start);
$date3 = DateTime::createFromFormat(‘H:i a’, $end);

//echo $date1;
if ($date1 &gt;= $date2 || $date1 &lt; $date3)
{
return 1;
}
else{
return 0;
}
}

$curTime = date(‘h:i a’);
$curTime = "9:00 pm";
//echo $curTime;
if(checkTime($curTime, "9:00 pm", "4:00 am")==1){
echo "Server Under Maintenance !!
<div style="color: #cc503f; border: 2px solid red; border-radius: 6px; margin-left: auto; margin-right: auto; width: 600px; height: 200px; padding: 10px; text-align: center;">
<h2>Notice!!!</h2>
<h3>Portal under Maintenance from 9PM to 4AM. Please visit back soon.</h3>
</div>
";
exit;
}
[/code]

[dfads params=’groups=-1′]

Eport data to excel using Codeigniter and Oracle (OCI)

Below is a simple code snippet that will help you to export data to CSV/Excel format using Codeigniter and Oracle. Yes, it is obvious that you must have knowledge regarding Codeigniter and Oracle before you proceed further reading.

[dfads params=’groups=-1′]

The code below contains few PHP variables and function calls. I hope that you understand the same in a better way and please give your feedback if you feel this needs.

$sql = "SELECT * FROM your_table_name";
$filename = "Name_of_the_file.csv";
$countRow = functionCountRow();

$this->searchkyc_model->ExportToExcel($sql,$filename,$countRow);

public function ExportToExcel($sql,$filename,$countRow) { 	

		$output = "";

		$this->epfo_db = $this->load->database('EPFO', true);		

		$stmt = oci_parse($this->epfo_db->conn_id, $sql);

		oci_execute($stmt);

		$ncols = oci_num_fields($stmt);

		for ($i = 1; $i <= $ncols; ++$i) { 			
                    $colname = oci_field_name($stmt, $i);			 			
                    $output .= '"'.$colname.'",'; 		
                 } 		
                $output.="n"; 		 		
                $row = oci_fetch_all($stmt, $result); 		
                oci_free_statement($stmt); 		
                oci_close($this->epfo_db->conn_id);	

		// Get Records from the table
		for($i=0;$i<$countRow;$i++){ 				 				                
                    foreach($result as $key=>$val){
					$output.='"'.$val[$i].'",';
		          }
				$output.="n";
		}

		// Download the file	
		header('Content-type: application/csv');
		header('Content-Disposition: attachment; filename='.$filename);

		echo $output;
		exit;

	 }

[dfads params=’groups=-1′]

ORA-24408: could not generate unique server group name

After continuous google for more than 10 hours, I finally came to a conclusion that the problem “ORA-24408: could not generate unique server group name” was not with oracle instanclient or the connection string oci_connect(). The only problem was with the mis-match of the hostnames of the application server defined in /etc/sysconfig/network & /etc/hosts.

[dfads params=’groups=-1′]

After modifying the hostnames in both the file to a single name, the problem was solved.

 $ vi /etc/sysconfig/network

NETWORKING=yes
HOSTNAME=RHEL65
$vi /etc/hosts

$ vi /etc/hosts
#127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
127.0.0.1    RHEL65

$service network restart

The above steps helped me save my valuable time. Thanks to the bloggers.

I hope these information would help you too. Best wishes!

[dfads params=’groups=-1′]

[Source: http://ahmadzainuddinzakaria.blogspot.in/2012/06/warning-ociconnect-functionoci-connect.html]

Unable to save changes to menu in Drupal 6

[dfads params=’groups=-1′]

On the menu-customize page, after

1) dragging a menu item, or

2) checking/unchecking an enable checkbox,

and clicking “Save configuration”, changes to menu were not saved in Drupal 6. Hence, I started to debug the issue at the Application level. After long head bang, I raised my hand and took some rest. Finally, I googled and found that the problem was not at the Application Level but at System Level. I came to know that while posting the form (i.e. when Save Configuration is clicked) the data sent was of large amount and the system was not able to accept since maximum input size was not defined. Following were the changes made in php.ini file.

; How many GET/POST/COOKIE input variables may be accepted
max_input_vars = 2048

After making above changes I restarted the Apache server. Thus, the problem was resolved and Save Configuration in Menu started working.

[dfads params=’groups=-1′]

Http Error 0 in Drupal

[dfads params=’groups=-1′]

Http Error 0  is a very common error that occurs in Drupal. There are many reasons behind this error.

htttp-error-0

One of the way to resolve this error is to append the following line in this file : /etc/apache2/mods-available/fcgi.conf

[code]

MaxRequestLen 536870912

[/code]

Increase the number value of the MaxRequestLen until the error stops to continue.

[dfads params=’groups=-1′]

Upload Max Filesize PHP Configuration

[dfads params=’groups=-1′]

I have installed Apache2, PHP5.5 & MySQL5 independently on my Debian 7.3 OS. I hosted my drupal site on my Dedicated Server. I faced problem to upload files greater than 2MB from the CMS of the Site. After exploring the Internet I found the solution. Here’s the steps:

1. Edit /etc/php5/cgi/php.ini file.

2. Add the following line of code:

[php]upload_max_filesize = 10M[/php]

Make sure that you are not editing /etc/php5/php.ini file

[dfads params=’groups=-1′]

Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe. You need to recompile PHP.

[dfads params=’groups=-1′]

After installing Apache2, MySQL & PHP on Debian wheezy 7.1, I tried to reboot the apache server. It showed me the following error.
Starting web server: apache2[Fri Dec 27 11:29:16 2013] [crit] Apache is running a threaded MPM, but your PHP Module
is not compiled to be threadsafe. You need to recompile PHP.
Pre-configuration failed
Action 'start' failed.
The Apache error log may have more information.
failed!

So I searched through the internet to recomplie the PHP Source. But none of the tutorials were best and feasible.

Finally, after long try I found the command below that helped me to run the apache and PHP along.
apt-get install apache2-mpm-prefork

[dfads params=’groups=-1′]

Admin Panel with Login in CodeIgniter

[dfads params=’groups=-1′]

Today, I came up with a solution for how to make an inbuilt Admin Panel with already coded Login module in codeigniter. Just follow the steps below to setup into your project.

1. Download the adminPanelWithLogin.zip file. Extract it. Copy the respective admin folders to the Controllers, Models, & Views of your project.

Screenshot - Saturday 24 August 2013 - 05:23:59  IST

2. Create the MySQL table & populate data.

[sql]
CREATE TABLE IF NOT EXISTS `tbl_admin` (
`admin_id` int(4) NOT NULL AUTO_INCREMENT,
`admin_name` varchar(128) NOT NULL,
`admin_email` varchar(64) NOT NULL,
`admin_password` varchar(64) NOT NULL,
`admin_role` int(2) NOT NULL,
`admin_status` int(1) NOT NULL,
PRIMARY KEY (`admin_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=14 ;

INSERT INTO `tbl_admin` (`admin_id`, `admin_name`, `admin_email`, `admin_password`, `admin_role`, `admin_status`) VALUES
(1, ‘admin’, ‘admin’, ‘admin_123’, 1, 0),
(13, ‘super’, ‘super’, ‘super_123’, 1, 1);
[/sql]

3.  Check whether the database & session are initiated by exploring to application/config/autoload.php file.

[php]$autoload[‘libraries’] = array(‘database’, ‘session’); [/php]

4. Browse the admin login from you browser: http://localhost/your_project/admin. A screen must appear like this:

Screenshot - Saturday 24 August 2013 - 05:40:09  IST

5. Use the default admin user as “admin ” and Password as “admin_123” then press Login. You will be redirected to a secure home page like this:

Screenshot - Saturday 24 August 2013 - 05:40:32  IST

You can further add modules of your choice & code your project as you like.

Feedbacks & suggestions are always welcome.

[dfads params=’groups=-1′]

Difference between PHP4 & PHP5

Here’s a quick overview of what has changed between PH4 and PHP5. PHP5 for the most part is backwards compatible with PHP4, but there are a couple key changes that might break your PHP4 script in a PHP5 environment. If you aren’t already, I stronly suggest you start developing for PHP5. Many hosts these days offer a PHP5 environment, or a dual PHP4/PHP5 setup so you should be fine on that end. Using all of these new features is worth even a moderate amount of trouble you might go through finding a new host!

Note: Some of the features listed below are only in PHP5.2 and above.

Object Model
The new OOP features in PHP5 is probably the one thing that everyone knows for sure about. Out of all the new features, these are the ones that are talked about most!

Passed by Reference
This is an important change. In PHP4, everything was passed by value, including objects. This has changed in PHP5 — all objects are now passed by reference.

PHP Code:
$joe = new Person();
$joe->sex = 'male';
$betty = $joe;
$betty->sex = ‘female’;

echo $joe->sex; // Will be ‘female’

The above code fragment was common in PHP4. If you needed to duplicate an object, you simply copied it by assigning it to another variable. But in PHP5 you must use the new clone keyword.

Note that this also means you can stop using the reference operator (&). It was common practice to pass your objects around using the & operator to get around the annoying pass-by-value functionality in PHP4.

Class Constants and Static Methods/Properties
You can now create class constants that act much the same was as define()’ed constants, but are contained within a class definition and accessed with the :: operator.

Static methods and properties are also available. When you declare a class member as static, then it makes that member accessible (through the :: operator) without an instance. (Note this means within methods, the $this variable is not available)

Visibility
Class methods and properties now have visibility. PHP has 3 levels of visibility:

  1. Public is the most visible, making methods accessible to everyone and properties readable and writable by everyone.
  2. Protected makes members accessible to the class itself and any subclasses as well as any parent classes.
  3. Private makes members only available to the class itself.

Unified Constructors and Destructors
PHP5 introduces a new unified constructor/destructor names. In PHP4, a constructor was simply a method that had the same name as the class itself. This caused some headaches since if you changed the name of the class, you would have to go through and change every occurrence of that name.

In PHP5, all constructors are named __construct(). That is, the word construct prefixed by two underscores. Other then this name change, a constructor works the same way.

Also, the newly added __destruct() (destruct prefixed by two underscores) allows you to write code that will be executed when the object is destroyed.

Abstract Classes
PHP5 lets you declare a class as abstract. An abstract class cannot itself be instantiated, it is purely used to define a model where other classes extend. You must declare a class abstract if it contains any abstract methods. Any methods marked as abstract must be defined within any classes that extend the class. Note that you can also include full method definitions within an abstract class along with any abstract methods.

Interfaces
PHP5 introduces interfaces to help you design common APIs. An interface defines the methods a class must implement. Note that all the methods defined in an interface must be public. An interface is not designed as a blueprint for classes, but just a way to standardize a common API.

The one big advantage to using interfaces is that a class can implement any number of them. You can still only extend on parent class, but you can implement an unlimited number of interfaces.

Magic Methods
There are a number of “magic methods” that add an assortment to functionality to your classes. Note that PHP reserves the naming of methods prefixed with a double-underscore. Never name any of your methods with this naming scheme!

Some magic methods to take note of are __call, __get, __set and __toString. These are the ones I find most useful.

Finality
You can now use the final keyword to indicate that a method cannot be overridden by a child. You can also declare an entire class as final which prevents it from having any children at all.

The __autoload Function
Using a specially named function, __autoload (there’s that double-underscore again!), you can automatically load object files when PHP encounters a class that hasn’t been defined yet. Instead of large chunks of include’s at the top of your scripts, you can define a simple autoload function to include them automatically.

PHP Code:
function __autoload($class_name) {
require_once "./includes/classes/$class_name.inc.php";
}

Note you can change the autoload function or even add multiple autoload functions using spl_autoload_register and related functions.

Standard PHP Library
PHP now includes a bunch of functionality to solve common problems in the so-named SPL. There’s a lot of cool stuff in there, check it out!

For example, we can finally create classes that can be accessed like arrays by implementing the ArrayAccess interface. If we implement the Iterator interface, we can even let our classes work in situations like the foreach construct.

Miscellaneous Features

Type Hinting
PHP5 introduces limited type hinting. This means you can enforce what kind of variables are passed to functions or class methods. The drawback is that (at this time), it will only work for classes or arrays — so no other scalar types like integers or strings.

To add a type hint to a parameter, you specify the name of the class before the $. Beware that when you specify a class name, the type will be satisfied with all of its subclasses as well.

PHP Code:
function echo_user(User $user) {
echo $user->getUsername();
}

If the passed parameter is not User (or a subclass of User), then PHP will throw a fatal error.

Exceptions
PHP finally introduces exceptions! An exception is basically an error. By using an exception however, you gain more control the simple trigger_error notices we were stuck with before.

An exception is just an object. When an error occurs, you throw an exception. When an exception is thrown, the rest of the PHP code following will not be executed. When you are about to perform something “risky”, surround your code with a try block. If an exception is thrown, then your following catch block is there to intercept the error and handle it accordingly. If there is no catch block, a fatal error occurs.

PHP Code:
try {
$cache->write();
} catch (AccessDeniedException $e) {
die('Could not write the cache, access denied.');
} catch (Exception $e) {
die('An unknown error occurred: ' . $e->getMessage());
}

E_STRICT Error Level
There is a new error level defined as E_STRICT (value 2048). It is not included in E_ALL, if you wish to use this new level you must specify it explicitly. E_STRICT will notify you when you use depreciated code. I suggest you enable this level so you can always stay on top of things.

Foreach Construct and By-Reference Value
The foreach construct now lets you define the ‘value’ as a reference instead of a copy. Though I would suggest against using this feature, as it can cause some problems if you aren’t careful:

PHP Code:
foreach($array as $k => &$v) {
// Nice and easy, no working with $array[$k] anymore
$v = htmlentities($v);
}
// But be careful, this will have an unexpected result because
// $v will still be a reference to the last element of the $array array
foreach($another_array as $k => $v) {

}

 

New Functions
PHP5 introduces a slew of new functions. You can get a list of them from the PHP Manual.

New Extensions
PHP5 also introduces new default extensions.

Compatibility Issues
The PHP manual has a list of changes that will affect backwards compatibility. You should definately read through that page, but here is are three issues I have found particularly tiresome: