Online Visitor Tracking System using CodeIgniter 4, MySQL 8 and AJAX

In this tutorial I am going to show you how you can build an online visitor tracking system using PHP based framework CodeIgniter 4, MySQL 8 and AJAX technique. The similar system for tracking online visitors on web site, I built in past, using CodeIgniter 3 framework.

As a web site owner you would like to the progress to the count of your visitors, page views, etc. because, it gives you overall idea on the website’s analytical measurements. It will also give you how you can make improvements to your the websites.

Prerequisites

PHP 7.4.3, Codeigniter 4.0.4/4.1.4, MySQL 8.0.17/8.0.22

Project Directory

It’s assumed that you have already setup PHP and CodeIgniter in Windows system.

Now I will create a project root directory called codeigniter-4-online-visitor-tracker-system anywhere in the system.

Now move all the directories and files from CodeIgniter framework into the project root directory.

I may not mention the project root directory in subsequent sections and I will assume that I am talking with respect to the project root directory.

MySQL Table

For this example I am going to create and insert few sample data into the table visitors under roytuts database. So create a table visitors under database roytuts in the MySQL server with the below structure.

CREATE TABLE IF NOT EXISTS `visitors` (
  `visitor_id` int unsigned NOT NULL AUTO_INCREMENT,
  `no_of_visits` int unsigned NOT NULL,
  `ip_address` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  `requested_url` tinytext COLLATE utf8mb4_unicode_ci NOT NULL,
  `referer_page` tinytext COLLATE utf8mb4_unicode_ci NOT NULL,
  `page_name` tinytext COLLATE utf8mb4_unicode_ci NOT NULL,
  `query_string` tinytext COLLATE utf8mb4_unicode_ci NOT NULL,
  `user_agent` tinytext COLLATE utf8mb4_unicode_ci NOT NULL,
  `is_unique` tinyint NOT NULL DEFAULT '0',
  `access_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`visitor_id`)
) ENGINE=InnoDB AUTO_INCREMENT=665 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

You can download the whole source code from this tutorial later from the Source Code section.

Database Configuration

You need to setup database connection in order to fetch or write data to the table. The following configuration is done in the file app/Config/Database.php under the default group of database setting. Make sure you change or update the configuration according to yours. You can also setup your database using the .env file.

The main properties I have shown below and you can change according to your values:

...
'username' => 'root',
'password' => 'root',
'database' => 'roytuts',
...
'charset'  => 'utf8mb4',
'DBCollat' => 'utf8mb4_unicode_ci',
...

Create Library

A library, in CodeIgniter is a class with a set of functions, that allows creating an instance of that class and is written in Object Oriented programming approach.

The following library I am going to create will store each visitor details into MySQL database. The following code is written into a file app/Libraries/VisitorTracker.php. The main function in this file is visitor_tracker() that will pass through different validations before a visitor gets logged into the database.

...
function track_visitor() {
	$router = \Config\Services::router();
	
	$track_visitor = TRUE;
	
	if (isset($track_visitor) && $track_visitor === TRUE) {
		$proceed = TRUE;
		
		if ($this->IGNORE_SEARCH_BOTS && $this->is_bot()) {
			$proceed = FALSE;
		}
		
		if ($this->HONOR_DO_NOT_TRACK && !allow_tracking()) {
			$proceed = FALSE;
		}
		
		foreach ($this->CONTROLLER_IGNORE_LIST as $controller) {
			if (strpos(trim($router->controllerName()), $controller) !== FALSE) {
				$proceed = FALSE;
				break;
			}
		}
		
		if (in_array($this->request->getIPAddress(), $this->IP_IGNORE_LIST)) {
			$proceed = FALSE;
		}
		
		if ($proceed === TRUE) {
			$this->log_visitor();
		}
	}
}
...

In the above code snippets I have shown only the important code what I am doing. The whole source code you can later download from the bottom of this tutorial under section Source Code.

First I am checking whether visitor tracking is on or not. Next I am checking whether this visitor is a bot or a user.

Then I am honouring if DNT found in the browser’s http headers. Next I am ignoring the controller class name which is found in the ignore list of controller names.

Finally I am checking the ignore list of IP addresses. If everything is successfully validated then only I am storing the visitor details.

$this->request->getIPAddress() is used to get IP address in CodeIgniter 4 for the client or user.

Configure Events

In CodeIgniter 4, the hooks which was there in CodeIgniter 3, has been replaced by events.

Therefore you need to configure events for the above library class (VisitorTracker). The following entries are added to the app/Config/Events.php file.

First you need to import your VisitorTracker library class at the top of the file.

use App\Libraries\VisitorTracker;

Next you have to add the following lines at the end:

$visitorTracker = new VisitorTracker();
Events::on('post_controller_constructor', [$visitorTracker, 'track_visitor']);

I have created an instance of the VisitorTracker class because the class does not have static method so I cannot use the method directly.

I have used post_controller_constructor with Events::on() to execute the track_visitor() function every time a particular controller class gets loaded.

Model Class

The model class will fetch required data which will be displayed on the chart for a given date. The following source code is written into app/Models/VisitorModel.php file.

if you receive error while executing the below queries in your MySQL database server related to Group By clause then you may check this issue and solution.

In CodeIgniter you can choose two ways of modeling your data – using CodeIgniter’s model and using entity class.

I am using CodeIgniter’s model to create my own model that extends CodeIgniter’s model class. They come out of the box with helper methods for much of the standard ways you would need to interact with a database table, including finding records, updating records, deleting records, and more.

I am creating my own function in the model class to fetch data from the table.

<?php

namespace App\Models;
use CodeIgniter\Model;

class VisitorModel extends Model {

	protected $table = 'visitors';
	
	function get_site_data_for_today() {
        $results = array();
        
		$query = $this->db->query('SELECT SUM(no_of_visits) as visits 
            FROM ' . $this->table . ' 
            WHERE CURDATE()=DATE(access_date)
            LIMIT 1');
			
        if ($query->resultID->num_rows == 1) {
            $row = $query->getRow();
            $results['visits'] = $row->visits;
        }

        return $results;
    }

    function get_site_data_for_last_week() {
        $results = array();
		
        $query = $this->db->query('SELECT SUM(no_of_visits) as visits
            FROM ' . $this->table . '
            WHERE DATE(access_date) >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY
            AND DATE(access_date) < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY 
            LIMIT 1');
			
        if ($query->resultID->num_rows == 1) {
            $row = $query->getRow();
            $results['visits'] = $row->visits;

            return $results;
        }
    }

    function get_chart_data_for_today() {
        $query = $this->db->query('SELECT SUM(no_of_visits) as visits,
                DATE_FORMAT(access_date,"%h %p") AS hour
                FROM ' . $this->table . '
                WHERE CURDATE()=DATE(access_date)
                GROUP BY HOUR(access_date)');
				
        if ($query->resultID->num_rows > 0) {
            return $query->getResult();
        }
		
        return NULL;
    }

    function get_chart_data_for_month_year($month = 0, $year = 0) {
        if ($month == 0 && $year == 0) {
            $month = date('m');
            $year = date('Y');
			
            $query = $this->db->query('SELECT SUM(no_of_visits) as visits,
                DATE_FORMAT(access_date,"%d-%m-%Y") AS day 
                FROM ' . $this->table . '
                WHERE MONTH(access_date)=' . $month . '
                AND YEAR(access_date)=' . $year . '
                GROUP BY DATE(access_date)');
            
			if ($query->resultID->num_rows > 0) {
                return $query->getResult();
            }
        }
		
        if ($month == 0 && $year > 0) {
            $query = $this->db->query('SELECT SUM(no_of_visits) as visits,
                DATE_FORMAT(timestamp,"%M") AS day
                FROM ' . $this->table . '
                WHERE YEAR(access_date)=' . $year . '
                GROUP BY MONTH(access_date)');
            
			if ($query->resultID->num_rows > 0) {
                return $query->getResult();
            }
        }
		
        if ($year == 0 && $month > 0) {
            $year = date('Y');
			
            $query = $this->db->query('SELECT SUM(no_of_visits) as visits,
                DATE_FORMAT(access_date,"%d-%m-%Y") AS day
                FROM ' . $this->table . '
                WHERE MONTH(access_date)=' . $month . '
                AND YEAR(access_date)=' . $year . '
                GROUP BY DATE(access_date)');
				
            if ($query->resultID->num_rows > 0) {
                return $query->getResult();
            }
        }

        if ($year > 0 && $month > 0) {
            $query = $this->db->query('SELECT SUM(no_of_visits) as visits,
                DATE_FORMAT(access_date,"%d-%m-%Y") AS day
                FROM ' . $this->table . '
                WHERE MONTH(access_date)=' . $month . '
                AND YEAR(access_date)=' . $year . '
                GROUP BY DATE(access_date)');
				
            if ($query->resultID->num_rows > 0) {
                return $query->getResult();
            }
        }

        return NULL;
    }
	
}

Helper Functions

Helper is a file with a set of functions in a procedure programming approach. The following functions generate_years() and generate_months() dynamically generate years and months respectively.

The helper file is created with the naming convention as <file_name>_Helper.php and put under the app/Helpers folder. Here I have created file Visitor_Helper.php.

<?php

/**
 * dynamically generate year dropdown
 * @param int $startYear start year
 * @param int $endYear end year
 * @param string $id id of the select-option
 * @return html
 */
if(!function_exists('generate_years')) {
	function generate_years($id = 'year', $startYear = '', $endYear = '') {
		$startYear = (strlen(trim($startYear)) ? $startYear : date('Y') - 10);
		$endYear = (strlen(trim($endYear)) ? $endYear : date('Y'));

		if (!isInt($startYear) || !isInt($endYear)) {
			return 'Year must be integer value!';
		}

		if ((strlen(trim($startYear)) < 4) || (strlen(trim($endYear)) < 4)) {
			return 'Year must be 4 digits in length!';
		}

		if (trim($startYear) > trim($endYear)) {
			return 'Start Year cannot be greater than End Year!';
		}

		//start the select tag
		$html = '<select id="' . $id . '" name="' . $id . '">"n"';
		$html .= '<option value="">-- Year --</option>"n"';
		//echo each year as an option    
		for ($i = $endYear; $i >= $startYear; $i--) {
			$html .= '<option value="' . $i . '">' . $i . '</option>"n"';
		}
		//close the select tag
		$html .= "</select>";

		return $html;
	}
}

/**
 * dynamically generate months dropdown
 * @param string $id id of the select-option
 * @return html
 */
if(!function_exists('generate_months')) {
	function generate_months($id = 'month') {
		//start the select tag
		$html = '<select id="' . $id . '" name="' . $id . '">"n"';
		$html .= '<option value="">-- Month --</option>"n"';
		//echo each month as an option    
		for ($i = 1; $i <= 12; $i++) {
			$timestamp = mktime(0, 0, 0, $i);
			$label = date("F", $timestamp);
			$html .= '<option value="' . $i . '">' . $label . '</option>"n"';
		}
		//close the select tag
		$html .= "</select>";

		return $html;
	}
}

if(!function_exists('isInt')) {
	function isInt($str) {
		return preg_match("/^[1-9][0-9]*$/", $str);
	}
}


/* End of file Visitor_Helper.php */
/* Location: ./app/Helpers/Visitor_Helper.php */

Controller Class

The controller class is responsible for handling request/response from/to end users or clients. The code is written into the file app/Controllers/VisitorController.php file.

In the constructor I have loaded the helper file (Visitor_Helper.php as shown above) and created the instance from the model class.

In the index() function I am loading the required data which need to be displayed on the chart for today’s visits.

The get_chart_data() function is called asynchronously through AJAX technique using jQuery to fetch data from the server for the selected date on the UI (user Interface).

<?php

namespace App\Controllers;

use App\Models\VisitorModel;

class VisitorController extends BaseController {
	
	private $model;
	
	public function __construct() {
		helper(['visitor']);
        $this->model = new VisitorModel();
    }
	
	public function index() {		
        $site_statics_today = $this->model->get_site_data_for_today();
        $site_statics_last_week = $this->model->get_site_data_for_last_week();
        $data['visits_today'] = isset($site_statics_today['visits']) ? $site_statics_today['visits'] : 0;
        $data['visits_last_week'] = isset($site_statics_last_week['visits']) ? $site_statics_last_week['visits'] : 0;
		$chart_data_today = $this->model->get_chart_data_for_today();
		$chart_data_curr_month = $this->model->get_chart_data_for_month_year();
        $data['chart_data_today'] = isset($chart_data_today) ? $chart_data_today : array();
        $data['chart_data_curr_month'] =  isset($chart_data_curr_month) ? $chart_data_curr_month : array();
        
		return view('visitor', $data);
    }

    function get_chart_data() {
        if (isset($_POST)) {
            if (isset($_POST['month']) && strlen($_POST['month']) && isset($_POST['year']) && strlen($_POST['year'])) {
                $month = $_POST['month'];
                $year = $_POST['year'];
                $data = $this->model->get_chart_data_for_month_year($month, $year);
				
                if ($data !== NULL) {
                    foreach ($data as $value) {
                        echo $value->day . "t" . $value->visits . "n";
                    }
                } else {
                    $timestamp = mktime(0, 0, 0, $month);
                    $label = date("F", $timestamp);
                    echo '<div style="width:600px;position:relative;font-weight:bold;top:100px;margin-left:auto;margin-left:auto;color:red;">No data found for the "' . $label . '-' . $year . '"</div>';
                }
            } else if (isset($_POST['month']) && strlen($_POST['month'])) {
                $month = $_POST['month'];
                $data = $this->model->get_chart_data_for_month_year($month);
				
                if ($data !== NULL) {
                    foreach ($data as $value) {
                        echo $value->day . "t" . $value->visits . "n";
                    }
                } else {
                    $timestamp = mktime(0, 0, 0, $month);
                    $label = date("F", $timestamp);
                    echo '<div style="width:600px;position:relative;font-weight:bold;top:100px;margin-left:auto;margin-left:auto;color:red;">No data found for the "' . $label . '"</div>';
                }
            } else if (isset($_POST['year']) && strlen($_POST['year'])) {
                $year = $_POST['year'];
                $data = $this->model->get_chart_data_for_month_year(0, $year);
                if ($data !== NULL) {
                    foreach ($data as $value) {
                        echo $value->day . "t" . $value->visits . "n";
                    }
                } else {
                    echo '<div style="width:600px;position:relative;font-weight:bold;top:100px;margin-left:auto;margin-left:auto;color:red;">No data found for the "' . $year . '"</div>';
                }
            } else {
                $data = $this->model->get_chart_data_for_month_year();
                if ($data !== NULL) {
                    foreach ($data as $value) {
                        echo $value->day . "t" . $value->visits . "n";
                    }
                } else {
                    echo '<div style="width:600px;position:relative;font-weight:bold;top:100px;margin-left:auto;margin-left:auto;color:red;">No data found!</div>';
                }
            }
        }
    }
}

View File

You need to display your data on a chart in a view file. Therefore you will need to create a view file (for example, visitor.php) under app/Views folder.

I have loaded the required JavaScript and jQuery files for the chart data. I am using the CDN (Content Delivery Network) link for the jQuery file. Other JavaScript files I have kept under public/js folder.

The public folder, is the standard folder in CodeIgniter, where you can put all your static resources such as js, css, images, etc. which are accessible easily.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>CodeIgniter 4 MySQL 8 Online Visitor Tracking System</title>
	<meta name="description" content="The small framework with powerful features">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="shortcut icon" type="image/png" href="/favicon.ico"/>
	<script src="https://code.jquery.com/jquery-3.5.1.min.js" crossorigin="anonymous"></script>
	<script type= 'text/javascript' src="js/highcharts.js"></script>
	<script type= 'text/javascript' src="js/exporting.js"></script>	
	<script type= 'text/javascript' src="js/jquery.tsv-0.96.min.js"></script>
</head>
<body>

	<div class="clear"></div>
        <div>
            <div style="font-size: 30px;font-weight: bold; color: #129FEA;">Visits statistics</div>
            <script type="text/javascript">
                $(function () {
                    var chart;
                    $(document).ready(function () {
                        Highcharts.setOptions({
                            colors: ['#32353A']
                        });
                        chart = new Highcharts.Chart({
                            chart: {
                                renderTo: 'container',
                                type: 'column',
                                margin: [50, 30, 80, 60]
                            },
                            title: {
                                text: "Visits Today: <?php echo date('d-m-Y'); ?>"
                            },
                            xAxis: {
                                categories: [
									<?php
									$i = 1;
									$count = count($chart_data_today);
									foreach ($chart_data_today as $data) {
										if ($i == $count) {
											echo "'" . $data->hour . "'";
										} else {
											echo "'" . $data->hour . "',";
										}
										$i++;
									}
									?>
                                ],
                                labels: {
                                    rotation: -45,
                                    align: 'right',
                                    style: {
                                        fontSize: '9px',
                                        fontFamily: 'Tahoma, Verdana, sans-serif'
                                    }
                                }
                            },
                            yAxis: {
                                min: 0,
                                title: {
                                    text: 'Visits'
                                }
                            },
                            legend: {
                                enabled: false
                            },
                            tooltip: {
                                formatter: function () {
                                    return '<b>' + this.x + '</b><br/>' +
                                            'Visits: ' + Highcharts.numberFormat(this.y, 0);
                                }
                            },
                            series: [{
                                    name: 'Visits',
                                    data: [
										<?php
										$i = 1;
										$count = count($chart_data_today);
										foreach ($chart_data_today as $data) {
											if ($i == $count) {
												echo $data->visits;
											} else {
												echo $data->visits . ",";
											}
											$i++;
										}
										?>
                                    ],
                                    dataLabels: {
                                        enabled: false,
                                        rotation: 0,
                                        color: '#F07E01',
                                        align: 'right',
                                        x: -3,
                                        y: 20,
                                        formatter: function () {
                                            return this.y;
                                        },
                                        style: {
                                            fontSize: '11px',
                                            fontFamily: 'Verdana, sans-serif'
                                        }
                                    },
                                    pointWidth: 20
                                }]
                        });
                    });
                });
            </script>
            <div id="container" style="min-width: 300px; height: 180px; margin: 0 auto"></div>
        </div>
        <div class="clear"> </div>
        <div>
            <div>
                <div>
                    <h4>Today</h4> <?php echo $visits_today; ?> Visits
                </div>
                <div>
                    <h4>Last week</h4> <?php echo $visits_last_week; ?> Visits
                </div>
            </div>
        </div>
        <div class="clear"> </div>
        <div>
            <div><span style="font-size: 30px;font-weight: bold; color: #129FEA;">Check Visits statistics</span>
                <div style="float: right;margin: -4px 20px 0 5px;">
                    <form id="select_month_year" style="margin: 0;padding: 0;" method="post">
						<?= csrf_field() ?>
                        <?php echo generate_months() . '  ' . generate_years(); ?>
                        <input type="button" name="submit" id="chart_submit_btn" value="Get Data"/>
                    </form>
                </div>
            </div>
            <script type="text/javascript">
                $(function () {
                    var chart;
                    $(document).ready(function () {
                        Highcharts.setOptions({
                            colors: ['#32353A']
                        });
                        chart = new Highcharts.Chart({
                            chart: {
                                renderTo: 'month_year_container',
                                type: 'column',
                                margin: [50, 30, 80, 60]
                            },
                            title: {
                                text: 'Visits'
                            },
                            xAxis: {
                                categories: [
									<?php
									$i = 1;
									$count = count($chart_data_curr_month);
									foreach ($chart_data_curr_month as $data) {
										if ($i == $count) {
											echo "'" . $data->day . "'";
										} else {
											echo "'" . $data->day . "',";
										}
										$i++;
									}
									?>
                                ],
                                labels: {
                                    rotation: -45,
                                    align: 'right',
                                    style: {
                                        fontSize: '9px',
                                        fontFamily: 'Tahoma, Verdana, sans-serif'
                                    }
                                }
                            },
                            yAxis: {
                                min: 0,
                                title: {
                                    text: 'Visits'
                                }
                            },
                            legend: {
                                enabled: false
                            },
                            tooltip: {
                                formatter: function () {
                                    return '<b>' + this.x + '</b><br/>' +
                                            'Visits: ' + Highcharts.numberFormat(this.y, 0);
                                }
                            },
                            series: [{
                                    name: 'Visits',
                                    data: [
										<?php
										$i = 1;
										$count = count($chart_data_curr_month);
										foreach ($chart_data_curr_month as $data) {
											if ($i == $count) {
												echo $data->visits;
											} else {
												echo $data->visits . ",";
											}
											$i++;
										}
										?>
                                    ],
                                    dataLabels: {
                                        enabled: false,
                                        rotation: 0,
                                        color: '#F07E01',
                                        align: 'right',
                                        x: -3,
                                        y: 20,
                                        formatter: function () {
                                            return this.y;
                                        },
                                        style: {
                                            fontSize: '11px',
                                            fontFamily: 'Verdana, sans-serif'
                                        }
                                    },
                                    pointWidth: 20
                                }]
                        });
                    });
                });
            </script>
            <script type="text/javascript">
                $("#chart_submit_btn").click(function (e) {
                    // get the token value
                    var cct = $("input[name=csrf_token_name]").val();
                    //reset #container
                    $('#month_year_container').html('');
                    $.ajax({
                        url: "<?= site_url('visitorcontroller/get_chart_data') ?>", //The url where the server req would we made.
                        //async: false,
                        type: "POST", //The type which you want to use: GET/POST
                        data: $('#select_month_year').serialize(), //The variables which are going.
                        dataType: 'html', //Return data type (what we expect).
                        csrf_token_name: cct,
                        success: function (response) {
                            if (response.toLowerCase().indexOf("no data found") >= 0) {
                                $('#month_year_container').html(response);
                            } else {
                                //build the chart
                                var tsv = response.split(/n/g);
                                var count = tsv.length - 1;
                                var cats_val = new Array();
                                var visits_val = new Array();
                                for (i = 0; i < count; i++) {
                                    var line = tsv[i].split(/t/);
                                    var line_data = line.toString().split(",");
                                    var date = line_data[0];
                                    var visits = line_data[1];
                                    cats_val[i] = date;
                                    visits_val[i] = parseInt(visits);
                                }
                                var _categories = cats_val;
                                var _data = visits_val;
                                var chart;
                                $(document).ready(function () {
                                    Highcharts.setOptions({
                                        colors: ['#32353A']
                                    });
                                    chart = new Highcharts.Chart({
                                        chart: {
                                            renderTo: 'month_year_container',
                                            type: 'column',
                                            margin: [50, 30, 80, 60]
                                        },
                                        title: {
                                            text: 'Visits'
                                        },
                                        xAxis: {
                                            categories: _categories,
                                            labels: {
                                                rotation: -45,
                                                align: 'right',
                                                style: {
                                                    fontSize: '9px',
                                                    fontFamily: 'Tahoma, Verdana, sans-serif'
                                                }
                                            }
                                        },
                                        yAxis: {
                                            min: 0,
                                            title: {
                                                text: 'Visits'
                                            }
                                        },
                                        legend: {
                                            enabled: false
                                        },
                                        tooltip: {
                                            formatter: function () {
                                                return '<b>' + this.x + '</b><br/>' +
                                                        'Visits: ' + Highcharts.numberFormat(this.y, 0);
                                            }
                                        },
                                        series: [{
                                                name: 'Visits',
                                                data: _data,
                                                dataLabels: {
                                                    enabled: false,
                                                    rotation: 0,
                                                    color: '#F07E01',
                                                    align: 'right',
                                                    x: -3,
                                                    y: 20,
                                                    formatter: function () {
                                                        return this.y;
                                                    },
                                                    style: {
                                                        fontSize: '11px',
                                                        fontFamily: 'Verdana, sans-serif'
                                                    }
                                                },
                                                pointWidth: 20
                                            }]
                                    });
                                });
                            }
                        }
                    });
                });
            </script>
        <div id="month_year_container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>
    </div>

</body>
</html>

Route Configuration

You also need to configure route to point to your own controller file instead of the default controller that comes with the framework.

Search for the line $routes->setDefaultController('Home'); and replace it by $routes->setDefaultController('VisitorController');.

Search for the line $routes->get('/', 'Home::index'); and replace it by your controller name, for this example, $routes->get('/', 'VisitorController::index');.

These route configurations are done on the file app/Config/Routes.php.

Testing the Application

I am not going to use any external server but CLI command to run the application. Make sure you start the MySQL database server before you start your application. If you want to use external server to run your application you can use. Execute the following command on your project root directory to run your application.

php spark serve

Your application will be running on localhost and port 8080.

The URL http://localhost:8080/ will show you the following page on the browser for today’s visitor details:

online visitor tracking system using codeigniter 4 mysql 8 ajax

For a selected date, for example, for the month August 2020, if data available then you will find the below output:

online visitor tracking system using codeigniter 4 mysql 8 ajax

That’s all about how to build a basic visitor tracking system using CodeIgniter 4, MySQL 8 and AJAX.

Source Code

Download

3 thoughts on “Online Visitor Tracking System using CodeIgniter 4, MySQL 8 and AJAX

  1. Hey, Good read! enjoyed it all, very nice use of hooks right there, I’ve been working on CI for a while now and loving it, currently working on a CI4 project and now I’m in need of tracking visits, I like this approach, definitely inspiring and going to use bits of for sure, thanks!

  2. I have Codeigniter3.1.11. My hook is not registering user if I use same browser.
    I need to log anonymous user(s) no matter if they have visited 2 min back.

    Regards,
    Rahul

Leave a Reply

Your email address will not be published. Required fields are marked *