Я наткнулся на интересную проблему. На сайте, на котором я работаю, на данный момент есть три страницы: login.php и welcome.php и ajax.php. Все они называют session_start() в верхней части своего кода. Login.php проверяет переменные $ _SESSION [], чтобы убедиться, что кто-то вошел в систему; если нет, он получает свое имя/pwd, контакты ajax.php, чтобы проверить имя/pwd, и записывает их, установив соответствующие $ _SESSION [] vars. Welcome.php ищет подходящие $ _SESSION [] vars и отображает приветственное сообщение пользователю - если они не установлены, он просит пользователя войти в систему. Типичное поведение, и если оно используется обычным образом, оно отлично работает.PHP: session_start(), называемый «одновременно» на нескольких вкладках, создает несколько сеансов
Однако если вы заложите закладку login.php и welcome.php в виде набора вкладок (например, в Firefox), а затем откройте их как на одновременно, произойдет что-то странное. Возможно, потому что session_start() вызывается дважды в одно и то же время (проверяется с помощью error_log()), создаются два отдельных сеанса (проверяется с помощью session_id()). Какое бы значение session_start() не называлось «последним» (хотя такая же временная метка) является оставшимся сеансом. Это вызывает проблемы в следующем сценарии: login_php session_start() называется до Вызывается session_start() welcome.php.
В этой ситуации сеанс, созданный в файле login.php, продолжает существовать на этой странице, если он не обновляется. Однако, когда он связывается с ajax.php для проверки сведений о имени/pwd, а ajax.php вызывает session_start(), он извлекает сеанс, созданный welcome.php, который не имеет ничего в переменной $ _SESSION [], что делает все это потерпеть неудачу. Поэтому, если login.php сначала вызывает session_start(), мне нужно выяснить способ предотвратить получение session.start() welcome.php от создания нового. Примечание. Вызывающий порядок несовместим, и все явно работает нормально до тех пор, пока session_start() login.php вызывается последним (что я не могу контролировать).
В идеале, для второго файла было бы полезно заметить, что первый файл - в процессе создания сеанса, поэтому он не должен создавать свои собственные (но только для welcome.php).
Это ДОЛЖНО быть проблемой, с которой другие столкнулись, но я не смог найти никаких упоминаний об этом на этих межстранах. Любая помощь будет принята с благодарностью.
EDIT1: Вот файлы, необходимые для воспроизведения проблемы:
login.php
<?php
session_start();
error_log("login.php, session id: ".session_id());
$_SESSION['user'] = "EleventyOne"
?>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>multiple session bug - login</title>
<script src='jquery-1.9.1.js'></script>
<script>
$(document).ready(function() {
$.ajax({
url : 'ajax.php',
data : { 'func' : 'check_login' },
dataType : 'json',
type : 'GET',
timeout : 10000
})
.done(function(data,textStatus,jqXHR){
alert("Done: "+data.status);
})
.fail(function(jqXHR,textStatus,errorThrown) {
alert("Failed: " + textStatus + "(" + errorThrown + ")");
});
}); // end ready
</script>
</head>
<body>
</body>
</html>
WELCOME.PHP:
<?php
session_start();
error_log("welcome.php, session id: ".session_id());
$message = "";
if (isset($_SESSION['user'])) {
$message = "Hello, ".$_SESSION['user'];
}
else {
$message = "Please login!";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>multiple session bug - welcome</title>
</head>
<body>
<div>
<?php echo $message; ?>
</div>
</body>
</html>
ajax.php:
<?php
session_start();
error_log("ajax.php, session id: ".session_id());
// ignoring $_GET[] here, as superfluous to the point...
if (isset($_SESSION['user'])) {
// check the database for that user...
// ...
// return status
$ret['status'] = "ok";
echo json_encode($ret);
exit;
}
else {
// return failed status
$ret['status'] = "broken session";
echo json_encode($ret);
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>multiple session bug - ajax</title>
<script src='_js/jquery-1.9.1.js'></script>
<script>
$(document).ready(function() {
}); // end ready
</script>
</head>
<body>
</body>
</html>
При загрузке login.php, откройте новую вкладку и загрузить welcome.php, вот файл error_log вы получите (все в порядке):
[27-Jun-2013 18:39:40 UTC] login.php, session id: skofpr8g0tg81aqohnkahv3vk5
[27-Jun-2013 18:39:40 UTC] ajax.php, session id: skofpr8g0tg81aqohnkahv3vk5
[27-Jun-2013 18:39:44 UTC] welcome.php, session id: skofpr8g0tg81aqohnkahv3vk5
Если вы BookMark login.php и welcome.php как набор вкладок, закройте браузер, заново откройте его и одновременно откройте обе вкладки, вы получите один из двух файлов error_log, в зависимости от того, какой вызов session_start вызывается первым.
Этот файл работает, поскольку session_start() login.php сохраняется для ajax.php. Итак, аякс.PHP сообщает статус "КИ":
[27-Jun-2013 18:40:39 UTC] welcome.php, session id: 6q2q96lhhoaqqhj214gs3gos36
[27-Jun-2013 18:40:39 UTC] login.php, session id: j8eaa5mtfsla9q3q80qt03kvt7
[27-Jun-2013 18:40:39 UTC] ajax.php, session id: j8eaa5mtfsla9q3q80qt03kvt7
Это один не работает, так как session_start welcome.php (в) сохраняется ajax.php, так ajax.php сообщает "разбитая сессия":
[27-Jun-2013 18:40:18 UTC] login.php, session id: s4b7jo41jpg1ubbe8at7c5qr35
[27-Jun-2013 18:40:18 UTC] welcome.php, session id: freu86sn3edc3fuoc2pn875o90
[27-Jun-2013 18:40:18 UTC] ajax.php, session id: freu86sn3edc3fuoc2pn875o90
Зависит ли 'login.php' от предварительной загрузки хранилища сеансов и впоследствии не работает с более новым сеансом или мешает' welcome.php'? – mario
Извините, Марио, но я не понимаю, о чем вы спрашиваете. Login.php может продолжать использовать данные $ _SESSION [] без проблем, если он не обновляется. Однако каждая другая страница, вызывающая session_start(), получает сеанс, созданный welcome.php, а не login.php (при первом запуске session_start() login.php). – EleventyOne
Как проблема возникает в пользовательском интерфейсе? Разве 'login.php' не требует второго представления формы до фактической регистрации идентификатора пользователя? Потому что тогда это довольно неуместно, если он использует свой первоначальный сеанс или любой из последующих/более поздних идентификаторов сеанса. – mario