Сессии PHP заканчиваются рано - PullRequest
7 голосов
/ 21 сентября 2011

У меня проблемы с сайтом PHP, который я запускаю на работе, где пользователи выходят из системы через несколько минут (точное время меняется, но достаточно часто, чтобы вызывать проблемы), независимо от того, были ли они активно используя сайт или нет.

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

Вещи, которые я уже проверил:

  • Попросить пользователей попробовать разные браузеры. Похоже, это не решает проблему и не является долгосрочным решением, так как я не могу определить, какие браузеры будут использовать клиенты.
  • Время сервера правильное и соответствует пользовательским машинам.
  • Пользователь Apache запускается с правами доступа для записи в папку сеанса, и я вижу, как создаются файлы сеанса и время их изменения обновляется.
  • Функции буферизации вывода не используются.
  • Проблема возникает на разных страницах, которые, похоже, не имеют ничего общего (т.е. дело не в том, что они все используют AJAX, или обновляют базу данных, или по какой-то другой причине).
  • Пользователи получают доступ к своей учетной записи только с одного компьютера, то есть они не выполняют небольшую работу на своем ноутбуке, переключаются на рабочий стол и затем задаются вопросом, почему они вышли из системы на своем ноутбуке (мы не разрешаем несколько одновременный вход в систему для одного и того же пользователя).

Настройки сеанса в PHP являются значениями по умолчанию Debian и не были изменены ни в файле .htaccess, ни где-либо еще. Основные из них:

session.cookie_lifetime    0
session.gc_divisor    100
session.gc_maxlifetime    1440
session.gc_probability    0
session.save_handler    files
session.save_path    /var/lib/php5
session.use_cookies    On

Debian удаляет сессии с помощью задания cron вместо использования сборщика мусора PHP, поэтому gc_probability имеет значение 0. Версия PHP, которую мы используем: PHP 5.2.6-1 + lenny13 с Suhosin-Patch 0.9.6.2 (cli) (последняя версия в Lenny, мы скоро перейдем на Squeeze, но я не думаю, что это является причиной проблемы).

Мы используем Zend_Session для управления сеансами, и экземпляр Zend_Session_Namespace создается один раз на каждой странице, таким образом автоматически вызывая session_start (). Сеансы очищаются путем вызова Zend_Session :: destroy () на странице выхода из системы, поэтому единственные способы выхода пользователя из системы:

  • Если они явно нажимают на ссылку выхода из системы (мы регистрируем, когда это происходит, и не похоже, что при просмотре страницы происходит предварительная загрузка страницы и, таким образом, вывод пользователя из системы).
  • Если они оставляют сеанс неактивным более чем на 24 минуты, в этот момент Debian, вероятно, удалит их сеанс (есть задание cron, которое выполняется каждые полчаса, удаляя все сеансы, которые не были изменены в течение более 24 минут).
  • Если они закроют браузер, их сеансовый cookie со временем истечения 0 будет удален.

Проверяет, вошел ли пользователь в систему:

  • У них есть действительный сеанс (проверяется, видим ли мы доступ к $ zsession-> user_id).
  • В таблице сеансов есть строка с совпадающим идентификатором пользователя и идентификатором сеанса, и последнее обновление было выполнено менее часа назад. Мы удаляем эту строку при выходе из системы, чтобы, даже если сеанс все еще существует на диске, никто не может получить доступ к этой учетной записи без входа в систему.

Кто-нибудь может предложить другие вещи, которые я могу попробовать?

Редактировать: некоторые дополнительные вещи, которые я пробовал на основе оставленных комментариев:

  • Установка session.cookie_domain: Это кажется очень странным поведением в PHP. Если я не установлю эту переменную и оставлю ее в качестве значения по умолчанию '' (пустая строка), то запрос на www.domain.com приведет к созданию файла cookie для www.domain.com. Однако, если я установлю cookie_domain на «www.domain.com», доменом для cookie будет «.www.domain.com» (обратите внимание на начальную точку, что означает действительный для всего, что ниже www.domain.com, например subsite.www .domain.com).
  • Установка session.cookie_lifetime: похоже, PHP не обновляет время истечения для каждого запроса, поэтому, если я установлю cookie_lifetime на 3600, cookie истекает через час после первого посещения сайта пользователем, даже если он входит в систему и постоянно использует его. .

Редактировать 2: На основании других вопросов, которые люди спрашивали:

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

Ответы [ 8 ]

3 голосов
/ 21 сентября 2011

Debian удаляет сессии через задание cron вместо использования сборщика мусора PHP

Это очень странно - а какой код выполняется в задании cron?

Мы удаляем эту строку при выходе из системы

Я предлагаю вам оставить это, скажем, на 2 дня после того, как сессия истекла / удалена (но пометить ее как мертвую в точке, где вы в данный момент удаляетеЭто).Кроме того, начните регистрировать идентификатор сеанса в журналах вашего веб-сервера.

1 голос
/ 29 ноября 2011

В итоге ответом было просто отказаться от сессий и написать свой собственный очень простой код cookie, который отличается от сессий следующими способами:

  1. Хранит хеш (бит как идентификатор сеанса) в базе данных, а не в файлах.
  2. Устанавливает срок действия файла cookie через 3600 секунд (обновляется на каждой странице) вместо 0 секунд (последние, похоже, вызывали проблемы у пользователей IE, хотя я никогда не мог их воспроизвести).
  3. Отправляет заголовок cookie только тогда, когда пользователь входит в систему или входит в систему.

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

1 голос
/ 26 сентября 2011

Существуют ли другие приложения php, работающие в той же системе (например, под разными vhosts?)?Сохраняют ли они также сессии в / var / lib / php5?

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

Я много занимаюсь разработкой ZF, и если я использую сеансы на основе файловой системы, я помещаю их в application / data / session вместо системных по умолчанию.

1 голос
/ 25 сентября 2011

Я думаю, вы рассчитываете изменить значение

session.gc_maxlifetime 

Я тоже столкнулся с той же проблемой.Я потратил на это много времени, затем спрашиваю своего провайдера веб-услуг, и когда он получил разрешение, он изменил эту вейл.Теперь работает нормально.

0 голосов
/ 30 сентября 2011

В конце я решил отправить заголовок Set-Cookie при каждом запросе страницы, аналогично тому, что FlyBy предложил в одном из комментариев. Соответствующий код / ​​логика теперь (при условии, что session_start () уже был вызван):

$this->session_name = session_name();
$update_cookie = isset($_COOKIE[$this->session_name]); // Check if cookie already set, as PHP will send the first Set-Cookie when the session is started
$this->logged_in = $this->checkSession(); // Function which checks whether a valid (i.e. not timed-out) session row exists in the DB
if ($this->logged_in) {
  $this->updateSession(); // Update the session row to the current time

  if ($update_cookie) {
    // Update the cookie expiry only if it existed before the login check
    setcookie($this->session_name, $_COOKIE[$this->session_name], $this->time + 3600, '/');
  }
}

Я не уверен, почему это сработало, но у меня больше не было жалоб, и количество входов в систему резко упало (больше нет нескольких входов в журнал для одного и того же пользователя в течение нескольких минут друг от друга). ).

Однако в какой-то момент я, вероятно, перепишу код, чтобы просто использовать строку базы данных и cookie на клиенте, потому что функциональность сеанса в PHP имеет так много переменных, что очень трудно понять, что является причиной проблемы, и обработка файлов cookie сеанса немного отличается от того, как обрабатываются обычные файлы cookie. В частности, вы должны быть осторожны с функцией setcookie, поскольку путь по умолчанию для файлов cookie сеанса, запускаемых PHP, - '/', но по умолчанию для setcookie - текущий путь к каталогу, и они не обязательно будут одинаковыми.

0 голосов
/ 21 сентября 2011

Вы можете попробовать установить session.use_only_cookies на значение 1 и session.cookie_lifetime на значение 1440 секунд.

0 голосов
/ 21 сентября 2011

ваше session.gc_maxlifetime установлено на 1440 мс, что составляет всего 1,44 секунды. не должно ли быть 1440000 мс = 24 минуты?

0 голосов
/ 21 сентября 2011

Ваш сайт находится на разных доменах? например domain.com, www.domain.com, subdomain.domain.com? если некоторые страницы перенаправляются в другой домен (www считается поддоменом, который отличается), сеансы не будут работать при изменении адреса

EDIT: Вы должны воспроизвести проблему. Спросите своих клиентов, какой браузер они используют, какие действия они выполняют, пока не выйдут из системы, просматривают ли они тот же ip для сайта, что и вы? (то есть вы оба во внешних сетях или оба в одной сети с сайтом)

Если вам удастся найти проблему, проверьте заголовки запроса / ответа, когда сеанс работает, а также когда он не работает, а затем сравните.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...