Почему PHP не сохраняет переменные сеанса для определенных пользователей в Internet Explorer?

У меня проблема с сайтом, на котором PHP не сохраняет переменные сеанса для определенных пользователей в Internet Explorer. Но для некоторых других пользователей с Internet Explorer проблем нет, и у пользователей с другими браузерами тоже нет никаких проблем.

Я создал следующие три небольших скрипта, чтобы убедиться, что на сайте не было другого кода:

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

Ожидаемый вывод для var_dump($_SESSION) будет примерно таким:

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

Однако выход для пользователей с проблемой заключается в следующем:

array(0) {
}

array(0) {
}

array(1) {
    ["count"] => int(1)
}

Это означает, что переменные сеанса не сохраняются для этих пользователей. Однако идентификатор сеанса для пользователей с проблемами одинаковый для всех трех тестовых страниц.

Кто-нибудь знает, что это может быть? Насколько я знаю, проблемный код работал несколько лет, и проблемы начали проявляться в последний месяц или около того.

Edit

Ответы на вопросы в комментариях:

  • Я не могу реплицировать проблему на локальной машине.
  • У меня есть сообщения о проблемах пользователей с IE7 и IE9. Но я не могу точно сказать, что проблем с другими версиями нет, потому что может быть, что они просто не сообщаются.
  • В браузере пользователя с этой проблемой не отключены файлы cookie, cookie PHPSESSID отправляется на сервер.
  • В имени машины нет - или _ (qaru.site/info/360503/...).
  • Восстановление идентификатора сеанса с помощью session_regenerate_id() не влияет на результат для пользователей с проблемой.
  • Настройки часового пояса и времени для пользователя с такой же проблемой, как на сервере.

Изменить 2

Как указано @nl-x в комментарии, данные сохраняются во втором запросе. Поэтому я адаптировал тестовый сценарий и добавил еще один шаг, чтобы увидеть, работает ли сеанс в последующих запросах. И это так. Данные сеанса, установленные в step2.php и step3.php, сохраняются между запросами.

Итак, теперь возникает вопрос, почему данные сеанса для первого запроса теряются, а не для последующих запросов?

Ответ 1

Я понял, что у пользователей, у которых были все проблемы, установлен Chrome Frame. Я проверил это, установив Chrome Frame на локальном компьютере, и в этом случае я смог реплицировать проблемы.

Проблемы были вызваны тем, что на нашем сервере установлен Suhosin. Были активированы следующие настройки Suhosin:

suhosin.session.cryptua
suhosin.cookie.cryptua

Это означает, что строка User Agent также является частью идентификации пользовательского сеанса. Обычно это не проблема, но для пользователей с установленным фреймом Chrome строка User Agent отличается от первого запроса и последующих запросов. После отключения этих настроек Suhosin проблем больше не было.

Ответ 2

Я установлю это, вместо того, чтобы ждать кого-то, у кого есть определенные знания механизма сеанса PHP:

Я работаю в основном с ASP.NET, а объект Session использует файл cookie для сохранения данных по запросам. Если PHP работает одинаково, наиболее очевидный вывод состоит в том, что пользователи с проблемами сеанса либо отключили cookies, либо используют программное обеспечение, которое разрешает домены whitelisted устанавливать файлы cookie. Я посмотрю, смогу ли я найти какие-либо факты, чтобы поддержать эту теорию...

Из руководства PHP (http://www.php.net/manual/en/intro.session.php):

Это либо сохраняется в cookie на стороне пользователя, либо распространяется в URL.

Ответ 3

Я не могу точно сказать, почему в/после первого запроса, файл cookie, кажется, затерялся. (Это то, что, как я думаю, происходит.) И почему второй/второй запрос не теряется.

Возможно, проблема кэширования. Проверьте инструменты разработчика и посмотрите, что именно происходит на вкладке сети. Первый запрос поступает с 200-OK, и отвечает ли ответ на заголовок файла cookie? Или это действительно кэшируется, как сказал один из комментариев?

Но в конце вы должны фактически выполнить правильный идентификатор сеанса (прочитайте его). Это предназначено для людей, которые не хотят или не могут обрабатывать файлы cookie.

В основном это означает изменение:

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

в

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

или

enable --enable-trans-sid

Теперь, когда PHP-уведомления о сеансах не передаются куки файлами, он будет передавать их менее безопасным образом в URL-адресе. Особенно в этом случае вам понадобится session_regenerate_id().

изменить Ой, да, я хотел упомянуть об этом раньше, но потом подумал, что это не может быть так. Но, во-вторых, я все равно буду упоминать об этом!

По умолчанию используются файлы cookie. Если пользователь переходит к http://yourdomain.com (без www.), а второй запрос переходит к http://www.yourdomain.com, cookie не сможет пережить изменение домена! Таким образом влияет на вашу сессию.

Чтобы исправить это, либо установите домен cookie сеанса, либо всегда используйте тот же домен (с или без www.)

Ответ 4

Прежде всего, вы должны проверить конфигурацию сеанса php.ini, особенно продолжительность файла cookie. Добавьте раздел к вашему вопросу. Установите Fiddler на клиента, который дает вам сообщение об ошибке и выдает полный откат дат сеанса. Это должно помочь вам легко найти проблему.