У меня проблема с сайтом, где 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("dmY, 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("dmY, 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("dmY, 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) }
Это означает, что переменные сеанса не сохраняются для этих пользователей. Однако идентификатор сеанса для пользователей с проблемами одинаковый для всех трех тестовых страниц.
Кто-нибудь знает, что это может быть? Насколько я знаю, проблемный код проработал несколько лет, и проблемы начали проявляться за последний месяц или около того.
редактировать
Ответы на вопросы в комментариях:
Изменить 2
Как указано в комментарии @ nl-x, данные сохраняются во втором запросе. Поэтому я адаптировал тестовый сценарий и добавил еще один шаг, чтобы увидеть, работает ли сеанс в последующих запросах. И это так. Данные сеанса, установленные в step2.php
и step3.php
, сохраняются между запросами.
Итак, теперь возникает вопрос, почему данные сеанса для первого запроса теряются, а не для последующих запросов?
Я понял, что у пользователей, у которых были проблемы, установлен Chrome Frame. Я проверил это, установив Chrome Frame на локальный компьютер, и в этом случае я смог реплицировать проблемы.
Проблемы были вызваны тем, что на нашем сервере установлен Suhosin. Были активированы следующие настройки Suhosin:
suhosin.session.cryptua suhosin.cookie.cryptua
Это означает, что строка User Agent также является частью идентификации сеанса пользователя. Обычно это не проблема, но для пользователей с установленным фреймом Chrome строка User Agent отличается от первого запроса и последующих запросов. После отключения этих настроек Suhosin проблем больше не было.
Я полагаю это, вместо того, чтобы ждать кого-то, обладающего особыми знаниями механизма сессии PHP:
Я работаю в основном с ASP.NET, а объект Session
использует cookie для хранения данных по запросам. Если PHP работает одинаково, наиболее очевидный вывод состоит в том, что пользователи с проблемами сеанса либо отключили cookies, либо используют программное обеспечение, которое разрешает домены whitelisted устанавливать файлы cookie. Я посмотрю, смогу ли я найти какие-либо факты, чтобы поддержать эту теорию …
Из руководства по PHP ( http://www.php.net/manual/en/intro.session.php ):
Это либо сохраняется в файле cookie на стороне пользователя, либо распространяется в URL-адресе.
Я не могу точно сказать, почему в первый раз, после первого запроса, cookie, кажется, заблудился. (Это то, что, как я думаю, происходит.) И почему второй / второй запрос НЕ пропадает.
Возможно, проблема кеширования. Проверьте инструменты разработчика и посмотрите, что именно происходит на вкладке сети. Первый запрос поступает с 200-OK, и отвечает ли ответ на заголовок файла cookie? Или это действительно кэшировано, как сказал один из комментариев?
Но в конце вы должны фактически реализовать правильную передачу идентификатора сеанса (прочитайте его). Это предназначено для людей, которые не хотят или не могут обрабатывать файлы cookie.
В основном это означает изменение:
<a href="test3.php">Next</a>
в:
<a href="test3.php?<?php echo htmlspecialchars(SID); ?>">Next</a>
или:
включение –enable-trans-sid
Теперь, когда PHP-уведомления о сеансах не передаются с помощью файлов cookie, он будет передавать их менее безопасным образом в URL-адресе. Особенно в этом случае вам понадобится session_regenerate_id()
.
edit: Ой, да, я хотел упомянуть об этом раньше, но потом подумал, что это не может быть. Но, во-вторых, я все равно буду упоминать об этом! :
По умолчанию файлы cookie являются доменными. Если пользователь перейдет на сайт http://yourdomain.com (без www. ), А второй запрос будет отправлен на http://www.yourdomain.com , cookie не передержит изменение домена! Таким образом, влияет на вашу сессию.
Чтобы исправить это, либо настройте домен cookie сеанса, либо всегда используйте тот же домен (либо с www, либо без него).
Прежде всего, вы должны проверить конфигурацию сеанса php.ini, особенно продолжительность файла cookie. Добавьте раздел к вашему вопросу. Установите Fiddler на клиента, который дает вам сообщение об ошибке и выдает полный откат дат сеанса. Это должно помочь вам легко найти проблему.