PHP Session not being saved - php

I have a rather strange problem; there are three pages which are using this cookie - one sets $_SESSION = 0 (as another Stack article suggested my issue might be related to PHP having difficulties with timings so 'pre-creating' the session, then writing to it might help), another file starts the session, changes the session cookie to an array with some useful data in it and supposedly saves it. Only, in this file the session will never actually get written to disk... On the third page, I will try and access the cookie and get an output of '0' (first page).
I've spent a lot of time debugging this and have checked:
That session_start and session_write_close are being used appropriately.
That PHP.ini is set up correctly, with a writable storage path (/tmp)
That PHP is actually using this storage path!
And I've also sat there comparing cookie ID's in browser and on the server to work out when sessions are and are not being created.
I don't see an issue in my code, and as other pages are able to use the session correctly (pages 1 and 3), it is only page 2 which is having an issue.
This is my debugging output from page two, showing the array I tried to write plus the fact that PHP doesn't seem to know what the session ID is, but there are no errors when I call session_start?
bool(true)
session id:
session file: /tmp/sess_ does not existarray(3) {
["user"]=>
string(5) "kevin"
["time"]=>
int(1472646292)
["ip"]=>
string(13) "178.62.20.247"
}
array(1) {
["oscar"]=>
string(26) "9h8c8fgkscitc7l3m7t18f37u2"
}
And the pertinant code from page two:
<?php
//error reporting
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
//session starts
session_name("oscar");
var_dump(session_start());
session_regenerate_id();
if (! is_writable(session_save_path())) { throw new \Exception( session_save_path() . ' NOT WRITABLE!'); }
$_SESSION['user'] = $_POST['username'];
$_SESSION['time'] = time();
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
echo '<pre>';
echo 'session id: ', session_id(), "\n";
$sessionfile = ini_get('session.save_path') . '/' . 'sess_'.session_id();
echo 'session file: ', $sessionfile, ' ';
if ( file_exists($sessionfile) ) {
echo 'size: ', filesize($sessionfile), "\n";
echo '# ', file_get_contents($sessionfile), ' #';
}
else {
echo ' does not exist';
}
var_dump($_SESSION);
var_dump($_COOKIE);
echo "</pre>\n";
session_write_close();
exit();
?>
The output of var_dump(session_start()); is
bool(true)
And if you refresh the page, the output of $_COOKIE changes (as the session ID is changed).
Thank you for any help - I hope I'm not being stupid. I've made a lot of effort debugging this.
EDIT:
This now appears to be an issue with where scripts are in the filesystem.
All the files are loaded through one index.php - the ones that don't update sessions (don't work) are located in api/filename.php, whilst, ones that do work are located in ../server/includes/admin/filename.php. (Nb. those paths are relative to index.php)
System: Ubuntu Server 16.04 PHP7 Apache2

Many thanks to Ryan Vincent who helped solve this over chat.
It stems from the way the actual scripts were loaded - using relative paths from a file higher up the directory. Unfortunately, this caused PHP some issues but didn't generate any errors. By transitioning to absolute paths: DIR . api/filename.php we managed to fix the problem.

session_start();
Should be at the top of the script and it should be on top of every page where session variables are used if the included files on top does not contain session_start().

Related

PHP Session Suddenly Stopped Working For Some Pages

I've bumped into a strange glitch. I had no problems before but now suddenly the PHP session will only work for some pages but not others.
Here is how I use the session:
ini_set('session.save_path', realpath(dirname($_SERVER['DOCUMENT_ROOT']) . '/../session'));
session_start();
if(!isset($_SESSION["account"])) {
// session does not exist
echo "<h1>session does not exist</h1>";
} else {
echo "<h1>session exists</h1>";
}
The same code does not longer work for some pages. For example I'm able to login just fine and use most of the tools for login. But when I created a new file testSession.php with the same content as shown above. It has lost the session for some reason.
I specifically used ini_set('session.save_path', realpath(dirname($_SERVER['DOCUMENT_ROOT']) . '/../session')); to solve a simmilar problem but now the problem is back... why?
The strange thing about all of this is that the one php script I wanted to trigger has worked before without a problem. What could be the issue here? Why does it suddnely not work for some pages/script, as far as I can tell I've never touched that part of the code, so I didn't even change anything.
I suggest to make a session.php file that you call in every page you need to access to sessions like:
session.php
ini_set('session.use_only_cookies', 1); // secure cookie
session_set_cookie_params(0,'/','localhost',true,true); // duration, path, domain, secure connection, httponly (secure js access)
session_start(); // start session
session_regenerate_id(); // regenerating for security issues
and then include this to your pages:
include 'session.php';
if(!isset($_SESSION["account"])) {
echo "<h1>session does not exist</h1>";
} else {
echo "<h1>session exists</h1>";
}
Make sure that u start session on every page. If you have it dynamicly, make sure that your require 'xxx'; is right. Then try deleting you phpsessionid in webdevelopment tools in chrome. At last, restart your local server - wamp, xampp etc.

How to find out that session has expired in PHP?

I'm trying to improve the session management for web applications. My major issue is the session expiration and how to deal with it. For that I'd like to find out if the session is still available or not. I'm using the default file based sessions (PHP 7.1, Apache 2.4, Fedora/RHEL) and it is cookie based.
What I've found out is that the session GC gets executed when session_start() is called. It is not with the begin or end of the script execution, it happens with this function. What seems odd to me is that if session_start() and the GC consider the session as expired and want to delete the corresponding session file, $_SESSION gets populated regularly first, then the file will be deleted. That's surprising.
With that behaviour only the next following request leads to an empty $_SESSION. I would expect this with the call before - the one that deletes the file. So if I'd like to know whether the session has expired in the current request I would have to check if the session file still exists after the session_start() call. That seems strange to me.
Are there any other or better ways to check that a session has expired than looking into the file system?
I thought I could just check if $_SESSION is empty to determine that the session was renewed - but that is obviously not possible.
Update: I've found the following bug reports dealing with the issue: this and that. There's also a SO entry about the expiration problem. Current PHP source: php_session_start calls php_session_initialize calls php_session_gc.
You may want to play with this script (unreal settings are just for testing purposes):
ini_set('session.gc_maxlifetime', 2); // Session gets expired after 2 seconds
ini_set('session.gc_divisor', 1); // Delete expired session files immediately
ini_set('session.save_path', '/some/safe/path/for/testing'); // Must be accessible for the server
//ini_set('session.use_strict_mode', true); // Uncomment if the id should be renewed, what makes no difference here
echo "Session files before session_start call<br>";
listSessionFiles();
session_start();
echo "Session files after session_start call<br>";
listSessionFiles();
echo "<hr>";
echo "Session id: " . session_id() . "<br>";
echo "Session content: " . print_r($_SESSION, true);
$_SESSION['x'] = time(); // Populate the session with something
function listSessionFiles() {
echo "<ul>";
$none = true;
$dir = dir(ini_get('session.save_path'));
while ($entry = $dir->read()) {
if (preg_match('/^sess_/', $entry)) {
echo "<li>" . $entry . "</li>";
$none = false;
}
}
$dir->close();
if ($none) echo "<li>None</li>";
echo "</ul>";
}
Just reload the page some times. Wait at least more than two seconds. Otherwise the session does not expire.
One way to circumvent the problem is to use cookies with a certain lifetime (below the session lifetime). If the cookie expires it won't be sent to the server. PHP will then create a new session when session_start() is called, so $_SESSION will be empty.
This might be enough to find out that the session is not available. Although one cannot distinguish in PHP if the session has expired or anything went wrong. You can just tell that no session data is available and do appropiate things then (amongst other also destroy the newly created empty session).

PHP session variable set on page (verified) does not exist after redirect or page change

PHP 7.1.7 on Windows Server 2008 Enterprise
... I noticed there were 5 other questions here just like this with no answer. I'm getting frustrated trying to do something that's always been so easy to accomplish in other languages for me. I just want to set a session variable and then read it on another page after a redirect. That should be simple basic functionality and I do not get why I've been sitting here for 2 hours trying everything I can think of and I still can't figure it out.
Each page of my application starts with: session_start();
I have a form edit processing page I'm starting with, where on a successful edit, the user is redirected back to the index page. Before the redirect, I'm setting a session variable ('success'). At this point, the session variable is set. If I comment out the header and exit() lines and echo the session["success"] variable.
$_SESSION["success"] = "The record was inserted successfully.";
header( 'Location: index.php');
exit();
}
Register Globals does not exist in my PHP.ini file (register_globals). I tried adding "register_globals=0;" to the PHP.ini file and restarting the server but I still doid not see a "register_globals" listing on the PHP info page.
No matter what I have tried, after the redirect to the index.php page, that session variable does not exist after the redirect ($_SESSION["success"]). I'm staying inside the same domain (same folder on the server really)
After setting the session variable ('success') and proving that it is set by echoing it on the edit proccessing page followed by an exit, I can not figure out how to get the session variable to persist after a redirect or page change:
If I try and echo that 'success' session variable after a redirect, I get this:
Notice: Undefined index: success
I'm not understanding why this is so difficult? What else could I try?
Thanks for any help.
Test whether the session cookie is set properly.
$_SESSION["success"] = "The record was inserted successfully.";
// header( 'Location: index.php');
echo session_name() .': '.session_id(); // print session cookie name & value
echo '<pre>' . print_r(session_get_cookie_params() ) . '</pre>';
exit();
What do you see? Open your browser's dev tools and look at cookies set when the server echoes the info above. If there is no cookie with the name (typically PHPSESSID) and session ID value above, then either your browser is not accepting cookies or the server isn't setting them. Either one will break cookie-based sessions.
If these seem to work ok, then re-establish your redirect. On the next page (index.php in your example), take a look at which cookies are received:
// Notice: this won't work on the page setting the cookie.
// Cookie should show up on the next page
echo '<pre>' . print_r($_COOKIE) . '</pre>';
Does the session id cookie exist?
If all this works, I would then look at whether PHP is actually storing session files properly. Session data is serialized and saved to files in a folder on the server's hard drive. Take a look at your php.ini, where you should see something like:
session.save_handler = files
session.use_cookies = 1
; where on server the files should be stored. the folder should be
; readable/writeable to the PHP process. Maybe '/tmp'?
session.save_path =
If you edit your php.ini, remember to restart the server.
Update
From your comments, everything seems to be setup correctly. Remove all other code. and just have this:
page1.php
<?php
session_start();
$_SESSION = []; //start with an empty array
$_SESSION['success']= 'record saved';
$_SESSION['id'] = session_id();
header('Location: index.php');
exit;
index.php
<?php
session_start();
var_dump($_SESSION);
if(isset($_SESSION, $_SESSION['id'])):
echo 'Session ids ' . ($_SESSION['id']===session_id()? 'match' : 'do not match');
endif;
What gets var-dumped in index.php after you get redirected from page1.php?

Why does PHP not save session variables for specific users with Internet Explorer?

I have a problem with a website where PHP does not save session variables for specific users with Internet Explorer. But for some other users with Internet Explorer there is no problem at all, and users with other browsers also do not have any problems.
I created the following three small scripts to make sure no other code in the website was involved:
test.php:
<?php
session_start();
function logMsg($text) {
$filename = dirname(__FILE__) . "/test.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("d-m-Y, H:i")." - $text\n") or die("Could not write file!");
fclose($fh);
}
ob_start();
var_dump(session_id(), $_SESSION, $_SERVER, $_REQUEST);
$content = ob_get_clean();
logMsg("test.php");
logMsg($content);
$_SESSION['test'] = array('test' => 'lalala');
$_SESSION['count'] = 1;
?>
Next
test2.php:
<?php
session_start();
function logMsg($text) {
$filename = dirname(__FILE__) . "/test.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("d-m-Y, H:i")." - $text\n") or die("Could not write file!");
fclose($fh);
}
ob_start();
var_dump(session_id(), $_SESSION, $_SERVER, $_REQUEST);
$content = ob_get_clean();
logMsg("test2.php");
logMsg($content);
$_SESSION['count']++;
?>
Next
test3.php:
<?php
session_start();
function logMsg($text) {
$filename = dirname(__FILE__) . "/test.log";
$fh = fopen($filename, "a") or die("Could not open log file.");
fwrite($fh, date("d-m-Y, H:i")." - $text\n") or die("Could not write file!");
fclose($fh);
}
ob_start();
var_dump(session_id(), $_SESSION, $_SERVER, $_REQUEST);
$content = ob_get_clean();
logMsg("test3.php");
logMsg($content);
The expected output for the var_dump($_SESSION) would be something like:
array(0) {
}
array(2) {
["test"] => array(1) {
["test"] => string(6) "lalala"
},
["count"] => int(1)
}
array(2) {
["test"] => array(1) {
["test"] => string(6) "lalala"
},
["count"] => int(2)
}
However, the output for the users with the problem is the following:
array(0) {
}
array(0) {
}
array(1) {
["count"] => int(1)
}
This means that the session variables are not stored for these users. However, the session ID for the users with problems is the same for all 3 test pages.
Does somebody have any idea what this could be? As far as I know the problematic code has worked for several years and the problems started showing in the last month or so.
Edit
Answers to questions in the comments:
I cannot replicate the problem on a local machine.
I have reports of problems from users with IE7 and IE9. But I cannot say for certain that there are no problems with the other versions, because it could be that these are simply not reported yet.
The browser of a user with the problem does not have cookies disabled, the PHPSESSID cookie is sent to the server.
There are no - or _ in the machine name (https://stackoverflow.com/a/306601/534109).
Regenerating the session id with session_regenerate_id() has no influence on the result for the users with the problem.
Timezone and time settings for a user with the problem are the same as on the server.
Edit 2
As stated by #nl-x in a comment the data gets stored in the second request. So I adapted the test scenario and added another step to see if the sessions works in subsequent requests. And this is the case. Session data set in step2.php and step3.php are saved between requests.
So now the question is why does session data for the first request get lost and not for subsequent requests?
I figured out that the users that were having the problems all had Chrome Frame installed. I verified this by installing Chrome Frame on a local machine, and in this case I was able to replicate the problems.
The problems were caused by the fact that our server has Suhosin installed. The following Suhosin settings were enabled:
suhosin.session.cryptua
suhosin.cookie.cryptua
This means that the User Agent string is also a part of the identification of a user's session. Normally this is not a problem, but for users with the Chrome frame installed the User Agent string differs between the first request and the subsequent requests. After disabling these Suhosin settings there were no more problems.
I will posit this, in lieu of waiting for someone with specific knowledge of PHP's session mechanism:
I work mostly with ASP.NET, and the Session object uses a cookie to persist data across requests. If PHP works the same way, the most obvious conclusion is that the users with session issues either have cookies disabled or are using software that only allows whitelisted domains to set cookies. I will see if I can find any facts to back this theory up...
From the PHP manual (http://www.php.net/manual/en/intro.session.php):
This is either stored in a cookie on the user side or is propagated in
the URL.
I can't exactly tell you why on/after the first request, the cookie seems to get lost. (That is what I guess is going on.) And why on/after the second request is does NOT get lost.
Perhaps indeed a caching issue. Check the Developer tools, and look at what exactly is going on in the network tab. Is the first request coming in with a 200 - OK, and does the response contain a cookie header? Or is it indeed cached, as one of the comments suggested?
But in the end you should actually implement correct session id passing (read it). This is meant for people who dont want or can't handle cookies.
Basicly it means changing:
Next
into:
Next
or:
enabling --enable-trans-sid
Now when PHP notices sessions are not passed by cookies, it will give them along in a less secure way, in the URL. Especially in this case you would need session_regenerate_id().
edit:
Ow yeah, I wanted to mention it earlier, but then thought it couldn't be it. But on second thought I will still mention it! :
Cookies are domain specific by default. If the user goes to http://yourdomain.com (without www.) , and the second request goes to http://www.yourdomain.com , the cookie will not survive the domain change! Thus affecting your session.
To fix this, either set the session cookie domain, or always use the same domain (either with, or without www.)
First of all, you should verify your php.ini session configuration, especially cookie duration. Add section to your question.
Install Fiddler on a client which is giving you the error and produce a full http dump of the session. This should be help you to track down the problem easily.

PHP: session_cookie over subdomains?

I'm rather new to PHP and sessions.
I've actually never worked with them before and I'm having quite a few problems working with them with AJAX over a subdomain.
I'm on http://www.example.com/whatever and I'm setting the cookie with:
session_set_cookie_params(0, '/', '.example.com');
session_start();
if(!isset($_SESSION['password']) ) {
$_SESSION['password'] = $_POST['password'];
}
var_dump(ini_get_all('session')); //seems like it doesn't save the cookie???
Then I'm using jQuery (load()) to reload a certain part of the page. I'm loading somefile.php from http://subdomain.example.com/subdomain/somefile.php. I want to retrieve the session information inside this somefile.php. I'm using
var_dump(ini_get_all('session')); //can't find the cookie!??
if(isset($_SESSION['password']) ) {
$user_pass = $_SESSION['password'];
echo "Password: " . $user_pass . "<br>";
} else {
print "can't find cookie!";
}
But I can't get the information! Any idea what I could have done wrong? Did I miss anything?
If the subdomain is run on a different server then... the session simply isn't there! This is because session data is by default saved somewhere in /tmp.
If you want to share session data across multiple servers, you'll need to write your own session handler and save them, for example, in a database.
Session_set_save_handler()
Even within the structure of the relevant RFCs getting cookies to work across sub-domians is far from trivial. Add to that the complication of the variation in different implementations by different browser suppliers - it's just not worth the hassle.
Use SSO instead. This has been discussed many times on Stack Overflow
C.

Categories