Click here to Skip to main content
Click here to Skip to main content

Getting number of users online and other functionalities

By , 29 Apr 2013
Rate this:
Please Sign up or sign in to vote.

Introduction

Knowing your website statistic is a very important factor in tracking the growth of your site. A more obvious use of such statistical information in is forums, communities, and social networks where it is of paramount necessity to know

  • If a user is online (useful in Live Web chat)
  • The number of users currently online
  • The highest online ever (with date and time)
  • The number of users that has been online for that day
  • The time and date a user was Last Seen

This article presence how these can be achieved using PHP and MySQL. Implementing this using PHP and MySQL is pretty easy and straightforward (trust me on this Smile). You can grab the source files attached to this article which contains two files checker.php (the backend code) and check.php (which contains HTML, PHP, and AJAX to asynchronously ping the server for checker.php).

Test this on various browsers and tabs to simulate multiple users. Close a few tabs and browser to see the effect.

The Setup  

A database online_users is needed on your MySQL server. Two tables are needed in this database: online and highest. The table online should contain two columns: column id which could be an INT or VARCHAR depending on the way the ID’s of users are handled on your site but for the purpose of this illustration, it will be VARCHAR(10). The second column in table online should be time which should be a TIMESTAMP

The second table highest should contain two columns; column time which is a TIMESTAMP that defaults to the current time on the server and column num which is an INT.

You can set these up manually using your phpMyAdmin or by using the code below assuming your database name is “online_user” and you have connected to the MySQL server using the variable $connection.

<?php
.
.
.
//already connected to MySQL using $connection
//To create database
$sql = “CREATE DATABASE online_users”;
mysql_query($sql, $connection);
 
//To create tables
$sql = “CREATE TABLE online_users.online (id VARCHAR( 10 ) NOT NULL ,
time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE = InnoDB”;
mysql_query($sql, $connection);
 
$sql = “CREATE TABLE online_users.highest (time TIMESTAMP NOT NULL 
              DEFAULT CURRENT_TIMESTAMP , num INT NOT NULL ) ENGINE = InnoDB”;
mysql_query($sql, $connection);
.
.
.
?>  

Please note that you have to create these database and tables before the source files included with this article can work. This section of database and table creation were left out of the source code so as to keep it clean, clear, and straight to the point. 

The checking checker 

checker.php contains the backend code but before usage you have to change the $db_host, $db_username, $db_password, $db_name variables to your MySQL host, username, password, and database name, respectively. 

Challenge 1 

The first step in achieving our aim is in logging the ID and the current time of every user present on the site into the “online” table of the database and to ensure this information is updated as long as the user still has the site opened in their browser. If this is achieved, the following problems are solved at once.

Solution 1: 

  • Get if a user is online: By checking the time the row of a user was last updated, you can tell if the user is still online or not. For instance, if you set the row to be updated every 30 seconds and the last time the row was updated was 1 minute ago or more, you can rightly say the user is no longer online.
  • Get the number of users that are online: If you choose that a user can be considered offline if the time the row was last updated is 1 minute ago or more, then by getting the number of rows updated less than 1 minute ago, you get the number of users online.
     
  • Last Seen: By checking the last time the row of a user was last updated, you can determine if he is online or the “Last Seen” time.  
  • Number of users online today: By getting the number of rows that has been updated that particular day, you get the number that has been online that day.

Challenge 2:

The second challenge (and last since Solution 1 solved 4 of 5) is how to get the highest online ever. Of course this will be at a “point in time”. This might look scary at first when you think a script might have to keep running on your server at all time so as to get the the number of users online every millisecond. That is not the solution anyway so relax!

Solution 2: 

  • Highest Online Ever: to have the highest online, you have to have users present online! This might first seem like a dump statement but it is true. So why not put the responsibility of checking for the “highest online ever” on online users instead of having Cron Jobs run a script perpetually on your server. If there are no users online then there is no need for checking the highest online.

When a user reports his presence, the number of online users is checked and compared with the column “num” of the table “highest”. If the number is greater or equal to “num”, the current time and number is INSERT INTO or UPDATEd into the table.

The pinging check

The check.php file contains PHP code, AJAX scripts, and HTML that runs on the frontend. This is just like your web page, i.e., what the user will see. AJAX is used to asynchronously communicate with the server every 30 seconds to report the presence of the user amidst others.

Codes and Explanation

Four out of our five challenges can be solved by the page simply reporting its presence to the server, say every 30 seconds, and the server appropriately updating the row in the table “online”.

  • Reporting User’s Presence
  • .
    .
    .
    //Report your presence
    if(isset($_GET[report]))
    {
        $query = "SELECT * FROM ". $db_name .".online WHERE id = '%s'";
        $query = sprintf($query, mysql_real_escape_string(stripslashes($_GET[id])));
        if(mysql_num_rows(mysql_query($query, $con)) > 0)
        {
            $query = "UPDATE ". $db_name .".online SET time = '%s' WHERE id = '%s'";
            $now = date('Y-m-d H:i:s', strtotime('now'));
            $query = sprintf($query, $now, mysql_real_escape_string(stripslashes($_GET[id])));
            mysql_query($query, $con);echo $query;
        }
        else
        {
            $query = "INSERT INTO ". $db_name .".online (id, time) VALUES ('%s', '%s')";
            $now = date('Y-m-d H:i:s', strtotime('now'));
            $query = sprintf($query, mysql_real_escape_string(stripslashes($_GET[id])), $now);
            mysql_query($query, $con);
        }
        //Set highest online info
        setHighestOnline($con, $db_name);
    }
    .
    .
    .

    This piece of code sits on the backend (checker.php) and checks if $_GET[report] is set(). If true, that indicates a page is reporting the presence of a user. The code then checks if the user has been registered into the table “online” before. If true (i.e., the number of rows returned in the query is greater than zero) the row is UPDATEd else the information is INSERT INTO the table.

    Remember in Solution 2 it was stated that whenever a user presence is reported, the number of online users should be checked and appropriately handled, that is the reason for the setHighestOnline() function. The function will be discussed later.

    The user reports the presence from check.php with this piece of AJAX code:

    .
    .
    .
    function doReport()
    {
    k = getXMLHttpRequestObject();
        if(k != false)
        {
            url = "checker.php?report&id=" + 
                         document.getElementById("userID").value;
            k.open("POST", url, true);
            k.onreadystatechange=function()
            {
    if(k.readyState==4)
                {
                    //...Do nothing...
                }
            }                                        
            k.send();
        }
        else
        {
            alert("Cant create XMLHttpRequest");
        }
    }
    .
    .
    .
    doReport();
    setInterval(doReport, 30000);// Report user presence every 30sec
    .
    .
    .

    This is just a simple AJAX code but notice that “POST” was used in the open method but the parameters were passed using GET method (i.e., appending the parameters to the URL). $_GET[] was also used on the backend code. The purpose of using POST in the open method is to prevent caching, GET will always cache if used in the open method and this is not desirable in this situation hence the POST. All the other AJAX codes simply follow this pattern. The parameter id in the variable URL above should be the UserID of the user. In this example, an ID is randomly generated and stored in a hidden input field.

    .
    .
    .
    <?php
    echo "<input type=hidden id=userID value=" . rand(0, 5) . ">";
    ?>

    In your own code use the real UserID.

  • Setting the highest online ever
  • .
    .
    .
    //Set the highest online at all time
        $highest_online = 0;
        function setHighestOnline($con, $db_name)
        {
            //Get number of user currently online
            mysql_select_db($db_name, $con);
            $query = "SELECT * FROM ". $db_name .".online";
            $result = mysql_query($query, $con);
    
            if(mysql_num_rows($result) > 0)
            {
                while($row = mysql_fetch_assoc($result)) 
                {    //If last seen is less than 1 minute, user is assumed online
                    if(abs((strtotime($row['time'])-strtotime(
                        date('Y-m-d H:i:s', strtotime("now"))))) < 60)
                    {
                        $highest_online++;
                    }
                }
            }
            
            //Get highest online previous record
            $query = "SELECT * FROM ". $db_name .".highest";
            $result = mysql_query($query, $con);
            if(mysql_num_rows($result) > 0)
            {
                $row = mysql_fetch_assoc($result);
                if($highest_online >= $row['num'])
                {
                    //The currently online is greater
                    //than or equals to the previous record so update
                    $query = "UPDATE ". $db_name .
                      ".highest SET time = NOW(), num = '" . $highest_online . "'";
                    mysql_query($query, $con);
                }
            }
            else
            {
                //Highest online never set before so set the record
                $query = "INSERT INTO ". $db_name .
                  ".highest(time, num) VALUES(NOW(), '" . $highest_online . "')"; 
                mysql_query($query, $con);
            }
        }
    .
    .
    .

    This will simply check for the number of users online from table “online” and compares the result with the record in table “highest”. Table “highest” is UPDATEd or INSERT INTO appropriately. The other function just follows this pattern of checking, updating, and inserting into the MySQL database and is pretty simple to comprehend. The setInterval() function in the JavaScript is used to run all the AJAX functions at a specified interval.

    .
    .
    .
    setInterval(doReport, 30000);// Report user presence every 30sec
    setInterval(numOnline, 60000);//Get number of user online every 60sec
    setInterval(lastSeen, 60000);//Get the last seen time of a user every 60sec
    setInterval(highestOnlineEver,(60000*5));//Get the highest online every 5 minutes
    .
    .
    .

Other necessities

  1. Ensure both checker.php and check.php are in the same directory, else you will have to update the URL variable in the AJAX code appropriately.
  2. Note that the code assumes your connection to the database will never fail so no error handling was built in
  3. You can also extend the code to include a function too get the current page the user was viewing at a particular time. This and others were not included so as to keep the code focused, short, and clear. Though this can be featured as a Part Two on popular demand.

A screenshot

1st Revision: 9th of April, 2013

The basic algorithm still remains but the original code was altered a little to carter for some oversight

  1. The Daylight Time Saving behavior of strtotime() of PHP: The +1 hour advance of time by strtotime() of PHP during DTS was not considered in the initial code. This led to the inability of the code to detect online users during DTS because all user online appear to have been offline for the past one hour. That was fixed by passing date('Y-m-d H:i:s', strtotime('now')) as the current time instead of using MySQL NOW().
  2. An unexpected behavior was also detected whereby function setHighestOnline() was returning MySQL error "No Database selected". That was also fixed by passing an already connected MySQL link to the function.
  3. Fixed some typo's.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Oso Oluwafemi Ebenezer
Software Developer
Nigeria Nigeria
A graduate of Agricultural Engineering from Ladoke Akintola University of Technology, Ogbomoso but computer and web programming is his first love. You can meet him on Facebook Osofem Inc.
Follow on   Twitter   Google+

Comments and Discussions

 
Questionsql PinmemberMember 1020851113-Aug-13 21:09 
AnswerRe: sql PinmemberOso Oluwafemi Ebenezer14-Aug-13 4:04 
QuestionPerformance PinmemberGregoryW9-Apr-13 23:39 
AnswerRe: Performance Pinmemberkburman610-Apr-13 10:09 
GeneralMy Vote of 5 PinmemberMember 966609013-Mar-13 7:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 29 Apr 2013
Article Copyright 2013 by Oso Oluwafemi Ebenezer
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid