Why does PHP not save session variables for specif

2020-06-03 04:52发布

问题:

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;
?>
<a href="test2.php">Next</a>

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']++;
?>
<a href="test3.php">Next</a>

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?

回答1:

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.



回答2:

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.



回答3:

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:

<a href="test3.php">Next</a>

into:

<a href="test3.php?<?php echo htmlspecialchars(SID); ?>">Next</a>

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



回答4:

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.