Codeigniter Online Visitor Tracking System

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

Prerequisites

Netbeans 8.1
XAMPP in Windows
Codeigniter 3.0.6

Configure XAMPP and Netbeans

From Netbeans IDE go to Tools->Options. Click on PHP. Now on tab “General” browse the file for “PHP 5 Interpreter”. The php interpreter file generally placed inside the <physical drive in Windows OS>:xamppphpphp.exe

Configure Codeigniter and Netbeans

Create a new PHP project in Netbeans. Then remove the index.php file from the newly created project. Now copy the extracted files from Codeigniter 3.0.6 to the newly created project directory.

Directory Structure

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

nested categories codeigniter

Step 1. Now modify <root directory>/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');

Add encryption key in ci3/application/config/config.php file

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

Create ci3/application/libraries/site_config.php file with the following source code

<?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 */

Create ci3/application/hooks/Track_Visitor.php file with the following source code

<?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 */

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

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

Step 2. Go to location ci3/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

Step 3. Create a MySQL table 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;

Step 4. Dump some data into database table – site_log

/*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');

Step 5. Create a model file visitormodel.php under ci3/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 */

Step 6. Create a controller file visitorcontroller.php under ci3/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 */

Step 7. Create a view file visitor.php under ci3/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 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">&nbsp;</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">&nbsp;</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() . '&nbsp;&nbsp;' . $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>

Step 8. Modify file ci3/application/config/routes.php file

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

Step 9. Download assets directory.

assets

Step 10. If everything is fine then run the application. You will get the output in the browser.

codeigniter visitor tracking system

Thanks for reading.

Soumitra Roy Sarkar

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on JEE Tutorials Twitter Facebook  Google Plus Linkedin Or Email Me

16 Replies to “Codeigniter Online Visitor Tracking System”

  1. Hello Soumitra,

    I am getting Unable to load the requested class: Page_hit_counter error so can you please give me this file Page_hit_counter.php.

  2. Hi!
    Good job. however, I noticed that the names of database columns do not correspond to the names of the class Track_Visitor. For example request_uri and requested_url. Similarly with visitormodel (visits_count and no_of_visits).
    I also had a problem with functions siteconfig-> get_db_table_prefix () and siteconfig-> track_visitor ().
    After taking the necessary amendments graph works, but only for the current day. Do you foresee update your code?
    Regards

    1. How did you do to resolve the issue with functions siteconfig-> get_db_table_prefix () and siteconfig-> track_visitor () ?

      Regards

  3. Hi,
    Your code in not inserting the record to the table. Do I need to call any function in controller. However I called library in my default controller. But still it is not inserting the record. Please guide.

  4. hi
    tnx for visitor
    but i have error for first viste
    Error Number: 1054
    Unknown column ‘visits_count’ in ‘field list’
    select max(visits_count) as next from site_log limit 1
    Filename: hooks/Track_Visitor.php
    Line Number: 134

  5. Warning: Unterminated comment starting line 77 in C:\xampp\htdocs\SATZ\CodeIgniter\appl\libraries\site_config.php on line 77

  6. Hi,
    we have check your script.
    Can you please explain, when you insert data in ‘is_unique’ field in database.
    Because in ‘Track_Visitor.php’ file you have not inserted ‘is_unique’ value.

    Thanks,

Leave a Reply

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