It is true that BASIC Auth has no concept of sessions. However, sessions is not the only way to authenticate users, or to keep track of how many users are logged in. In fact, HTTP is stateless, and so is HTTP Sessions. You can only guess how many are logged in via the number of recent active (modified recently) sessions.
You can implement BASIC Auth with PHP. http://php.net/manual/en/features.http-auth.php
You can guess how many are logged in just by counting the number of authentications made in the last 5 minutes, or 10 minutes etc. This would be just as accurate as HTTP sessions.
Eg:
Create a file called basic-auth.php or similar. This is the basic example from PHP.net
<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Text to send if user hits Cancel button';
exit;
} else {
echo "<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>You entered {$_SERVER['PHP_AUTH_PW']} as your password.</p>";
}
?>
You can then require() this file from every file/directory you want to protect. However, all downloads will have to be validated by PHP now.
Remove your .htaccess basic authentication. Since you'll have PHP do it.
Now you modify it to autheticate users.
One thing to note is that BASIC Auth is only a specification for HTTP authentication. It does not specify how to authenticate. Since you're using Apache, how you authenticate is specific to Apache. You should have created a password file for Apache, similar to mentioned here: http://httpd.apache.org/docs/1.3/howto/auth.html#basicconfig
Apache uses three hashing functions. Either crypt, md5 or sha1. So if you want to use the same password file, then you need to know which hash you're using.
Here is an example for SHA1:
Basically you'll just go through each line of the password file, and if it has the user, check if the supplied password matches. The file looks something like:
user1:passwordhash1
user2:passwordhash2
Which is just one user and their password hash per line, separated with ":".
See here for how the hash is generated:
http://httpd.apache.org/docs/trunk/misc/password%5Fencryptions.html
Your code would be something like this (untested) :
<?php
$authenticated = false;
// a user and password was supplied
if (isset($_SERVER['PHP_AUTH_USER'])) {
$user = $_SERVER['PHP_AUTH_USER'];
$pass = $_SERVER['PHP_AUTH_PW'];
$hash = '{SHA}' . base64_encode(sha1($password, TRUE));
$password_file = '/path/to/your/passwords/file';
$lines = file($password_file);
// find the user in the password file
foreach($lines as $line) {
list($_user, $_hash) = explode(":", $line);
if ($_user == $user) {
// if the hash matches, then their password was correct
if ($hash == $_hash) {
$authenticated = true;
}
break;
}
}
}
if (!$authenticated) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'You need to log in to access the downloads';
exit;
}
// log file
$log_file = '/path/to/authentication/logs.log';
$lines = file($log_file);
$time = time();
$mins = 5; // last 5 mins
// write this user to log
$lines[] = $user.":".time();
// remove log entries older then $mins
// also count unique user entries
$unique_users = array();
foreach($lines as $i=>$line) {
list($_user, $_time) = explode(":", $line);
if ($time > $_time + 60*$mins) unset($lines[$i]);
else $unique_users[$user] = isset($unique_users[$user]) ? $unique_users[$user]+1 : 0;
}
// write log file to disk
file_put_contents($log_file, implode("\n", $lines));
// users online
$users_online_count = count($unique_users);
?>
Of course, you can implement any authentication method. You could use a database, or write your own file formats, etc.