I've got my login sorted, which sets an array of around 15-20 different database items, the user can change some of these and admins can change all of them.
Obviously for a general user, it would be silly having to reset the entire session when they change something on their account. For example their name. My code DOES work with the database, it is inputting the name after the user changes it.
$username=$this->session->userdata("logged_in");
if(strlen($name)>=1){
$databasename = $row->firstname;
if($name != $databasename){
$input_array['first']= $name;
$this->session->unset_userdata($username['name']);
$this->session->set_userdata($username['name'],$name);
}
}
To add some background to my code, the input array is defined outside of the if statements, and is the added to if the name is NOT equal to the database name and if the name has been changed.
All it does, is save the data to the database, and does not change the session variables. Ideally they need to change, they do change if i log off then back on, however this is impractical.
If i understood your correctly, you want to make sure that the user always get's displayed the up to date data, even when the admin did some changes to it, e.g. to his username. If so, then there are 3 ways to do this.
The first one
Only store the userid in the session as well as any data that does not need to be up to date. You then select the needed data, e.g. the username from the database when a request has been made. That will ensure that everything is always up to date.
The second one
Store the userĀ“s session id in the database when it will be created. To get the session id use the session_id function. You then use the session_id function again, but this time with the id from the sesison you want to destroy as the first parameter. e.g
session_id($old_session_id);
session_start();
session_destroy();
This will crerate an empty session (and therefore kill the existing one), and destroy is right after that. and then the user has to log in again when he visits your site the next time.
The third one
Let PHP store the sessions in the database, that way you can modify them or simple remove them and force the user to relog. I would however be careful with this solution at it might be an overkill, the first one tho is a very common one, the second one is also a great way.
Explanation
The reason why it does not work otherwise, is the fact that the session does still contain the old data which has been set previously. If the user updates his username himself then you can also set it at the session, but if the admin does it (or any other one except for the user himself), the username (just as a example, it can of course be anything else) in the session won't change.
Maybe because you get variable $logged_in and try to put back another variable with name "username". If i right understand your problem you need save logged_in:
$username['name'] = $name;
$this->session->unset_userdata('logged_in');
$this->session->set_userdata('logged_in',$username);
Related
I'm developing a site in PHP. When the user session starts I load all his db row in the $_SESSION var. When the user changes a db value I update the $_SESSION var too.
The problem starts when more than one session is active for the same user. Is there a way to update the data for all the sessions of the same user without overloading the database? Or, alternatively, is there a way to force php to use the same session file for all the session that belongs to the same user? Or I must simply query the db every time a session continues?
And another dilemma is: is it worth it? I mean, I do not know how much this mechanism could alleviate the server load, and I do not know if this mechanism is applicable to file-based sessions or I must use another session storing type.
This question is somewhat related to this other question on mine (even if the workaround for this is simply to delete all session files).
It really reaches the question why would you need to many data in a $_SESSION. And you should really take a time to decide which data is so often needed to be displayed.
In most of the cases you only need session identifier that keeps the user logged in, containing user_id, to take the needed data directly from the database.
Assuming the user can change its avatar, and you haven't go so many places to display this avatar, you don't need to store it in session, nor to SELECT it at the very same time. For instance, you can have a trigger page, which SELECTS the avatar by $_SESSION['user_id'] when he tries to send personal message to another user. Otherwise, you can put a cache (i.e. using memcached) where a query, which selects the user avatars should not be made more often than once an hour.
If user changes an email, it's the same. If somebody else tries to send him message, you trigger the SELECT query. Otherwise a cache is set.
So, let's say the user has changed his avatar, email, some other trivial info, then accessed your index page. In his session you load only the identifier. In the db the records are present, but they are not selected yet. So you have neither server load, because the session is light, nor database load, because no SELECT queries were sent.
No matter how many times the user tries to set his session (in this case logs second time), you have a present data in the db, and a session only with identifier. You can identify all his instances, but never use a data, which is not needed.
1 Well, I (don't, but) could do this with my session handler. I use databased SESSIONS with some extra information/columns like username and userid. That way I can exactly determine which session belongs to which user without fiddeling around with the serialized data.
http://php.net/manual/de/function.session-set-save-handler.php
2 But in your case it might be simpler to update your user table and then SELECT the user again to put the (new) data to $_SESSION['user']. (You will need some "user data was updated" info, to reload new data for all sessions).
3 Or you just avoid that a user can login more than once.
I developed a small application Contact Manager and while updating the contacts, the contact id is being sent using GET method. But a user can change the Id and edit any contact, how can i add security to it?
<td>
Update
</td>
http://localhost/contmanager/home.php?action=update&contactid=1
If i change the id to some other number, another contact will show up.
You can't control what the client asks the server to do.
If you want to add restrictions on who can modify particular contacts then you need to Authenticate (username + password, client SSL cert, OpenID, etc) users and then check if they are Authorized (this will depend on the business logic you decide on) to modify the entry in question.
As Quentin pointed out, your logic is going wrong here, data like these should be stored inside sessions and shouldn't be passed using $_GET or $_POST, unless and until required, if you still need to pass for some reason, than you can read my answer ahead for a solution.
Store the user id in a session, so when the user updates, just compare the session id and $_GET id, if it matches, update the entry else throw an error.
When the user logs in
$_SESSION['user_id'] = $db_data['col_name'];
Now, before the entry is updated...
if(!empty($_GET['user_id'])) {
//First validate, you can check whether the id is only numeric, is valid db entry etc
$user_id = $_GET['user_id']; //Store the id in a variable
} else {
//Invalid
}
if($_SESSION['user_id'] == $user_id) { //Compare the ids
//Process
} else {
//Not Valid
}
Note: Make sure you use session_start() at the very top of the page,
before you start writing anything.
You need to use session and to store the data inside like this:
<?php
session_start();
$_SESSION['contact_id']=$contact->contact_id;
<td>Update</td>
?>
use it like this:
http://localhost/contmanager/home.php?action=update
and when you need to use contact_id(after the GET) :
session_start();
if(isset($_SESSION['contact_id']) && !empty($_SESSION['contact_id'])){
$contact_id=$_SESSION['contact_id'];
}
A PHP session variable is used to store information about, or change settings for a user session. Session variables hold information about one single user, and are available to all pages in one application.
PHP Session Variables
When you are working with an application, you open it, do some changes and then you close it. This is much like a Session. The computer knows who you are. It knows when you start the application and when you end. But on the internet there is one problem: the web server does not know who you are and what you do because the HTTP address doesn't maintain state.
A PHP session solves this problem by allowing you to store user information on the server for later use (i.e. username, shopping items, etc). However, session information is temporary and will be deleted after the user has left the website. If you need a permanent storage you may want to store the data in a database.
Sessions work by creating a unique id (UID) for each visitor and store variables based on this UID. The UID is either stored in a cookie or is propagated in the URL.
I have found that on my simple web application, if you leave the page alone for more than about five minutes and then reload the page, calling session_id() will return a different value the second time. Users remain logged in, so the session data is being moved across to the new ID, but I keep track of cart items in a MySQL database based on the session ID, and when the ID changes, the association with the cart items is lost.
Nowhere in my code do I ever call session_regenerate_id()
Help!
You might want to check your code to see if you are using session_id() with an argument anywere as this will also change the session id. Without seeing the code it is hard to be specific as to a fix or to know what is going wrong.
Few more things you might want to check if encountered such situation AND you do use session_name():
From PHP Online Manuals:
Warning! The session name can't consist of digits only, at least one letter must be present.
Make sure you dont have spaces in your session_name() argument like
session_name('blah blah')
Both situations force a new session id generated every time.
lets say i have a session called $_SESSION['id_user']
and it stores session of the user id. Lets say that the user profile is www.example.com/profile.php?id=123
if I want to check if that profile is the user and if i do something like
if(isset($_SESSION['id_user']))
{
if($_SESSION['id_user']==$_GET['id']){print something since this is the users own profile}else{print nothing}
}
Is the above code good enought? or is their any security problem? or is it wise to compare GET variable with SESSION variable? its not printing anything that will give user identity away or anything I just want to show a (edit profile button) for the user that is visiting his own profile.
Yes, it is safe - the session is stored on the server and a user cannot change the session data manually. Unless their session is hijacked, then only they will be able to see their own profile.
For piece of mind (and to prevent possible SQL injections I'd just cast the two variables as (int)s before using them (also cuts down on having to write $_SESSION['id_user'] multiple times. I would also use === which checks the variables without any type conversions.
As mentioned in the comments by Thomas, if you've got the users ID in the session already, then unless you need to (differentiate between profiles), just use that and don't send the user ID over GET.
As in many web applications, when my users log into my site, I set several session variables that control permissions for accessing site functionality.
Whenever a user undertakes an action that would result in a change to those permissions, I update the session variables as part of the normal processing flow.
But sometimes a user's session needs to be updated based on the actions of another user. For example, a moderator upgrades a user's permissions. The moderator does not have access to the user's session space, so the normal update functions cannot be run for the affected user.
I have considered a few ways of forcing an update to another user's session, but they all have drawbacks:
I could search for and delete their
session from the sessions table, but
this requires a full table scan
(where sessdata like '%user_id%'),
and it could cause the loss of
content that the affected user may be
engaged in generating.
I could force a session update
periodically, such as when
sess_time_to_update is triggered.
But there is no guarantee that this
will transpire prior to the user
attempting to access the
functionality for which the update is
needed.
I could run a complete series of
variable updates on every page load,
but the whole point of maintaining a
session is to avoid that overhead.
I could set a flag indicating the need
for a session update, but that signal
would have to be interrogated at every page execution, and in every controller. (I know that I could extend CI_Controller as MY_Controller, but I don't want to do that)
I'm already sending the user an email
notifying them of the change in
permission, and it's easy enough to
make them click a session update link
(or even log out and log back in).
But there's no guarantee they are
going to even read beyond the subject
line, let alone actually click the
link.
So is there anything I'm missing? Am I looking for a magic bullet that does not exist?
(Note that I've tagged this with CodeIgniter, and made reference to CI-specific technical details, because that's what I'm using. That said, this isn't a CI-specific (or even a PHP-specific) issue.)
Thanks for the help!
Well, one option would be to set an "ACL Version" number (either for all users, or for each user). Then when initializing the session (well, when you call session_start()) check to see if the stored version matches the session's version. If it doesn't, refresh the ACL.
Another slightly different way would be to add a column to the sessions table ("status" or "dirty", etc). Then, instead of killing the session, simply update that status to 1. Then when loading the session, check that flag to see if it's 1. If so, reload the cached data in the session and set it to 0. If not, continue on...
As far as updating another user's session, I wouldn't do that... If sessions are managed by PHP, then you'll need to kill the current session and start the one you want to modify. That's just asking for problems... (you need to do that, since PHP's mechanism does not use serialize.).
As far as deleting their session, I wouldn't worry about the full table scan. Unless you have a TON of users updating permissions all the time, it's not going to matter. The data loss is a significant concern, so that nicks that idea...
As far as the other 2 options, I think you hit the nail on the head, so I have nothing else to offer on them...
I'm going to take a stab, though my approach is not entirely applicable to Code Igniter.
The way I've solved this problem in the past is to make a User object model with a constructor that takes the UserID from the database primary key where the credentials are stored. I'll write a static login method that checks login credentials and then instantiates and returns an instance of user if the login is correct for a row and then sets the session.
So far so good, right? So all your permissions, access levels etc are stored in the database. Just like having a login method, we can have a refresh method that reinstantiates the object, re-fetching from the db off the already obtained primary key.
class User{
public function __construct($uid){
//fetch from the db here
$sql = 'SELECT FROM User_Table WHERE UserID = ?';
$params = array($uid);
//fetch and assign using your flavor of database access, I use PDO
//set all your object properties for access, as well as user_id, something like
//$this->user_id = $result['UserID'];
}
public static function Login($uname, $pass){
$sql = 'SELECT UserID FROM User WHERE Username = ? AND Password = ?';
$params = array($uname, md5($pass));
//again I'm going to employ pseudocode here, fetch according to your preferred system
if(!empty($result)){
$_SESSION['user'] = new User($result['UserID']);
}else{
//login failed!
return false;
}
}
final public function _refresh(){
//refresher method. Since the controller sets all the object properties for access
//reconstructing and assigning it refreshes these priveliges.
$_SESSION['user'] = new User($this->user_id);
}
}
Using this model, whenever I am performing an action with the user in the session that might potentially need time-sensitive permissions, I can call refresh on the user object all ready in the session. Let's say we have a controller function to access a restricted form.
function _topSecret(){
$_SESSION['user']->refresh();
if($_SESSION['user']->specific_permission_from_db){
//Perform the special action, get the view, whatever.
}else{
//redirect to an error page
}
}
So if you already have routines written for the admins, all they need to do is set the user's privileges in the database, and when the refresh method runs on the specific, time-sensitive functions, that data will be put in the session for the user. So you're not necessarily updating another user's session, you're just determining which actions are so chronologically sensitive they require the newest permissions and issuing that command to the user object in the session.
This has proven pretty efficient for me, since reconstructing need only be performed on actions that need the most up to date permissions. Again, I'm not sure how useful it may be in the context of CI and your individual application, but I figured I'd share. I'm assuming you've already done all the necessary session security measures and started the session - most frameworks like CI will handle this for you through their native means.
Add a column in the session table that can hold the primary key of the user object. Set it upon login and use it later to update the session.
Edit: If you don't want to extend the session table, make an additional lookup table where you have the user object id and the session key link.
If your're storing the session as a native php session I'd tend to leave it alone, and allow them to get some kind of notice that they need to login/out to refresh the setting. I've also had sites where the session data is stored in the db and then its much more trivial to just write the new setting in.