PHP best practice keep track of logged in users - php

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.

Related

Checking if user is online or not (updating activity time on each page visit)

So basically, I have a cronjob, that will check user database activity time, and if user has not done anything in last 10 minutes, it will automatically logout user and set it's status to offline.
Now about the hard part - On each user page visit, I'm doing an update to database, and inserting new activityTime, for example, if he visits homepage, database will automatically update, if he will go to users online page, again, the database will update e.c. That happens to all of users.
So the question is - is there any other, better solutions, or this is good enough solution for that?
Can it cause any troubles in long term, or will it reduce the website speed cause of too many db connections?
Hope you understood what I ment :)!
Basicly having sessions last 10 minutes, and send a simple UPDATE on each page load isn't a big deal. I can promise you that there are far more worse way to overload your database than this. For instance every time you need a value from the user, to extract it from the database every time instead of storing all the values through cookies or global values.
Don't worry about this approach since it will only require 1 more command per session. Some codes can run 25 unnecessary queries per page request without the programmer realizing it.
If you wish to have a number saying how many is online, simply run this through cron aswell:
$str_time = date('Y-m-d H:i:s', strtotime('-10 Minutes'));
$query = $this->db->query("
SELECT COUNT(*) AS online
FROM users
WHERE last_online >= ?
", array($str_time));
if ($query->num_rows())
$int_online = $query->row()->online;
else $int_online = 0;
// Save into database, .json file or whatever
If your site logins are session/cookie based, you can just set the session/cookie timeout to be 10 minutes, then update that timeout/expiration each time someone visits a new page. This method would be less intensive, but also not as secure as someone could modify the cookie.
I have done this in the past with good success.

Can I count sessions to determine number of people online?

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...

PHP: Most Efficient Way to Track if a User is Online?

I'm developing a project of mine with scalability in mind and I've come to a crossroad. On my website I would like to detect if a user is online or not. And I can't quite think of the best way to handle this. The way I was thinking would be something along these lines(in psuedocode):
// SQL user table:
user {
"name": "blah blah",
"email": "derpy#derpyderp.com",
"online": false
}
So whenever the user logs in I could update his online column to true. However that would eventually lead to SQL queries happening every time a user logs in and if it happens that I get say, 10 logins per second, well, that's a lot of queries happening. Another way I figured I could do the same thing but in a different table:
// Activity table:
activity {
"user_id": 2,
"online": true
}
For some reason I believe that would lead to less memory consumption because of the separation from the user table. However I'm not sure if it would have any actual effect on performance.
So if you could bless me with your insight I would be more then grateful, thank you.
Generally speaking it's a common practice to add a column to the users table to store the lastActivity time. Anytime the user logs in, or accesses a page, store the current time in that field. If you want to know whether or not they are online, see if the last recorded time is within a certain window - say, five minutes. You can query all rows to see how many users are currently online as a result.
I wouldn't be too worried about running queries every few seconds - your server can handle it (assuming these are well-written and not very verbose).
you can use datetime for field type and don't forget to record user IP so you can track time o
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.

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.

Currently online visitors logic in PHP

It could be a really easy thing to do but I am getting pretty confused by it.
Basicly, I want to get the amount of people currently browsing my website. The problem is, I can't count sessions. Many of them are created for different purposes. (e.g $_SESSION['age'] for the users who logged in.)
Also, there are "logged_in" and "not_logged_in" people.
In short, how can I count the users in my website in the most professional way?
Ps. Please note that I will run the function every 1-5 minutes, get the amount, store it to be used as cache. After 5 minutes, cache will be replaced again, and so on. Hence, db connections will be a possibility if you think that would be the most professional way.
One of the issues at hand is, your PHP doesn't know when your user closes the browser.
I've done something similar with a combination of a "last_used"-field in the user database (timestamp/datetime) and a "heartbeat"-function (jscript), which regularly sends an "I'm still alive"-command to the server (every x seconds), where then this last_used-field is updated. It ain't a high traffic site, but it does the job very reliable.
Then just count the amount of users which a very current heartbeat in the database:
SELECT COUNT(*)
FROM your_user_table
WHERE last_used > TIMESTAMPADD(NOW(), INTERVAL -30 SECOND)
You don't need a user table for this, you can use a session table, too. Such a mechanism can then be used for other features, too, like giving the users new messages on the fly and similar.

Categories