I have a site with both public and private sections. To access the private areas, users have to log in, which sets session variables. The login script authenticates everything and then changes the header location to the private page:
//get info from database and if user is authorized, then redirect
session_start();
$_SESSION['authorized'] = $user;
$_SESSION['firstname'] = $first;
$_SESSION['lastname'] = $last;
$_SESSION['password'] = $pass;
$_SESSION['position'] = $position;
$_SESSION['email'] = $email;
header( "Location: index2.php" );
Then on the index2.php page, I have an authorization check at the top:
session_start();
if(!isset($_SESSION['authorized'])){
header( "Location: denied_unauth.php" );
die();
}else{
//rest of page
Everything works like a charm. EXCEPT...if there's no activity for 20 minutes, users have to log back in. Index2.php uses jQuery to load divs into it, so users never leave index2.php. If they click to retrieve a page on the private site after inactivity, instead of the div they requested, they get a "logged out" message and are presented with the login form again. It's the exact same script as the one listed above, setting the exact same session variables and redirecting them back to the exact same page (index2.php), which is the same page they're logging in from - basically, just reloading the page.
Whenever I test this, index2.php isn't recognizing the new session. It's sending users to "denied_unauth.php" every time. This tells me that the login script is working, it's recognizing the username and password and sending users to index2.php...but when the page reloads index2.php, the session isn't being recognized. I even tried adding a random number to the end of the URL "index2.php?somerandomnumber in case it was a caching problem, but it didn't help.
Any ideas?
EDIT: To be clear, I'm not asking for a way to STOP the user being logged out. I'm trying to figure out why, if new session variables are created during the log-back-in script, it's not recognizing them when reloading the page. The session variables ARE created the first time they log in, so I know that part of the script works. But when they go back to the page again after re-logging, it doesn't recognize the new $_SESSION['authorized'].
EDIT 2: Here's what is happening:
From the page index.php, user logs in. The login form creates a session and redirects the header to index2.php
Page index2.php checks whether session is set, if not it kicks the user out to a "denied access" page.
User clicks links within index2.php page to load sections into the main div
Each file that loads into the main div has a check on it to see if the session is set. If the session exists then the file loads, if the session is expired then instead of the file, it shows the user the login form and asks them to log back in. (all this works so far)
When the user logs back in from this form, a new set of session variables is created. I have tried both setting a new session or session_regenerate_id() and neither seems to work.
This new session is NOT being recognized by index2.php and it kicks them out every time. I have tried both redirecting straight to index2.php after login, or simply loading the div they'd requested in the first place, but both ways, index2.php doesn't see that the session is set and the user ends up on the "denied access" page.
Sessions have a timeout specified in the php.ini file:
; Lifetime in seconds of cookie or, if 0, until browser is restarted.
session.cookie_lifetime = 0
; After this number of seconds, stored data will be seen as 'garbage' and
; cleaned up by the garbage collection process.
session.gc_maxlifetime = 1440
; Document expires after n minutes.
session.cache_expire = 180
If you cannot or do not want to change that globally on the server, try using an .htaccess file on Apache.
I'm not sure it will work, but if you don't have access to your php.ini or .htaccess file,
you might wanna use this after your session_start():
session_regenerate_id(true);
You should also put this in the page your jquery is loading divs from.
One surefire way to deal with this is to create an ajax heartbeat script you load in the background every X minutes which only needs to "touch" the session. This expects all your users to have JavaScript enabled though.
It's a session lifetime problem. you can solve this problem two way. here the description:
change the php.ini file. increase the session.gc_maxlifetime, by default it is 1440 that means 24 mins. you can increase this by second.
Here the second way without change the php.ini file. you can set session lifetime with php by using the following code :
ini_set('session.gc_maxlifetime', 30*60);
session_start();
I finally figured it out and got it to work. The login form was bound to a jQuery call on submit, I changed it so that the new login form actually performs the post call...and it started working.
Related
I have a login page/system which has worked correctly for years, leaving the user logged in until he/she either closes the browser window or logs out manually. But lately (starting yesterday) after only a few minutes of inactivity the session cookie/s seems to expire, causing the user to be logged out automatically.
This happens on different browsers and different operating systems, the PHP version is 5.6.29, which has been changed recently (before it was 5.5 and even 5.3).
I create and refresh the session on every page with session_start(). The login script first checks user name and PW and also gets some other user data from the database. These other data are first saved in variables and then written into session variables like
$_SESSION['username'] = $name;
$_SESSION['usertype'] = $type;
The successful login state is saved like this:
$_SESSION['login'] = "ok";
On the other pages I check the login state like this:
session_start();
if(($_SESSION['login'] != "ok") OR ($_SESSION['usertype'] != "xxx")) {
header("Location: ../login.php"); /* redirects to login page if conditions are not true */
exit;
}
The login works, and logged-in users can proceed to other pages as long as the do it more or less in constant succession, but if someone waits a few minutes before proceding (i.e. without any acitivity), he/she is logged out (i.e. redirected to the login page when trying to open another page).
To make it extra-nasty, half of the time it just works as expected, also after half an hour...
Any help would be very much appreciated.
UPDATE:
Adding ini_set('session.gc_maxlifetime', 3600'); and `ini_set('session.cookie_lifetime', 3600); didn't help. I removed it again.
After that I had a look in the error logs and found this:
ap_pass_brigade failed with error 103: Software caused connection
abort
(problem is, I don't have access to the server settings - this is on a shared webspace...)
You can see the php configuration (php.ini) by phpinfo();
<?php
phpinfo();
Check the session.gc_maxlifetime values first then if you need to set it see the following ways.
You can set it with .htaccess file if you don't have permission for edit the php.ini file.
.htaccess
<IfModule mod_php5.c>
php_value session.cookie_lifetime 3600
php_value session.gc_maxlifetime 3600
</IfModule>
Even you can set it by ini_set();
<?php
ini_set('session.gc_maxlifetime', 3600);
For anyone who is interested: The session didn't actually expire, but the session variables disappeared (and reappeared again randomly).
This is discussed in a follow-up question I posted here:
php $_SESSION variables disappear and reappear randomly
You must have changed the session.name from default PHPSESSID to something else. Keep its default value session.name = PHPSESSID. Everything will be OK.
It's a PHP bug.
When the user decides to sign out, they obviously do so by using a "Sign out" button.
When they do, this script is executed:
if(isset($_POST['submit_Logout'])){
$_SESSION['backend']->logout(); // see this function bellow
unset($_SESSION['user']); // unset only this session since there are other sessions I'd like to keep
session_regenerate_id(true); // makes sure the session id is updated, and the old one is discarded
KD::notice('success',$success_LoggedOut); // adding a notice to another session
KD::redirect('/'); // redirecting the user using header();
session_commit();
}
I'm just unsetting this particular session (user) since there's other sessions that keeps other data available, regardless if the user is logged in or not, to better the user experience.
The logout()-function looks like this - for now:
public function logout(){
$this->accessible=false; // just a flag to check against (see bellow)
$this->username=''; // empty the username
}
Since I'm unsetting the session that holds the related user data, I just realized that this function is probably unnecessary. Alternatively move the unset part etc. into the function..
Anyway, I've come to experience that when a user has logged out, he/she, or somebody else for that matter, has the opportunity to just hit the backwards button in their browser, and voila, they can view the page(s). Of course, if they start clicking on any links, they gets thrown out. But the back-button is still available..
I believe this happens as a result of cached pages/views by the browser. So when they click the back-button, they see a cached page/view stored in the browser memory or something..
Since this page, or view, is loaded into my template trough a index.php page with a permanent <head>, there's not much I can do about the caching of these restricted pages/views. Or is there?
Deleting records from the browsers history is not possible? or preventing these pages from being recorded in the first place?
Point is. What I need to do, i believe, is to force the browser to always request the page from the server. So regardless if the user hits the back-button, or a link to a restricted page, the page should always reqest it from the server, and not the browsers memory..
Or am I not getting this correct?
If so. I do wonder how. How is this usually done?
I have this in my class
private $accessible = false; // when logged in, this is set to true
public function accessible(){
return $this->accessible;
}
At the very top of the page that includes the views into the restricted area I have this:
if($_SESSION['user']->accessible()===true):
Othervise the user is prompted with a login screen.
But that doesn't work as expected. This check is not performed when the user uses the back-button in their browser...
Thanks in advance..
UPDATE
Heres a quick overview of my structure/layout:
/*
when the user is logged in/out, the script that does that is executed up here.
That includes setting the sessions etc. aswell - which means, if the user is not logged in, the access will be set to false.
*/
<head>
</head>
<body>
/*
Here I include different pages with php include;
These pages can be home.pg.php, contact.pg.php, and of course restricted.pg.php
each of these pages includes different content (views as I like to call them) that is presented to the user based on their interaction.
Now. When the user tries to access the restricted.pg.php, I have this at the top:
*/
if($_SESSION['user']->accessible()===true):
/* now each view that is included here should be not accessable if accessable() is not true. */
else:
/* the user is presented with a login form */
endif;
</body>
Did this help?
All the pages that require some to login should have something like this,
session_start();
if(!isset($_SESSION['user']){
//REDIRECT USER TO LOGIN PAGE
}
If its because of the browser caching issue that hitting back is taking you back to cached version of the page (even though user is logged out) then you should redirect the user twice (good practice).
what I mean is create a file called logout.php so when user clicks on logout button,it redirect the user to logout.php (that'll have the session unset code) and after that redirect user to login page.
so current page ----redirects to---> logout.php ----redirects to----> login.php
i think in every page you can just check whether a session is set or not. ex. Session::handlelogin('user')
then you can just make a function namely handlelogin in Session class
Class Session {
function handlelogin($user) {
if (!isset($user)) {
//redirect the user to your login page
}
}
}
Notice: just set this up in top of the page if your using MVC architecture then you can set it up in the Controller
Session::handlelogin('user')
When I login, I have 2 options; Remember Me or Not. Now my problem is with the Remember Me part UNCHECKED. When it is unchecked, this means a session is created.
Now the problem is, when the session is created, if I go directly on the login.php, the session resets, meaning there is no session anymore and I need to login again(which is the index.php)
Here are my codes, I need it to go on post.php when user tries to go to login.php directly after logged in! It works when there is cookies(that is remember me checked) but it doens't when there is a session.
After correct loggin in login.php you have code: $_SESSION['sess_username'] = $userData['username'];
but in top of the login.php you check if user is logged by: isset($_SESSION['username'])
It should be: isset($_SESSION['sess_username'])
Now if you say they want to be remembered, you don't put anything in your session variable $_SESSION['sess_username']. So the next page it will be empty wich makes your site think you aren't logged on
I never used the function session_write_close();
A quick google delivered me this.
"void session_write_close ( void ) - End the current session and store session data."
Are you sure you are using this correct? As it states it closes the current session.
I am working on creating a website from scratch and am currently stuck with session stuff.. I know generally how sessions work and how to store things into $_SESSION after session_start() but my main problem is this. After clearing the cache and opening a new window, submitting a login request the FIRST time wont submit correctly and the page reloads and nothing has changed, but AFTER the first time, it works fine...
my login.php handles either a) the post request, or b) the login via url (for testing purposes) so a link to "user/login.php?username=facebook&method=get" would be sent to the code below and set the user to logged in with the name facebook..
<?php
session_start();
$method = $_GET['method'];
if($method == "get") $_SESSION['username'] = $_GET['username'];
else $_SESSION['username'] = $_POST['username'];
header('Location: http://www.imggroups.com');
?>
Im not sure if this matters, but, on the index page, I check to see if the user is logged in by doing this. starting session obviously, then doing. if(isset($_SESSION['username'])) echo whatever i need for logged in.. else echo whatever for not logged in.....
The issue is that you are redirecting the user to a new page, but the old page has not finished closing, so the session is not yet saved.
In order to fix this I usually setup an interum page which redirects to the correct page.
Alternatively you might be able to use session_write_close() (http://www.php.net/manual/en/function.session-write-close.php) before using the header redirect
The fact of the matter is, it is setting the session, BUT it's redirecting you to a different domain that the session isn't allowed on. If you access the website without the 'www.' in front then get redirected to the www version afterwards, then it's going to say your session doesn't exist. Use the following:
session_set_cookie_params(0, '/', ".imggroups.com");
Put it before your session_start() and it will work for both www and non-www versions of your site.
If that is the total of the login.php, I believe there is easier ways to do that:
If it does not matter whether the username actually comes in via _GET or _POST, then use _REQUEST as it encapsulates both.
if( isset($_POST['username'] ) {
$_SESSION['username'] = $_REQUEST['username'];
}
If it does matter, you don't have to trust or use an external parameter, just look at what's there:
if( isset($_POST['username'] ) {
$_SESSION['username'] = $_POST['username'];
} else if( isset($_GET['username'] ) {
$_SESSION['username'] = $_GET['username'];
} else {
// whinge
}
I've not run into that issue with PHP before, but you can also do a session_write_close(); to force it to write out the session before it redirects to the other page.
I also had this same issue if i open new window after logout in new tab or browser and try to log in login page stuck at loading i can see that session has been started because if i refresh on same stuck window i logged in to my dashboard.
But it was resolved later by redirecting it right:
Before
login.php (after ajax successful) --> index.php (if logged in) --> dashboard.php
After
login.php (after ajax successful) --> dashboard.php
hope it saves anybody's time & effort because i suffered alot!
I need to destroy a session when user leave from a particular page. I use session_destroy() on the end of the page but its not feasible for me because my page has pagination. My page is: abc.php?page=1 or abc.php?page=2 or abc.php?page=3.
So, I need to destroy a session when a user leaves from abc.php page. How can I do it without using a cookie?
Doing something when the user navigates away from a page is the wrong approach because you don't know if the user will navigate to a whole different page (say contact.php for the sake of the argument) or he/she will just go to the next page of abc.php and, as Borealid pointed out, you can't do it without JS. Instead, you could simply add a check and see if the user comes from abc.php:
First, in your abc.php file set a unique variable in the $_SESSION array which will act as a mark that the user has been on this page:
$_SESSION['previous'] = basename($_SERVER['PHP_SELF']);
Then, add this on all pages, before any output to check if the user is coming from abc.php:
if (isset($_SESSION['previous'])) {
if (basename($_SERVER['PHP_SELF']) != $_SESSION['previous']) {
session_destroy();
### or alternatively, you can use this for specific variables:
### unset($_SESSION['varname']);
}
}
This way you will destroy the session (or specific variables) only if the user is coming from abc.php and the current page is a different one.
I hope I was able to clearly explain this.
To trigger when the user actually leaves the page, you must use Javascript to send an asynchronous request back to the server. There's no way for the server to magically know the user has "left" a page.
See http://hideit.siteexperts.com/forums/viewConverse.asp?d_id=20684&Sort=0 .
I had a similar issue but mine was on a page reload I wanted variables that I had printed to be destroyed. It was for my login for my web design class I was making error feed back for if user put in a bad username or password. I could get the error to display but if I hit refresh page they errors would just stay there. I found that by just setting the variable to nothing after it printed would kill it. Take a look at what i did:
<p>To access my website please Login:</p>
<form name='login' action="./PHP_html/PHP/login.php" method='post'>
Username: <input type='text' name='username' /><div><?php print $_SESSION['baduser']; $_SESSION['baduser'] = "";?></div><br />
<div style="padding-left: 4px">Password: <input type='password' name='password' /><div><?php print $_SESSION['badpass']; $_SESSION['badpass'] = "";?></div></div>
<input type='submit' value='Login' /> or you can Register
I don't know if this helps at all but it worked for me.
Also, thanks to all you that post on sites like this to help those of us who are still learning.
For a particular page you need to destroy the session, then unset the all session variable
using
unset($_SESSION['varname']);
For the whole site you can use session_destroy();
I solve the problem.First take the current url then chk the page stay on current url.if page is not in the current url then destroy the session.
$url = "http" . ((!empty($_SERVER['HTTPS'])) ? "s" : "") . "://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
$page_name="abc.php";
if (!preg_match("/$page_name/",$url))
{
session_destroy();
}
But this code should be used on another pages.Because http is a stateless processes so no way to find when a user leave the page.
You can't tell when a user navigates away from the page, it's simply not possible in any reliable manner.
The best you can do is exploit how cookies work. When starting a session, you're sending a cookie to the client which identifies the client on each subsequent visit, and hence activates the associated session. It is up to the client to send this identification on subsequent visits, and it's up to the client to "forget" his identification.
You can instruct the client to only send the cookie for certain pages, and you can instruct him to forget the cookie when closing the browser (with a lifetime of 0). This can be set using session_set_cookie_params.
Other than that, you can simply ignore the session parameters on pages where they don't matter. You can delete the session (or certain values of it) after some time of inactivity when you assume the client has left.
Borealid deserves credit for pointing to the most elegant solution.
A more kludgey solution is to keep an iframe on the page that is pointed to another "monitor" page which is set to refresh every few seconds. This can be done without JavaScript using:
<meta http-equiv="refresh" content="10">
This refreshes the monitor page every 10 seconds. When this happens, the monitor page can record the time (overwriting the previously recorded time) and session ID on the server somewhere (DB or file).
Then you would have to create a cronjob that checks the file/DB for any sessions that are more than 10~12 seconds old and delete them manually. The session data is usually stored in a directory (specified by your PHP config) in a file named sess_the-session-ID. You could use a PHP function like this:
function delete_session($sessId) {
$sessionPath = session_save_path();
// you'll want to change the directory separator if it's a windows server
$sessFile = "$sessionPath/sess_$sessId";
if (file_exists($sessFile) && unlink($sessFile)) return true;
return false;
}