简体   繁体   中英

Find Number of Open Sessions

I'm looking for an easy (no database) method of listing how many users are active on a website. The easiest way I can come up with is by counting the number of open sessions.

This code should work:

$number_of_users = count(scandir(ini_get("session.save_path")));

Of course it won't because of the security constraints on that directory (as there should be..). Does anyone know another way to access this number without changing directory permissions.

Note: I'm looking for an option that does not involve databases or reducing the security on PHP sessions.

End Note: For anyone coming to this question, I ended up using a cronjob (running every minute) from root that did something similar to:

ls /var/lib/php5/ | wc -l > /var/www/sessioncount

Make sure the /var/www/sessioncount file is readable by the apache user. Then you can just read the file in PHP:

$number_of_users = file_get_contents("/var/www/sessioncount");
<?
// you must set your own accessible session path atop every page.
session_save_path("/home/some/other/location/"); # SECURITY VIOLATION!!!
session_start();

function session_count() {
  $filter = "sess_";
  $files = scandir(session_save_path());
  $count = 0;
  foreach ($files as $file) {
    if(strpos($file,$filter)===0) {
      $count += 1;
    }
  }
  return $count;
}

echo session_count();
?>

Easy does not mean no database in this case. Also relying on session to see how many users are active is not reliable.

If you wanted to go that route, you could do a cronjob that is run by a safe process every few minutes and saves that count into a file or db, which PHP reads.

But i recommend going the database route.

For the sake of solving this for anyone else, here. Assemble the code in order, and use directions on the way. Requires PHP's GD extension.

Make a directory in your webroot, make sure the web daemon can write to it:

mkdir liveusers

Create a PHP script ( vlive.php for example) for the touch code (btw. touch is a standard *nix command, use the system(),passthru() or exec() whatever you feel like to use it). Have it touch a file in that directory with a unique filename, for example IP+SessionID concat'd together:

<?php 
exec("touch ". $_SERVER['DOCUMENT_ROOT']."/liveusers/". md5($_SERVER['REMOTE_ADDR'].session_id())); /* SECURITY RISK */

Now, in the same file we need to output a JPEG finish it off with proper header()'s I put a 1x1 pixel named pixel.jpg into the webroot's /images/ directory , feel free to do something else:

$NewImage = imagecreatefromjpeg($_SERVER['DOCUMENT_ROOT']. "/images/pixel.jpg");
header("Content-type: image/jpeg");
imagejpeg($NewImage);
?>

Save the PHP file, then place a standard HTML tag in your document to get it useful:

<img src="/vlive.php" alt="Imagination!" />

Going pure PHP with this then caching pages will just make it so the live user files barely ever get touch 'd. By doing this you can still count "live" users and use a full page cache system on your site.

Ok so now every page a visitor loads touches their unique file, so if they're just recently arriving the touch command will create a file for that user, if they are visiting other pages too, it will edit the access date with that same touch command.

This is where it gets useful:

In a different PHP script (let's say readvlive.php ):

<?php 
$livenum = system("find ".$_SERVER['DOCUMENT_ROOT']."/liveusers/ -type f -amin +10 | wc -l");
echo "Live Visitors: ". $livenum;
?>

Now let's include this snippet into the HTML element you'd like to see it in:

<?php include($_SERVER['DOCUMENT_ROOT']. "/readvlive.php"); ?>

Ok so now we have a file that it'll print out the number of unique files with an access time changed only 10 minutes ago. These are our live users in the last ten minutes...

Now we have a choice here, again if you use full page cache you might freeze the cached live number into these documents thus making it rather annoying and useless. For this I suggest PrototypeJS (Google it), You use their fancy AJAX tools, place this between <head></head>

<script src="/js/prototype.js" type="text/javascript"></script>

then place this above the </body> tag.

<span id="live_users_count">&nbsp;</span>


<script type="text/javascript">
    <!--
    Event.observe(window, 'load', function() {
        if($('live_users_count')) {
            new Ajax.Updater('live_users_count','/readvlive.php'); 
        }
   }
-->
</script>

Should be fine.. not too rough. If you're concerned with how much your directory is gonna be running that find command, you could use APC or something to cache it. This example requires APC 3.1.4:

<?php
if(apc_exists('livenum')){
    $livenum = apc_fetch('livenum');echo $livenum;
} else {
    $livenum = system("find ".$_SERVER['DOCUMENT_ROOT']."/liveusers/ -type f -amin +10 | wc -l");
    apc_add('livenum',$livenum,30); 
}
?>

APC 3.0.13 and up:

<?php
if($livenum = apc_fetch('livenum')){
    echo $livenum;
} else {
    $livenum = system("find ".$_SERVER['DOCUMENT_ROOT']."/liveusers/ -type f -amin +10 | wc -l");
    apc_add('livenum',$livenum,30); 
}
?>

These will use APC caching for 30 seconds showing the last 10 minutes of live users, will run find command to calculate it twice per minute. Not bad. :P

Clean up can be done with crontab..

The script ( /root/deloverhead.sh ):

#!/bin/sh
find "/path/to/liveusers/ -type f -amin +60 -exec rm {} \;

Crontab entry (every hour):

0 * * * * /root/deloverhead.sh >/dev/null 2>&1

Have fun, sorry I might explain things weird. :P

You can't access that directory from a PHP script without posing a security risk.

The easiest way to achieve what you want is using a database. Just store the ip and the timestamp, and then SELECT based on the timestamp to get the number of active users on your website.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM