Codeigniter 3 MySQL Online Visitor Tracking System

Table of Contents

Introduction

Every website owner would like to know the progress to the count of the online visitors because it gives them overall idea on the website’s analytical measurements. It will also give them how to make improvements on the websites. This example will give you an idea how to implement such system to track visitors who visit your website on daily basis. This example also shows how to use hooks in Codeigniter framework.

You may also look into another tutorial how to use hooks Display site maintenence message using Codeigniter.

Related Post:

Prerequisites

Codeigniter 3.0.6 – 3.1.11, PHP 5.5 – 7.4.27, MySQL 5.5 – 8.0.26

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-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.

A typical directory structure for the project would be as shown below. Here assests directory will contain static resources, such as, css, js, images.

codeigniter 3 visitor system

Autoload Configuration

Now update application/config/autoload.php file for auto-loading html, url, file, form and session.

$autoload['helper'] = array('html', 'url', 'file', 'form');
$autoload['libraries'] = array('database', 'session', 'site_config');

Encryption Key

Add encryption key in application/config/config.php file. This encryption key is required to work with sessions in CodeIgniter 3.

$config['encryption_key'] = '2d8+e6]K0?ocWp7&`K)>6Ky"|.x|%nuwafC~S/+6_mZI9/17y=sKKG.;Tt}k';

Creating Library

Create application/libraries/site_config.php file with the following source code. This library is useful for generating months and years dynamically in PHP.

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * Description of Site_Config
 *
 * @author https://roytuts.com
 */
class Site_Config {

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

        if (!$this->holds_int($startYear) || !$this->holds_int($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
     */
    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;
    }

    private function holds_int($str) {
        return preg_match("/^[1-9][0-9]*$/", $str);
    }

}

/* End of file Site_Config.php */
/* Location: ./application/libraries/Site_Config.php */

Creating Hooks

Create application/hooks/Track_Visitor.php file with the following source code. Hook is used to execute some actions before or after something.

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * Description of track_visitor
 *
 * @author https://roytuts.com
 */
class Track_Visitor {
    /*
     * Defines how many seconds a hit should be rememberd for. This prevents the
     * database from perpetually increasing in size. Thirty days (the default)
     * works well. If someone visits a page and comes back in a month, it will be
     * counted as another unique hit.
     */

    //private $HIT_OLD_AFTER_SECONDS = 2592000; // default: 30 days.

    /*
     * Don't count hits from search robots and crawlers. 
     */
    private $IGNORE_SEARCH_BOTS = TRUE;

    /*
     * Don't count the hit if the browser sends the DNT: 1 header.
     */
    private $HONOR_DO_NOT_TRACK = FALSE;

    /*
     * ignore controllers e.g. 'admin'
     */
    private $CONTROLLER_IGNORE_LIST = array(
        'admin'
    );

    /*
     * ignore ip address
     */
    private $IP_IGNORE_LIST = array(
        '127.0.0.1'
    );

    /*
     * visitor tracking table
     */
    private $site_log = "site_log";

    function __construct() {
        $this->ci = & get_instance();
        $this->ci->load->library('user_agent');
    }

    function visitor_track() {
        $track_visitor = TRUE;
        if (isset($track_visitor) && $track_visitor === TRUE) {
            $proceed = TRUE;
            if ($this->IGNORE_SEARCH_BOTS && $this->is_search_bot()) {
                $proceed = FALSE;
            }
            if ($this->HONOR_DO_NOT_TRACK && !allow_tracking()) {
                $proceed = FALSE;
            }
            foreach ($this->CONTROLLER_IGNORE_LIST as $controller) {
                if (strpos(trim($this->ci->router->fetch_class()), $controller) !== FALSE) {
                    $proceed = FALSE;
                    break;
                }
            }
            if (in_array($this->ci->input->server('REMOTE_ADDR'), $this->IP_IGNORE_LIST)) {
                $proceed = FALSE;
            }
            if ($proceed === TRUE) {
                $this->log_visitor();
            }
        }
    }

    private function log_visitor() {
        if ($this->track_session() === TRUE) {
            //update the visitor log in the database, based on the current visitor
            //id held in $_SESSION["visitor_id"]
            $temp_visitor_id = $this->ci->session->userdata('visitor_id');
            $visitor_id = isset($temp_visitor_id) ? $temp_visitor_id : 0;
            $no_of_visits = $this->ci->session->userdata('visits_count');
            $current_page = current_url();
            $temp_current_page = $this->ci->session->userdata('current_page');
            if (isset($temp_current_page) && $temp_current_page != $current_page) {
                $page_name = $this->ci->router->fetch_class() . '/' . $this->ci->router->fetch_method();
                $page_length = strlen(trim($this->ci->router->fetch_class() . '/' . $this->ci->router->fetch_method()));
                $query_params = trim(substr($this->ci->uri->uri_string(), $page_length + 1));
                $query_string = strlen($query_params) ? $query_params : '';
                $data = array(
                    'no_of_visits' => $no_of_visits,
                    'ip_address' => $this->ci->input->server('REMOTE_ADDR'),
                    'requested_url' => $this->ci->input->server('REQUEST_URI'),
                    'referer_page' => $this->ci->agent->referrer(),
                    'user_agent' => $this->ci->agent->agent_string(),
                    'page_name' => $page_name,
                    'query_string' => $query_string
                );
                $this->ci->db->insert($this->site_log, $data);
                $this->ci->session->set_userdata('current_page', $current_page);
            }
        } else {
            $page_name = $this->ci->router->fetch_class() . '/' . $this->ci->router->fetch_method();
            $page_length = strlen(trim($this->ci->router->fetch_class() . '/' . $this->ci->router->fetch_method()));
            $query_params = trim(substr($this->ci->uri->uri_string(), $page_length + 1));
            $query_string = strlen($query_params) ? $query_params : '';
            $data = array(
                'ip_address' => $this->ci->input->server('REMOTE_ADDR'),
                'requested_url' => $this->ci->input->server('REQUEST_URI'),
                'referer_page' => $this->ci->agent->referrer(),
                'user_agent' => $this->ci->agent->agent_string(),
                'page_name' => $page_name,
                'query_string' => $query_string
            );
            $result = $this->ci->db->insert($this->site_log, $data);
            if ($result === FALSE) {
                /**
                 * find the next available visitor_id for the database
                 * to assign to this person
                 */
                $this->ci->session->set_userdata('track_session', FALSE);
            } else {
                /**
                 * find the next available visitor_id for the database
                 * to assign to this person
                 */
                $this->ci->session->set_userdata('track_session', TRUE);
                $entry_id = $this->ci->db->insert_id();
                $query = $this->ci->db->query('select max(visits_count) as next from ' .
                        $this->site_log . ' limit 1');
                $count = 0;
                if ($query->num_rows() == 1) {
                    $row = $query->row();
                    if ($row->next == NULL || $row->next == 0) {
                        $count = 1;
                    } else {
                        $count++;
                    }
                }
                //update the visitor entry with the new visitor id
                //Note, that we do it in this way to prevent a "race condition"
                $this->ci->db->where('site_log_id', $entry_id);
                $data = array(
                    'visits_count' => $count
                );
                $this->ci->db->update($this->site_log, $data);
                //place the current visitor_id into the session so we can use it on
                //subsequent visits to track this person
                $this->ci->session->set_userdata('visits_count', $count);
                //save the current page to session so we don't track if someone just refreshes the page
                $current_page = current_url();
                $this->ci->session->set_userdata('current_page', $current_page);
            }
        }
    }

    /**
     * check track_session
     * 
     * @return	bool
     */
    private function track_session() {
        return ($this->ci->session->userdata('track_session') === TRUE ? TRUE : FALSE);
    }

    /**
     * check whether bot
     * 
     * @return	bool
     */
    private function is_search_bot() {
        // Of course, this is not perfect, but it at least catches the major
        // search engines that index most often.
        $spiders = array(
            "abot",
            "dbot",
            "ebot",
            "hbot",
            "kbot",
            "lbot",
            "mbot",
            "nbot",
            "obot",
            "pbot",
            "rbot",
            "sbot",
            "tbot",
            "vbot",
            "ybot",
            "zbot",
            "bot.",
            "bot/",
            "_bot",
            ".bot",
            "/bot",
            "-bot",
            ":bot",
            "(bot",
            "crawl",
            "slurp",
            "spider",
            "seek",
            "accoona",
            "acoon",
            "adressendeutschland",
            "ah-ha.com",
            "ahoy",
            "altavista",
            "ananzi",
            "anthill",
            "appie",
            "arachnophilia",
            "arale",
            "araneo",
            "aranha",
            "architext",
            "aretha",
            "arks",
            "asterias",
            "atlocal",
            "atn",
            "atomz",
            "augurfind",
            "backrub",
            "bannana_bot",
            "baypup",
            "bdfetch",
            "big brother",
            "biglotron",
            "bjaaland",
            "blackwidow",
            "blaiz",
            "blog",
            "blo.",
            "bloodhound",
            "boitho",
            "booch",
            "bradley",
            "butterfly",
            "calif",
            "cassandra",
            "ccubee",
            "cfetch",
            "charlotte",
            "churl",
            "cienciaficcion",
            "cmc",
            "collective",
            "comagent",
            "combine",
            "computingsite",
            "csci",
            "curl",
            "cusco",
            "daumoa",
            "deepindex",
            "delorie",
            "depspid",
            "deweb",
            "die blinde kuh",
            "digger",
            "ditto",
            "dmoz",
            "docomo",
            "download express",
            "dtaagent",
            "dwcp",
            "ebiness",
            "ebingbong",
            "e-collector",
            "ejupiter",
            "emacs-w3 search engine",
            "esther",
            "evliya celebi",
            "ezresult",
            "falcon",
            "felix ide",
            "ferret",
            "fetchrover",
            "fido",
            "findlinks",
            "fireball",
            "fish search",
            "fouineur",
            "funnelweb",
            "gazz",
            "gcreep",
            "genieknows",
            "getterroboplus",
            "geturl",
            "glx",
            "goforit",
            "golem",
            "grabber",
            "grapnel",
            "gralon",
            "griffon",
            "gromit",
            "grub",
            "gulliver",
            "hamahakki",
            "harvest",
            "havindex",
            "helix",
            "heritrix",
            "hku www octopus",
            "homerweb",
            "htdig",
            "html index",
            "html_analyzer",
            "htmlgobble",
            "hubater",
            "hyper-decontextualizer",
            "ia_archiver",
            "ibm_planetwide",
            "ichiro",
            "iconsurf",
            "iltrovatore",
            "image.kapsi.net",
            "imagelock",
            "incywincy",
            "indexer",
            "infobee",
            "informant",
            "ingrid",
            "inktomisearch.com",
            "inspector web",
            "intelliagent",
            "internet shinchakubin",
            "ip3000",
            "iron33",
            "israeli-search",
            "ivia",
            "jack",
            "jakarta",
            "javabee",
            "jetbot",
            "jumpstation",
            "katipo",
            "kdd-explorer",
            "kilroy",
            "knowledge",
            "kototoi",
            "kretrieve",
            "labelgrabber",
            "lachesis",
            "larbin",
            "legs",
            "libwww",
            "linkalarm",
            "link validator",
            "linkscan",
            "lockon",
            "lwp",
            "lycos",
            "magpie",
            "mantraagent",
            "mapoftheinternet",
            "marvin/",
            "mattie",
            "mediafox",
            "mediapartners",
            "mercator",
            "merzscope",
            "microsoft url control",
            "minirank",
            "miva",
            "mj12",
            "mnogosearch",
            "moget",
            "monster",
            "moose",
            "motor",
            "multitext",
            "muncher",
            "muscatferret",
            "mwd.search",
            "myweb",
            "najdi",
            "nameprotect",
            "nationaldirectory",
            "nazilla",
            "ncsa beta",
            "nec-meshexplorer",
            "nederland.zoek",
            "netcarta webmap engine",
            "netmechanic",
            "netresearchserver",
            "netscoop",
            "newscan-online",
            "nhse",
            "nokia6682/",
            "nomad",
            "noyona",
            "nutch",
            "nzexplorer",
            "objectssearch",
            "occam",
            "omni",
            "open text",
            "openfind",
            "openintelligencedata",
            "orb search",
            "osis-project",
            "pack rat",
            "pageboy",
            "pagebull",
            "page_verifier",
            "panscient",
            "parasite",
            "partnersite",
            "patric",
            "pear.",
            "pegasus",
            "peregrinator",
            "pgp key agent",
            "phantom",
            "phpdig",
            "picosearch",
            "piltdownman",
            "pimptrain",
            "pinpoint",
            "pioneer",
            "piranha",
            "plumtreewebaccessor",
            "pogodak",
            "poirot",
            "pompos",
            "poppelsdorf",
            "poppi",
            "popular iconoclast",
            "psycheclone",
            "publisher",
            "python",
            "rambler",
            "raven search",
            "roach",
            "road runner",
            "roadhouse",
            "robbie",
            "robofox",
            "robozilla",
            "rules",
            "salty",
            "sbider",
            "scooter",
            "scoutjet",
            "scrubby",
            "search.",
            "searchprocess",
            "semanticdiscovery",
            "senrigan",
            "sg-scout",
            "shai'hulud",
            "shark",
            "shopwiki",
            "sidewinder",
            "sift",
            "silk",
            "simmany",
            "site searcher",
            "site valet",
            "sitetech-rover",
            "skymob.com",
            "sleek",
            "smartwit",
            "sna-",
            "snappy",
            "snooper",
            "sohu",
            "speedfind",
            "sphere",
            "sphider",
            "spinner",
            "spyder",
            "steeler/",
            "suke",
            "suntek",
            "supersnooper",
            "surfnomore",
            "sven",
            "sygol",
            "szukacz",
            "tach black widow",
            "tarantula",
            "templeton",
            "/teoma",
            "t-h-u-n-d-e-r-s-t-o-n-e",
            "theophrastus",
            "titan",
            "titin",
            "tkwww",
            "toutatis",
            "t-rex",
            "tutorgig",
            "twiceler",
            "twisted",
            "ucsd",
            "udmsearch",
            "url check",
            "updated",
            "vagabondo",
            "valkyrie",
            "verticrawl",
            "victoria",
            "vision-search",
            "volcano",
            "voyager/",
            "voyager-hc",
            "w3c_validator",
            "w3m2",
            "w3mir",
            "walker",
            "wallpaper",
            "wanderer",
            "wauuu",
            "wavefire",
            "web core",
            "web hopper",
            "web wombat",
            "webbandit",
            "webcatcher",
            "webcopy",
            "webfoot",
            "weblayers",
            "weblinker",
            "weblog monitor",
            "webmirror",
            "webmonkey",
            "webquest",
            "webreaper",
            "websitepulse",
            "websnarf",
            "webstolperer",
            "webvac",
            "webwalk",
            "webwatch",
            "webwombat",
            "webzinger",
            "wget",
            "whizbang",
            "whowhere",
            "wild ferret",
            "worldlight",
            "wwwc",
            "wwwster",
            "xenu",
            "xget",
            "xift",
            "xirq",
            "yandex",
            "yanga",
            "yeti",
            "yodao",
            "zao/",
            "zippp",
            "zyborg"
        );

        $agent = strtolower($this->ci->agent->agent_string());

        foreach ($spiders as $spider) {
            if (strpos($agent, $spider) !== FALSE)
                return TRUE;
        }

        return FALSE;
    }

}

/* End of file track_visitor.php */
/* Location: ./application/hooks/Track_Visitor.php */

Hooks Configuration

Modify file application/config/hooks.php to add the following configuration for hooks.

/*
  | -------------------------------------------------------------------------
  | Track Visitor
  | -------------------------------------------------------------------------
  | log visitor info
  |
 */
$hook['post_controller_constructor'][] = array(
    'class' => 'Track_Visitor',
    'function' => 'visitor_track',
    'filename' => 'Track_Visitor.php',
    'filepath' => 'hooks'
);

Database Configuration

Go to location application/config/database.php file and change database parameter values for below parameters.

$db['default']['username'] = 'root'; //your database username
$db['default']['password'] = ''; //your database password
$db['default']['database'] = 'roytuts'; //your MySQL database name

MySQL Table

Create a MySQL table site_log in roytuts database:

USE `roytuts`;

/*Table structure for table `site_log` */

DROP TABLE IF EXISTS `site_log`;

CREATE TABLE `site_log` (
  `site_log_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `no_of_visits` int(10) unsigned NOT NULL,
  `ip_address` varchar(20) NOT NULL,
  `requested_url` tinytext NOT NULL,
  `referer_page` tinytext NOT NULL,
  `page_name` tinytext NOT NULL,
  `query_string` tinytext NOT NULL,
  `user_agent` tinytext NOT NULL,
  `is_unique` tinyint(1) NOT NULL DEFAULT '0',
  `access_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`site_log_id`)
) ENGINE=InnoDB AUTO_INCREMENT=659 DEFAULT CHARSET=utf8;

Inserting Data

Dump some data into database table – site_log. Remember the dummy data are old data.

/*Data for the table `site_log` */

insert  into `site_log`(`site_log_id`,`no_of_visits`,`ip_address`,`requested_url`,`referer_page`,`page_name`,`query_string`,`user_agent`,`is_unique`,`access_date`) values (628,1,'::1','/blog/faqs','http://localhost/blog/blog/blogs','faqs/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-09 04:36:39'),(629,1,'::1','/blog/faqs/interview_faqs','http://localhost/blog/blog/blogs','faqs/interview_faqs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2013-11-09 04:36:39'),(630,1,'::1','/blog/','http://localhost/blog/faqs/interview_faqs','home/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2013-11-09 04:36:40'),(631,1,'::1','/blog/blog','http://localhost/blog/faqs/interview_faqs','blog/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2013-11-09 04:36:40'),(632,1,'::1','/blog/blog/blogs','http://localhost/blog/faqs/interview_faqs','blog/blogs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-01 04:38:47'),(633,1,'::1','/blog/faqs','http://localhost/blog/blog/blogs','faqs/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-01 04:38:47'),(634,1,'::1','/blog/faqs/interview_faqs','http://localhost/blog/blog/blogs','faqs/interview_faqs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-01 04:38:47'),(635,1,'::1','/blog/','http://localhost/blog/faqs/interview_faqs','home/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-02 04:38:47'),(636,1,'::1','/blog/blog','http://localhost/blog/faqs/interview_faqs','blog/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-02 04:38:47'),(637,1,'::1','/blog/blog/blogs','http://localhost/blog/faqs/interview_faqs','blog/blogs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-03 04:38:47'),(638,1,'::1','/blog/faqs','http://localhost/blog/blog/blogs','faqs/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-04 04:38:47'),(639,1,'::1','/blog/faqs/interview_faqs','http://localhost/blog/blog/blogs','faqs/interview_faqs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-04 04:38:47'),(640,1,'::1','/blog/','http://localhost/blog/faqs/interview_faqs','home/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-05 04:38:47'),(641,1,'::1','/blog/blog','http://localhost/blog/faqs/interview_faqs','blog/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-05 04:38:47'),(642,1,'::1','/blog/blog/blogs','http://localhost/blog/faqs/interview_faqs','blog/blogs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-05 04:38:47'),(643,1,'::1','/blog/about','http://localhost/blog/blog/blogs','about/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-03 04:38:47'),(644,1,'::1','/blog/contact','http://localhost/blog/about','contact/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-03 04:38:47'),(645,1,'::1','/blog/','http://localhost/blog/contact','home/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-03 04:38:47'),(646,1,'::1','/blog/blog','http://localhost/blog/contact','blog/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-03 04:38:47'),(647,1,'::1','/blog/blog/blogs','http://localhost/blog/contact','blog/blogs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-05 04:38:47'),(648,1,'::1','/blog/','http://localhost/blog/blog/blogs','home/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-05 04:38:47'),(649,1,'::1','/blog/blog','http://localhost/blog/blog/blogs','blog/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-04 04:38:47'),(650,1,'::1','/blog/blog/blogs','http://localhost/blog/blog/blogs','blog/blogs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-04 04:38:47'),(651,1,'::1','/blog/faqs','http://localhost/blog/blog/blogs','faqs/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-12 07:39:47'),(652,1,'::1','/blog/faqs/interview_faqs','http://localhost/blog/blog/blogs','faqs/interview_faqs','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-12 03:39:47'),(653,1,'::1','/blog/faqs/interview_faqs/jsf','http://localhost/blog/faqs/interview_faqs','faqs/interview_faqs','jsf','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-12 03:39:47'),(654,1,'::1','/blog/faqs/interview_faqs/struts2','http://localhost/blog/faqs/interview_faqs/jsf','faqs/interview_faqs','struts2','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-12 02:39:47'),(655,1,'::1','/blog/faqs/interview_faqs/hibernate','http://localhost/blog/faqs/interview_faqs/struts2','faqs/interview_faqs','hibernate','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-12 06:39:47'),(656,1,'::1','/blog/faqs/interview_faqs/ibatis','http://localhost/blog/faqs/interview_faqs/hibernate','faqs/interview_faqs','ibatis','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-12 04:39:47'),(657,1,'::1','/blog/signin','http://localhost/blog/faqs/interview_faqs/ibatis','signin/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2016-08-12 04:39:47'),(658,1,'::1','/blog/account','http://localhost/blog/signin','account/index','','Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0',0,'2013-11-09 04:39:53');

Model Class

Create a model file visitormodel.php under application/models directory with the below source code:

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * Description of visitormodel
 *
 * @author https://roytuts.com
 */
class VisitorModel extends CI_Model {

    private $site_log = 'site_log';   //site log

    function __construct() {
        
    }

    function get_site_data_for_today() {
        $results = array();
        $query = $this->db->query('SELECT SUM(no_of_visits) as visits 
            FROM ' . $this->site_log . ' 
            WHERE CURDATE()=DATE(access_date)
            LIMIT 1');
        if ($query->num_rows() == 1) {
            $row = $query->row();
            $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->site_log . '
            WHERE DATE(access_date) >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY
            AND DATE(access_date) < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY 
            LIMIT 1');
        if ($query->num_rows() == 1) {
            $row = $query->row();
            $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->site_log . '
                WHERE CURDATE()=DATE(access_date)
                GROUP BY HOUR(access_date)');
        if ($query->num_rows() > 0) {
            return $query->result();
        }
        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->site_log . '
                WHERE MONTH(access_date)=' . $month . '
                AND YEAR(access_date)=' . $year . '
                GROUP BY DATE(access_date)');
            if ($query->num_rows() > 0) {
                return $query->result();
            }
        }
        if ($month == 0 && $year > 0) {
            $query = $this->db->query('SELECT SUM(no_of_visits) as visits,
                DATE_FORMAT(timestamp,"%M") AS day
                FROM ' . $this->site_log . '
                WHERE YEAR(access_date)=' . $year . '
                GROUP BY MONTH(access_date)');
            if ($query->num_rows() > 0) {
                return $query->result();
            }
        }
        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->site_log . '
                WHERE MONTH(access_date)=' . $month . '
                AND YEAR(access_date)=' . $year . '
                GROUP BY DATE(access_date)');
            if ($query->num_rows() > 0) {
                return $query->result();
            }
        }

        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->site_log . '
                WHERE MONTH(access_date)=' . $month . '
                AND YEAR(access_date)=' . $year . '
                GROUP BY DATE(access_date)');
            if ($query->num_rows() > 0) {
                return $query->result();
            }
        }

        return NULL;
    }

}

/* End of file visitormodel.php */
/* Location: ./application/models/visitormodel.php */

Controller Class

Create a controller file visitorcontroller.php under application/controllers with the following source code.

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * Description of visitorcontroller
 *
 * @author https://roytuts.com
 */
class VisitorController extends CI_Controller {

    function __construct() {
        parent::__construct();
        $this->load->library('form_validation');
        $this->load->model('visitormodel', 'vm');
    }

    public function index() {
        $site_statics_today = $this->vm->get_site_data_for_today();
        $site_statics_last_week = $this->vm->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;
        $data['chart_data_today'] = $this->vm->get_chart_data_for_today();
        $data['chart_data_curr_month'] = $this->vm->get_chart_data_for_month_year();
        $this->load->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->vm->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->vm->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->vm->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->vm->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>';
                }
            }
        }
    }

}

/* End of file visitorcontroller.php */
/* Location: ./application/controllers/visitorcontroller.php */

View File

Create a view file visitor.php under application/views.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Codeigniter Vistor Tracking System</title>
        <!--<script type= 'text/javascript' src="<?php //echo base_url(); ?>assets/js/jquery-1.9.1.min.js"></script>-->
        <script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
        <script type= 'text/javascript' src="<?php echo base_url(); ?>assets/js/exporting.js"></script>
        <script type= 'text/javascript' src="<?php echo base_url(); ?>assets/js/highcharts.js"></script>
        <script type= 'text/javascript' src="<?php echo base_url(); ?>assets/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">
                        <?php echo form_hidden($this->security->get_csrf_token_name(), $this->security->get_csrf_hash()); ?>
                        <?php echo $this->site_config->generate_months() . '  ' . $this->site_config->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: "http://localhost/ci3/index.php/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>

Defining Route

Modify file application/config/routes.php file to point to the correct controller file.

$route['default_controller'] = 'visitorcontroller';

Static Resources

Download assets directory.

assets

Testing Visitor Tracking System

If everything is fine then run the application. You will get the output in the browser. Remember the data shown here are old data.

codeigniter visitor tracking system

Source Code

Download

1 thought on “Codeigniter 3 MySQL Online Visitor Tracking System

  1. It worked for me… it worked for me… it’s normally recording at the first recording that blocks because $temp_current_page = $this->ci->session->userdata(‘current_page’); is NULL so the condition ( if (isset($temp_current_page) && $temp_current_page != $current_page) is not respected and therefore no recording will be done

Leave a Reply

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