I just faced a problem. I am currently working on a project for school and I want to have all active users in the Sidebar (similar to a chat, but it's not).
First I thought of this (Pseudocode):
<?php
...
class user {
//Some instance vars.
public function __construct(){
//Write username in a textfile/database
}
public function logout {
//Delete username from textfile/database
}
}
...
?>
The problems are:
1) The user-object is stored in the $_SESSION[] Array. So I can't use the magic method __destruct(). That's why I made the logout() Method. (Problem solved ^^)
2) If we assume that the user is logged in on 2 devices (eg. Laptop, Smartphone) with the same ID and he quits the session on one device, the other device will also be removed.
3) The user probably doesn't want to press the logout but and just closes the browser window. How do I know, that he logged out / quit the session.
I know, that PHP is not the best programming language for this kind of task, but I really want to do this project in PHP. I am really sorry, if this question has already been asked, but I carefully searched through all related questions and all of them differ (more or less) from mine.
Thanks in advance :)
I think a much better approach (and the one that's usually employed) is to have a table that contains two columns. The user id and the last time that the user was active on the site.
You'd keep this table up to date at login and potentially each time a user loads a page or performs some significant action on the site.
To show who's online you then query this table for any users that have been active in the last N seconds/minutes.
You may optionally wish to add a "cleanup" job that removes users from the table where their last activity was more than (something >N) seconds/minutes ago to keep that table from becoming too large.
Related
I'm currently trying to display all online users on my SITE'S userpage using the php session variables. To do this, whenever a user logs in or out, a column in a database gets set to "1" or "0".. However this doesn't entirely work since the database doesn't get updated when the user closes their browser (and therefor destroys the session). So is there another way of checking if a certain sessionid is set??
I also want to know how the twitter and facebook handle this ?
You almost have it. The way that the vast majority of sites deal with the issue is to have a table like you do, but they add a timestamp to it and update the timestamp when a new page is loaded.
When querying the table, you simply look for say the last five minutes of active users and they are the "live" users on the site.
Technically, you don't even need to keep the "logged in/out" value in that table. If they have been logged in within the lat five minutes, they are probably still about.
There is no guaranteed, sure-fire, totally bullet-proof way of checking if a user is there or not. You can do some tricky JS to ping on and off, you can add even more JS that will try to alert the db when the user navigates away from the page - but at the end of the day, you cannot do anything if a browser is closed unexpectedly, or if that user loses power, or network.
On top of that web browsing is by default stateless and doesn't maintain a connection to the user after the server has finished sending code. The best we can efficiently do is update a table when the user does something new and assume they will be around for a few minutes at least.
I haven't checked but Twitter and Facebook most likely have Javascript code which notifies the server when somebody closes the page, probably coupled with a periodic heartbeat and timeout.
Check the onunload event and XMLHTTPRequest to see how you can make a request to your PHP application notifying of an user leaving (a library like jQuery might help you do this much more easily).
Add a field "last_visit" to user's Table and update it every time when user visit your site
When user login to your site find "last_visit" time and current time,after that use this function
$time_period = floor(round(abs($current_time - $last_visit)/60,2));
if ($time_period <= 10)
$online_offline_status = 1;
else
$online_offline_status = 0;
}
and then print your final result
<?php if (
$online_offline_status == 0){ ?>
<span style="color:#FF0000;">Offline</span>
<?php } else if ($online_offline_status == 1) {?>
<span style="color:#669900;">Online</span>
<?php }?>
I'm working on a PHP/MySQL application that allows for organization members to be maintained within the database. Currently, upon clicking on a "Add Member" span, I insert a blank entry into the database and return the created ID to PHP. Upon receipt of a valid ID, the application user is redirected via jQuery to an edit page that refers to the newly-created member.
As far as I can tell, this has the following advantages/disadvantages:
Advantages
Can instantly associate purchases/payments with a member upon submitting a jQueryUI dialog, since I already have the ID of that member.
Unifies what would have been separate add/edit screens, so easier maintainability on my side.
Disadvantages
There is a high possibility that I will have stale entries. That is, someone could click on "Add Member" multiple times and not save the new page, therefore causing entries to remain blank.
Not able to enforce as many constraints in the table, since I need to be able to accept NULL for all of the columns.
Am I thinking of all of the scenarios/advantages/disadvantages? Should I make a separate page for adding members, or is it better to accept the stale entries, and possibly add a few checks when I fetch all members to make sure that I'm not displaying a stale entry?
My database function for adding members currently:
public static function addMember()
{
$q = 'INSERT INTO ' . MemberTable::TABLE_NAME
. ' (' . MemberTable::ID
. ') VALUES (null)';
try
{
$db = new DBConnection();
$toRet = $db->execute($q);
}
catch(Exception $e)
{
error_log($e->getMessage());
$toRet = -1;
}
if($toRet > 0)
{
DBSystemEvent::logMessage("Added new member with ID $toRet");
}
unset($db);
return $toRet;
}
EDIT 1: After rereading the question, I need to clarify that members and users referred to in the first paragraph are different. Users refer to the person logged into the application. Members are not able to log into the application. This is similar to a hospital application (patients may not log in or edit their own information; only application users such as nurses or doctors may log in and edit information).
EDIT 2: While none of the given answers completely fit my problem (since I may have to insert into the database without knowing an ID), I decided to accept an answer based on how my question was worded (since making it any more specific may cross into too-localized territory).
It's a common problem - you need to know the ID before INSERT, but it's known only after. So there is only one adequate solution: use GUID (http://en.wikipedia.org/wiki/Globally_unique_identifier) instead of autoincrement ID. Generate guid from PHP code, for example com_generate_guid(), and do not preINSERT empty rows at all. And make relations between tables with GUID fields.
It's little bit unclear to me what exactly is the workflow of your site.
If user comes to you page then I assume that he must login from where you get his ID. If he is new user then he is redirected to userdata.php?id=0 where he enters his data. After submitting you should check if $id=0 and if the user with the same username/id/.. exists (SELECT... WHERE ID=xxx) and warn user to change his username. If no match is found then you can do INSERT and obtain the new ID.
If in future user wants to change his data then after login you can direct him to userdata.php?id=123 (where 123 is his ID). Then you can check if $id>0 and do UPDATE.
If you can, switch to postgresql. This will allow you to use a sequence to provide you with a unique ID without entering empty entities into you database.
Funny enough one of my clients is using the same approach you haven chosen and so far this lead to a lot of maintenance and work load overhead to weed out the empty entries from the db.
If you cannot use a database that offers sequences consider using an otherwise empty table which only atomically gives you unique ids. That way you can already start using the id to prepare relations on the client side and then enter them in bulk into the db when the member is finally created.
I'm not awesome enough to write a chat application, and I'm trying to get one to work, and I've recently downloaded one from here, it's pretty good so far, as I've tested it out on XAMPP, but I have a slight problem. I'm trying to generate a list of online users to give it a more practical application-like feel, but the problem with that, is I have no clue how to do it easily.
When users login to my site, a session named g_username is created, (the chat says 'username', but I'll fix that) and from what I see so far, the easiest method would be to store their username in a database called OnlineUsers and call that data via Ajax, but, the other problem, is that it's session based, and sometimes the users can just leave, without logging out, and I intended to run a script to logout the user from both the OnlineUsers table, and by deleting the session.
If they leave without logging out, they'd be online forever! I could potentially suffix a bit of code on every page, that toggled an ajax event on page close, the event being a script that kills their OnlineUsers table record, but then again, that would load the server with useless queries as users jump between pages, as far as I'm aware.
Creating my entire site in Ajax isn't really an option, as it's a load of different sites combined in to 1 'place' with a social 'layer' (if you will) from a social service.
Does anyone see a way to do this that would make sense, and be easy to integrate, and do with Apache, without command line access?
You could so something like storing a timestamp of the users last action in a database, comparing that timestamp when outputting online users and making sure that it was done at most 1 min ago.
Run on all/vital pages:
(Deciding if the last action is outdated, you could also check if it was done for one minute ago to reduce the database-load)
if($user['lastAction'] < time()) {
//update into database, last action is outdated
}
When calculating the amount of users online and is within the loop of each timestamp
//If the users last action was within a minute, the user is most likely online
if(($row['lastAction']- time()) > 60*60)
//count user as online
you could have a cron job [if you have cpanel] running on the server once every 60secs or so, that checks when a user last sent anything via the chat if they have not in the last lets say 5mins then remove their entry from the online users list.
I want to set up a few internal statistics for one of my dynamic sites. The idea is to make available to each member of the site:
a) How many times the profile has been seen in the day (1 click = 1 ip = 1 view)
b) How many times the profile has been seen in the month (1 click = 1 ip = 1 view)
c) How many have left since the mail button "contact".
Before developing this in php, I wanted to know if you would not have a resource that these actions. It would save me some time.
Sincerely,
Well, you would just simply need to have a DB where you could save those statistics. Then, you would create a class with a few functions that save statistics to this DB. E.g.
function addPageview($pageIdentifier, $loggedInUser) {
// code to save to DB
}
Then, when a page is viewed (e.g. the profile page of someone), you do a call to this addPageview() with the correct page identifier (e.g. the URL) and the logged in User so you know who has viewed the page. You leave $user empty if there is no logged in user.
Good luck!
So if you want to increase your profile-views counter by 1, you can restrict this to do so every 24 hours by setting a cookie on the visitors computer with that specific users ID. The user can clear their cookies and visit the profile again, but "commoners" dont know about this technique.
In your code for viewing the profile, you use the following pseudocode:
if user has no cookie
bump views up by 1
So I create my own internal link tracker for ZF.
I don't use cookie.
I check if an ip is already back on the site. If so, I change the date of last visit, otherwise I created. Then, I check if the called page has already been visited. If so, I change, otherwise I insert. Then, I check if the association ip / page exists: if so, I change, otherwise I insert.
In the end, I can have a system of click per day, month, year, and for su ...
I wrote a tutorial on the occasion on my blog, because now it is only really suited to the current project.
Thank you for your support.
Sort of a methods/best practices question here that I am sure has been addressed, yet I can't find a solution based on the vague search terms I enter.
I know starting off the question with "Fast and easy" will probably draw out a few sighs, so my apologies.
Here is the deal.
I have a logged in area where an ADMIN can do a whole host of POST operations to input data relating to their profile. The way I have data structured is pretty distinct and well segmented in most tables as it relates to the ID of the admin.
Now, I have a table where I dump one type of data into and differentiate this data by assigning the ADMIN's unique ID to each record. In other words, all ADMINs have this one type of data writing to this table. I just differentiate by the ADMIN ID with each record.
I was planning on letting the ADMIN remove these records by clicking on a link with a query string - obviously using GET. Obviously, the query structure is in the link so any logged in admin could then exploit the URL and delete a competitor's records.
Is the only way to safely do this through POST or should I pass through the session info that includes password and validate it against the ADMIN ID that is requesting the delete?
This is obviously much more work for me.
As they said in the auto repair biz I used to work in... there are 3 ways to do a job: Fast, Good, and Cheap. You can only have two at a time. Fast and cheap will not be good. Good and cheap will not have fast turnaround. Fast and good will NOT be cheap. haha
I guess that applies here... can never have Fast, Easy and Secure all at once ;)
Thanks in advance...
As a general rule, any operation that alters state (whether its session state, or database state) should use POST. That means the only 'safe' SQL operation you can perform with GET is SELECT. Even if you're only using a back-end admin thing, you shouldn't use get. Imagine re-opening your browser and finding that the last time you closed firefox was on your 'DELETE EVERYTHING' GET->delete page resulting in everything being deleted again.
One of the main reasons for this is preventing cross-site request forgeries. For example, if you had a page that took a GET variable such as http://example.com/account?action=logout, an attacker could post an image on your site like this:
<img src="http://example.com/account?action=logout" />
and anyone who opened a page containing that image tag would be immediately logged out, even if they were an admin. It would be very annoying to then search through your raw database for that data and remove it.
Although POST operations are 'nearly' as easy to forge, as a general rule with any web security issue, the trade-off is speed/simplicity vs. security, so you're going to have to choose one or the other.
You should have some kind of session set up.
Using POST over GET gets you nothing tangible as far as security is concerned. POSTs can be forged just like GETs.
So assuming once your admin logs in, you've got some kind of identifier in the session, you just leverage that.
Consider something roughly similar to this:
<?PHP
session_start();
if (empty ($_SESSION['admin_id'])) die("Log in, son.");
if (empty($_GET['record_id'])) die("You've got to tell me which record to delete!");
if (! is_numeric($_GET['record_id'])) die("Invalid record ID");
//just to be totally safe, even though we just enforced that it's numeric.
$record_id = mysql_real_escape_string($_GET['record_id']));
$sql = "DELETE FROM table WHERE record_id='{$record_id}' AND admin_id = {$_SESSION['admin_id']}";
mysql_query($sql);
echo "Record was deleted (assuming it was yours in the first place)";
?>
In that example, we're avoiding the "delete someone else's records" problem by leveraging the WHERE clause in the DELETE query. Of course, to be more user friendly, you'd want to first fetch the record, then compare the admin_id on the record to the admin_id in $_SESSION, and if they don't match, complain, log something, throw an error, etc.
HTH
You're saying: "What if Admin 123 access the URL of Admin 321 directly, thus deleting his stuff?" no?
If that's so then, every admin that is logged in should have at least one session with some unique identifier to that admin. If not, he shouldn't be able to be in the admin section in the first place. Can't you just compare the identifier in the URL with the identifier in the session?
If any user, not just an admin, access those 'delete me' URLs he should be identified by a session as the original 'owner' (admin) of that data.