Hit and Online Counter [PHP MySQL]

Download Source Code

Counters.phps [Downloads: 15]

Note: rename extension to .php to be able to run the script!

How does it Work?

The counters use two database tables hits and online. The first is for counting the total number of visits on a website and the other for showing the number of currently online users. Both counters read the user's IP to distinguish users and the user agent string (provided by the visiting entity) is used to exclude at least some robots (search engines and crawlers). The counters have a time throttle setting to limit the same user from getting more than one hit within a session (defaults to 10 minutes). When the user navigates or reloads the session is extended. If the user is inactive the session will expire after the set time and the user will get a new hit and appear as online again.

How to Setup

The two tables (see the source code below for details) must be created in your MySQL database and the credentials for the database entered in the script - that's basically it. The counters can then be integrated on your website and styled nicely with CSS.

Source Code

Counters.phps

<?php
// ========================================================================
// Hit + Online Counter with PHP and MySQL
// Version: 2019-10-15 08:37:00 (UTC+01:00)
// https://www.dunweber.com/docs/scripts/releases/hitcounters
// Copyright (C) Christian L. Dünweber
// This program is distributed under the GNU General Public License,
// see <http://www.gnu.org/licenses/gpl.html>.
// ------------------------------------------------------------------------
// Prerequisites: Create database tables and enter your credentials below.
// Usage:
// $counters = new Counters();
// echo 'Hits: '.$counters->getHits().'<br />';
// echo 'Online: '.$counters->getOnline();
// ========================================================================

/*
// ------------------------------------------------------------------------
TODO: Create these tables in your MySQL database:

CREATE TABLE `hits` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` varchar(20) NOT NULL,
  `time` datetime NOT NULL,
  PRIMARY KEY (id)
) AUTO_INCREMENT=1;

CREATE TABLE `online` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` varchar(20) NOT NULL,
  `time` datetime NOT NULL,
  PRIMARY KEY (id),
  UNIQUE (ip)
) AUTO_INCREMENT=1;
// ------------------------------------------------------------------------
*/

class Counters
{
    
// TODO: Change to your database credentials
    
private const HOST 'host';
    private const 
USER 'username';
    private const 
PASS 'password';
    private const 
DB   'database';

    
// Database table names
    
private const HITS   'hits';
    private const 
ONLINE 'online';

    
// Time in minutes limiting new hits from the same IP
    
private const SESSION_LENGTH_MIN 10;

    
// The user agent is checked against this list and matches will not get hits or appear online
    // TODO: Add more robots as the Internet evolves
    
private const ROBOTS = ['Ask Jeeves','WebCrawler','findlinks','Gigabot','Googlebot','Google-Sitemaps','HenryTheMiragorobot','libwww-perl','MSNBot','PHP version tracker','PHP_','Researchscan','Scooter','Speedy Spider','SurveyBot','Validator.nu','W3C_'];

    private 
$mysqli;
    private 
$ip;
    private 
$agent;

    
// ====================================================================
    // Constructor: connect to db and init.
    // --------------------------------------------------------------------
    
public function __construct()
    {
        
$this->mysqli = new mysqli(Self::HOSTSelf::USERSelf::PASSSelf::DB);

        if (
$this->mysqli->connect_errno) {
            exit(
'Could not connect to db: '.$this->mysqli->connect_errno);
        }

        
$this->ip $_SERVER['REMOTE_ADDR'];
        
$this->agent $_SERVER['HTTP_USER_AGENT'];
    }

    
// ====================================================================
    // Destructor: disconnect from db.
    // --------------------------------------------------------------------
    
public function __destruct()
    {
        
$this->mysqli->close();
    }
    
    
// ====================================================================
    // Get hit counter, i.e. total number of hits.
    // --------------------------------------------------------------------
    
public function getHits(): int
    
{
        
// Exclude robots
        
if (!$this->isRobot($this->agent)) {
            
// New hit or revisit within session
            
$result $this->mysqli->query('SELECT id FROM '.Self::HITS.' WHERE ip=\''.$this->ip.'\' AND DATE_ADD(time, INTERVAL '.Self::SESSION_LENGTH_MIN.' MINUTE) > NOW()');

            if (
$result) {
                
$row $result->fetch_assoc();

                
// A new hit gets inserted
                
if (!$row) {
                    
$this->mysqli->query('INSERT INTO '.Self::HITS.' SET time=NOW(), ip=\''.$this->ip.'\'');
                }
                
// Update timestamp for active user
                
else {
                    
$this->mysqli->query('UPDATE '.Self::HITS.' SET time=NOW() WHERE ip=\''.$this->ip.'\' AND id='.$row['id']);
                }

                
$result->close();
            }
        }

        
// Total number of hits are the number of entries in the table
        
$result $this->mysqli->query('SELECT COUNT(*) AS hits FROM '.Self::HITS);

        if (
$result) {
            
$row $result->fetch_assoc();
            
$result->close();
            return 
intval($row['hits']);
        }

        return -
1// Error
    
}

    
// ====================================================================
    // Get online counter, i.e. number of currently online.
    // --------------------------------------------------------------------
    
public function getOnline(): int
    
{
        
// Exclude robots
        
if (!$this->isRobot($this->agent)) {
            
// Is user already present
            
$result $this->mysqli->query('SELECT 1 FROM '.Self::ONLINE.' WHERE ip=\''.$this->ip.'\'');

            
// Update timestamp for active user
            
if ($result && $result->num_rows) {
                
$this->mysqli->query('UPDATE '.Self::ONLINE.' SET time=NOW() WHERE ip=\''.$this->ip.'\'');
                
$result->close();
            }
            
// A new onliner gets inserted
            
else {
                
$this->mysqli->query('INSERT INTO '.Self::ONLINE.' SET time=NOW(), ip=\''.$this->ip.'\'');
            }
        }

        
// Inactive user are deleted from the db
        
$this->mysqli->query('DELETE FROM '.Self::ONLINE.' WHERE DATE_ADD(time, INTERVAL '.Self::SESSION_LENGTH_MIN.' MINUTE) < NOW()');

        
// Number of onliners are the number of entries in the table
        
$result $this->mysqli->query('SELECT COUNT(*) AS online FROM '.Self::ONLINE);

        if (
$result) {
            
$row $result->fetch_assoc();
            
$result->close();
            return 
intval($row['online']);
        }

        return -
1// Error
    
}

    
// ====================================================================
    // Check if given user agent advertise to be a robot.
    // --------------------------------------------------------------------
    
private function isRobot(string $agent): bool
    
{
        for (
$i 0$i count(Self::ROBOTS); $i++) {
            if (
stripos($agentSelf::ROBOTS[$i]) !== false) {
                return 
true;
            }
        }
        
        return 
false;
    }
}
?>