Can I count sessions to determine number of people online? - php

I am confused about something. When I try to search how to count online users in PHP, all answers related with MySQL and many different ways.
In my script, any user that submits the login form creates a $_SESSION['$nickname']
So I thought, can I count login sessions with count($_SESSION['$nickname']); and show it in my page?
Or is this totally a wrong logic?

Totally wrong logic. $_SESSION is a per-user thing. One user's session is not shared with any other user's session. Think about it - an online bank written in PHP, all sharing a single $_SESSION - everyone would see everyone's account details.
Assuming you're on the standard PHP file-based sessions, you can count the session files in whatever directory they're stored, e.g.
$users = count(glob(session_save_path() . '/*'));
Note that this just counts session files - it will undoubtedly contain stale/dead sessions that haven't been garbage collected yet. If you want an actual "really is online right now", you'd have to parse each session file and examin its contents.

At first, you have to define what "to be online" means.
Should the user have clicked on a link within the last 5 minutes?
I assume that you already have a user table in your database.
So the simplest way is to add a new column, e.g. lastAction TIMESTAMP.
And when the user clicks on a link on your page, your script should update this value.
And on your statistics page or whatever, you get the number of online users with that code:
SELECT COUNT(*) FROM users WHERE lastAction > (NOW() - 60*5)

PHP is pretty flexible in terms of session storage, you can define your own session save/restore handlers.
However, the default session storage is files, where each session is individually stored to disk. Which means, that in order to find out how many users there are "online" (here, i assume "online = session exists with $_SESSION['$nickname'] set"), you would need to open all the session files stored on disk, and check how many unique nicknames exist within them. This is very heavy in both time and required resources.
Hence, most tutorials suggest counting this in the database, by maintaining a last-seen timestamp per user (and checking how many users were last seen in last X minutes).
If you wish to combine, that is doable via defining your own session save handler to store session information in the database...
Several additional notes on sessions:
Sessions are not destroyed immediately when closing a browser. In fact, the browser does not tell the server in any way that it is being closed. It means that the server should come up with some time-based algorithm to decide who's online and who is not.
Sessions are isolated from one another so $_SESSION["foo"] can not be shared by multiple different sessions - there is no equivalent to Global.asa in PHP. Not off the box.

This is the wrong logic and the session is only stored and immediately destroyed locally on the end user's PC, so it cannot be read from the server for any kind of confirmation without the user doing something. Server-side sessions are only destroyed on garbage cleanup.
Your best bet is to have a timestamp for each user which is updated whenever a user does anything. This means you will need to have this update triggered via JS/AJAX, PHP. Then you can check to see how many timestamps are within the last 5 minutes for example, and this would give you a rough idea of how many users are currently online.
You could also have a hidden iframe which continually refreshes every few seconds and updates the timestamp, or JS/AJAX which updates the timestamp every X seconds as well...

Related

PHP: how to update user logged in timer without using AJAX calls

I am creating a web application named Online Exam using PHP+MySQL and AngularJS. Now I am getting some trouble on project like changing the user looged in status. Let us take this condition as a example:
Suppose a authorized user/student successfully logged in online exam section(After successfully logged current time will be inserted in the db in exam_start_time column as unix timestamp format and exam_status will be set as 'ACTIVE`.
1hr(60 min) countdown timer is initialize for him/her as per the inserted exam_start_time in db.
Now suppose after 15 min the system shuts down automatically, then if user logged in again(In same system or other) then the countdown timer should be set for 45 minutes only.
Previously I was updating the last_activity_time in our table in every 10 sec(using ajax calls). but now I want to change this way, Is there any way like(socket or network programming using PHP) to update the column.
Here is my table structure which is managing user logged in status
Please give me some suggestions on it.
A Php socket server programming tutorial : http://www.christophh.net/2012/07/24/php-socket-programming/
Sockets, as Pascal Le Merrer mentioned, is IMO your best option. But beware of Apache! Every WebSocket holds one Apache thread, and Apache wasn't designed to do that. when too many (and by too many I mean few dozen) clients connect to your site, it will crash. (I've been there while trying to implement long polling/comet, ended up using NodeJS. If you're using nginx, it is more likely that it will become low on resources and effective, but there are also other ways. Take a look here:
Using WebSocket on Apache server
If you find this uncomfortable/hard to learn, try also another idea:
try to add hidden iFrame to your exam page, pointing to prepared site that updates database row. Use javascript to refresh this page every 10-15 seconds. Every refresh causes update of specific row in DB, using current date and time. It should work (not tested, but give it a try).

Modify variables from different PHP Sessions

I am making a session system for my website using PHP and MySQL. The idea is that a user session will last for around 5 minutes if they are inactive, and a CronJob runs every now and then and checks to see if sessions are expired, and if they are, removes the session.
The issue:
Every time someone loads their page it has to check the database to see if their session is still valid. I am wondering if in that CronJob task, I could make it find that users PHP Session and change a variable like $_SESSION['isValidSession'] and set it to false.
So once they load the page it just checks if that variable if the session is valid.
Sorry for the wall of text!
TL;DR: I want to modify session variables of different specified sessions.
Thanks.
Every time someone loads their page it has to check the database to
see if their session is still valid. I am wondering if in that CronJob
task, I could make it find that users PHP Session and change a
variable like $_SESSION['isValidSession'] and set it to false.
You have to do this regardless. When the users load their page, the system must verify whether the session exists in the database (I assume that you're using a DB).
If you run the cron job every minute, and expire all sessions older than five (which seems rather excessive? I often stay inactive on a site for five, ten, even fifteen minutes if I am reading a long page), this will automatically "mark invalid" (actually remove) the sessions.
Normally you would keep a TIMESTAMP column with the time of last update of that row (meaning that session), and the cron job would DELETE all rows with timestamp older than five minutes ago. When reloading the page, the system would no longer find the relevant session row, and deduce (correctly) that the session has expired.
However, what you want (reading a session knowing its SessionID) can be accomplished by reading in the session by the cron job (you can code the job in PHP) either loading as extant session given its ID, or by reading the DB column holding the serialized data with a SELECT SessionData FROM SessionTable WHERE id = 'SessionId'; and de-serializing it. Then you modify the inflated object, re-serialize it and store it back in the database with SQL UPDATE. Hey presto!, session has now been modified.
But be aware that this will likely cause concurrency problems with active clients, and cannot be done in SQL in one fell swoop - you can't execute UPDATE Sessions SET isInactive = 1 WHERE expiry... directly. Normally you need to read the rows of interest one by one, unserialize them and store them back, processing them with PHP code.
You can do it indirectly with two different workarounds.
One, you change your session code to use unserialized data. This will impact maintainability and performance (you can't "just add" something to a session: you have to create a column for it).
Two: you take advantage of the fact that in serialized form, "0" and "1" have the same length. That is, the serialized session containing isValidSession (name of 14 characters) will contain the text
...{s:14:"isValidSession";b:1;}...
and you can change that piece of string with {s:14:"isValidSession";b:0;}, thus making isValidSession become False. This is not particularly good practice - you're messing with the system's internals. Of course, I don't think anybody expects PHP's serialized data syntax to change anytime soon (...or do they?).
<?php var_dump($_SESSION); ?>
You should store the time of last request of the users in the database.
In the cornjob you should check users last view time and compare to current time, then check which user time has been expired.
And then update the column of database as false for expired users.
After than you can easily find out which user should be log out just by checking that colmn in database.

who's online with timestamp with high performance

i just created a user login system with php session and now users can register and login to site and do another things...
now i want to create online.php which will fetch all online users.i almost search everything in google and stackoverflow for this with no success.
ok now i want to describe the system which i want to create with high performance..
when a user logged in we just update table user.lastlogin which is a timestamp and then in online.php we SELECT * every user where time interval is < 5 minutes.
for this purpose i can update this timestamp lastlogin field in database when user load each page,and this cost many mysql query to do the job... then in each page load i have to update
UPDATE user set last=now()
that will cost me many mysql query.now i am looking for some another way like using sessions or something that i found in this link
"The normal solution is to store a timestamp in the table which you update every time the user does something. Users with a recent timestamp (say, five minutes) are shown as logged in, everybody else are logged out.
It doesn't even have to be updated on every page load. Keep a timestamp in the session with the last update time as well, and only update the table when the database flag are about to expire."
but unfortunately the answer wasnt quite helpful and i need an example or more describe on this.
1.) If you need more speed in sessions there is for example memcache. A simple key - value store to save your sessions or keys. You can configure Apache that all sessions will be automaticly stored in memcache.
2.) Another solution is to make a MEMORY Table which MySQL holds in RAM. Problem is when you restart your server the data in this table is lost. But i think in your case for last logon there is no problem.
3.) PHP Shared Memory: http://php.net/manual/de/ref.shmop.php for small data.
When you have implemented a solution i would prefer the MEMORY Table or the SHM solution.
Edit: The last paragraph with the searching on HDD was related to the comment on top: Find Number of Open Sessions

PHP best practice keep track of logged in users

I want to show users who else is logged in as part of a comment system. What are best practices for keeping track of users? For example:
Do you keep track of all sessions and then mark them as closed. Or do you delete users upon logout, keeping track only of active users.
I'm thinking I should create a table with userid, time logged in, time logged out and/or status. Is that the way to go or is there some alternative approach of tracking session ids. If using a table, is there value in keeping sessionid. Should I delete row when session no longer active, negating need for whenloggedout field.
There is a login so easy to keep track of users logging in. However, it is harder to track users logging out since their session may be broken by browser crashing etc.
Is it best practice to consider users logged in as long as they have not destroyed session... for example, FB and Gmail will leave you logged in almost indefinitely--or should there be a time limit since last activity? The idea of saving to this table every time there is activity on site is not appealing.
Right now, I'm thinking of following:
create table loggedin (userid (int), whenloggedin (datetime), whenlogged out (datetime), loggedin(tinyint))
with the latter going to 0 either if whenloggedout not null or after some long time limit like 24 hours. I imagine FB while leaving you logged in for long periods of time, also keeps track of activity for purposes of chat etc. but not sure. I'm also thinking of letting the table expand, rather than deleting closed sessions but maybe that's a mistake.
Would this approach be considered adequate or is there a better way. Many thx for advice on this.
Depending on how you want it to work you basically have two options:
Define a timeout after which you consider a user logged out
Use ajax/websockets/whatever to poll user
1: Timeout
This is the simpler use case. Every time the user requests a page, you update a timestamp in your database.
To find out how many users are online, you would do a query against this database and do a COUNT of users who have been active in the last N minutes.
This way you will get a relatively accurate idea of how many people are actively using the site at the moment.
2: Constant polling
This is a bit more complex to implement due to having to update the server with Ajax. Otherwise it works in a similar fashion to #1.
Whenever a user is on a page, you can keep a websocket open or do ajax requests every N seconds to the server.
This way you can get a pretty good idea of how many people have pages open on your site currently, but if a user leaves the page open in their browser and doesn't do anything, it would still count them as being online.
A slight modification to the idea would be to use a script on the client to monitor mouse movement. If the user doesn't move the mouse on your page for say 10 minutes, you would stop the polling or disconnect the websocket. This would fix the problem of showing users who are idle as being online.
To circumvent the problem with knowing if a user has logged out or browser crash ect, is to use a heartbeat/polling of sorts here is a stripped down example of how you can do that with jQuery
function heartbeat(){
setTimeout(function(){
$.ajax({ url: "http://example.com/api/heartbeat", cache: false,
success: function(data){
//Next beat
heartbeat();
}, dataType: "json"});
}, 10000);//10secs
}
$(document).ready(function(){
heartbeat();
});
http://example.com/api/heartbeat would keep the session alive & update a timestamp in your db, then on each page load you would check the time stamp with current time ect and if its lower then say 15 seconds then you would log them out.
Constant Polling and using heartbeat are a good idea, but for some scenarios they may create useless load on server. I think you should think about the importance of keeping track of your users and use it very appropriately, especially considering the impacts your changes may have on load time.

Updating db tables based on user activity

I have log table for all users of website
I'm recording various data about user righ after successfull login.
If signout_dt field not filled and status is 1 for some user_id, website prevents login automatically.
For that who have cookies - there is no problem.
The problem is,lets say user signed in without cookies: only sessions variables. I have no idea, how can I update db table and signout user let's say after 30 minute inactivity. Note that I can't create cron job or something serverside, because using shared hosting.
Heard that, it's possible to create some script like heartbeat that continously sends some data about user activity. But I think this will heavily load the server especially if there are more than 1000 users.. Any suggestion, tutorial, article, something else?
Update
Deceze tried to explain but I really need better explanation (better idea), with code.
To "timeout" a user, simply note the time he was last seen. Then, when necessary, check if the last time you've seen the user was over x minutes/hours/days, and consider the last session timed out. You don't need to run a cron job or anything that cleans up after users in realtime, you only need to be able to determine if some information should be considered stale when you need that information.
You may want to occasionally run a cron job or something to clean out old, unnecessary data, but that doesn't need to happen in realtime. You could even run this as part of a regular page request:
if (mt_rand(1, 1000) == 1) {
mysql_query('DELETE FROM `table` WHERE `last_seen` < some point in time');
}
To note the last seen time, just run this query on each page load:
UPDATE `table` SET `last_seen` = NOW() WHERE `user_id` = ...
To avoid thrashing the database with these queries, you can also just do it every so often. Keep a "last_seen_last_updated" timestamp in the user's session, then on each page load check if you might want to update the database:
if ($_SESSION['last_seen_last_updated'] < strtotime('-5 minutes')) {
mysql_query(...);
$_SESSION['last_seen_last_updated'] = time();
}
That gives you 5 minutes of jitter, but that's usually perfectly acceptable.
Your management of sessions is broken and does not conform to accepted stateless behaviour - in as much as you apparently require the user to sign out, which rarely is the case in web applications -- most people just closes the browser, and the cookies will just float around and appear next time the user accesses the website. If the system wants the user to sign in again, then the web server will have to validate the session -- for example using a timestamp and/or cookie signing etc, and invalidate the cookie to force the user to re-login if needed.
Hence you should treat cookies and sessions variables the same -- that is; have your server side generate a unique signed value. Keep an expiration time (for example now()+20min) either in the cookie/session variable or keep the expiration time in the database.
At each access check that the cookie/session-variable is correctly signed, and check that it is not beyond the expiration time, and update the expiration time to allow another 20min.
If the access is past the expiration time -- i.e. the user has been idle for too long, then clear the cookie/session-variable and force the user to login again.
If you keep the expiration time in the database, you simply write a small program which once and day or once an hour run though all records and remove those which you deem too old.
As per my understanding of your question, you want to address following things:
a. If for a given period of time, a user is inactive then he should be logged out and your database table gets updated. Here being inactive means, user has not used keyboard/mouse for a given period of time.
b. If a user closes the browser without logging out, then he should be forcefully logged out and database table gets updated.
Both these things can be accomplished using Javascript Functions and Ajax. Following is the flow which we have in our application for addressing above issues:
Create a Javascript function, say logoutUser(), which will send an Ajax request for updating the database tables and destroying the session.
Use Javascript function - setTimeOut - to call logoutUser() function after time period you have set for inactivity.
Use Javascript events to catch mouse movement and keyboard activity and in every such event call use successively clearTimeOut (in order to remove the old time for execution of logoutUser()) and setTimeOut (for setting the new time of execution of logoutUser()). This way you would be able to catch the inactivity and logout the user after a period of time.
For taking care of the issue related to closing of browser window use 'onbeforeunload' event of javascript and in this event send the Ajax request for updating the database tables.
As our application uses ExtJS, thus, we have used ExtJs library functions to detect events. You can also prefer using some Javascript library for catching the events and implemeting the above solution.
Hope this helps.

Categories