The Quickest Way To Count Users Online With PHP
Instead of relying on a database, an alternative method simply counts how many session files there are in the session directory. Because this method never has to read through any files, just their file names, this can take less than a millisecond (seven tenths, to be exact) to complete.
This article assumes that the user has intermediate experience with PHP, and is familiar with the concept of sessions. The server running this script must have PHP 4+ installed, and be compiled with sessions.
Before we can begin the script, we have find out if the session method is the better solution for your web site. This method has several advantages, and a few minor disadvantages.
Advantages
It doesn’t rely on a database: Some people might not have a database available, making the session method the only available choice. Others might want to save CPU cycles for their database driven forum, or want results to show up while the database is down.
Speed of execution: Timing tests have shown that the session method is around 19 times faster than other tested scripts.
Session method took approximately 0.7 ms to execute.
Database method took approximately 14.2 ms to execute.
Conclusion: The session method is roughly 19.4 times faster than the database method!
Right now you might be saying, “You saved 14 milliseconds. Big deal”. It is true, with one concurrent user, there is no noticeable difference in speed. But with 50 or 100 people on your site at once, it becomes a strain on the database, leading to slower results. 10 milliseconds can turn into 500 milliseconds, and by then it can make a huge difference.
Built in garbage collector: Using sessions gives us another advantage, which is a built in garbage collector. PHP will get rid of “old” (the session hasn’t been accessed within a certain time limit — by default 1440 seconds) sessions every 100 page requests (can be changed in php.ini). With a database solution, we have to delete old results ourselves, thus slowing the script down even more.
Easy to implement: The sessions method allows a programmer to simply call session_start() to track a user, as opposed to the database method which requires about 15 lines of code.
Disadvantages
No detailed statistics: You can hack away at a database visitor counter and be able to add more detailed statistics. An example of this is counting visitors based on the page they’re viewing, not the website.
Requires PHP4: If you or your host still haven’t updated to PHP4 (very unlikely), then you will not be able to use this method.
Building the Script
The script is surprisingly simple. It’s made up of one main function called getOnlineUsers and looks like this:
/* Start the session */
session_start();
/* Define how long the maximum amount of time the session can be inactive. */
define(”MAX_IDLE_TIME”, 3);
function getOnlineUsers(){
if ( $directory_handle = opendir( session_save_path() ) ) {
$count = 0;
while ( false !== ( $file = readdir( $directory_handle ) ) ) {
if($file != ‘.’ && $file != ‘..’){
// Comment the ‘if(…){’ and ‘}’ lines if you get a significant amount of traffic
if(time()- fileatime(session_save_path() . ‘\\’ . $file) < MAX_IDLE_TIME * 60) {
$count++;
}
}
closedir($directory_handle);
return $count;
} else {
return false;
}
}
echo ‘Number of online users: ‘ . getOnlineUsers() . ‘<br />’;
The script begins with call to session_start(), which tells PHP to create a blank file in your sessions directory.
If you don’t have a dedicated session directory because you’re hosted on a shared server, it isn’t a good idea to rely on the default session’s directory. Since all of the servers’ users share the same sessions directory, you could end up counting files that aren’t coming your visitors. To solve this problem, simply add this line at the top of your script:
session_save_path(”/path/to/custom/directory”);
After this, we define the timeframe (in minutes) that we allow users to be idle for:
define(”MAX_IDLE_TIME”, 3);
Essentially, if a visitor does not request a new page from the server within this timeframe (in this case 180 seconds), his session file will be ignored and not added to the visitor count.
Hold on. You might remember me saying, “built in garbage collector” earlier, and wondering why this line is necessary. There is, in fact, a built in garbage collector. The only problem with it is that by default, php.ini sets the random chance for the collector to be run at 1%. For smaller sites that don’t get much traffic, this could lead to inaccurate results because the script would count old sessions more often than not.
If the Webmaster does not have access to php.ini and cannot change the session.gc_probability value, then this line is necessary.
Next, we begin the getOnlineUsers function. The function begins by opening the session directory. This can be accessed by the built in function session_save_path():
if ( $directory_handle = opendir( session_save_path() ) ) {
The directory handle is given to $directory_handle for further use. If this line is successful, it proceeds.
The next line in the script loops through the directory handle and retrieves the filename:
while ( false !== ( $file = readdir( $directory_handle ) ) ) {
The “false !==” part is needed because if a file is named 0, it will be skipped over. This is because 0 is considered a false Boolean value in PHP, but not exactly a Boolean. With the “false !==” added, 0 would not be mistaken as a FALSE Boolean, since they are not exact.
The next section of code is where the actual counting occurs:
if($file != ‘.’ && $file != ‘..’){
The current filename in the loop, stored as $file, is first checked to see if it isn’t ‘.’ or ‘..’. This line is needed because when PHP returns a directory, the first two results are always ‘.’ and ‘..’.
Next, we see the line:
if(time()- fileatime(session_save_path() . ‘\\’ . $file) < MAX_IDLE_TIME * 60) {
This line checks to see if the file has not been accessed in the timeframe that we set up earlier. This line can be commented out if you have access to php.ini or get a fair amount of traffic.
Finally, $count++ increments the counter by one if all of these conditions have been satisfied.
After closing the directory, the function returns the variable $count, which holds the total number of users currently visiting your site.
To begin tracking users, we can simply call session_start() at the beginning of the page. For those of you who have php.ini access, you can also turn session.auto_start to 1.
To display how many users are online, put the getOnlineUsers in a file called getOnlineUsers.php. To display the tally on your site, simply include the file and call getOnlineUsers(), like this:
<?php
include(’getOnlineUsers.php’);
echo ‘There are ‘ . getOnlineUsers() . ‘ user(s) currently browsing MyDomain.com’;
?>
In this article you have learned how to improve the inefficient method of using a database to track users, and created a sleek file-based version of the “users online” counter. There are a number of ways to implement this script on your site, namely just changing session.auto_start to 1 in php.ini.
This article also sends an important message about overall efficiency. Whether it’s getting rid of an unnecessary loop, or completely rewriting the database structure, improving coding efficiency is an extremely important part of the development cycle and this process should not be overlooked. Take a look at each piece of code that you write and ask yourself, “Is this the most efficient solution for this problem?”.
