PHP: как определить, закончился ли сеанс автоматически?
Когда определено время окончания сеанса, можно ли вызвать прослушиватель событий, когда он истекает?
Если это невозможно, можно ли запустить задание cron, чтобы проверить, закончился ли сеанс?
ПРИМЕЧАНИЕ. Меня интересует серверное решение. Я говорю о том, что определено время истечения сеанса, и сеанс заканчивается автоматически, потому что этот период истек.
Ответы
Ответ 1
можно ли вызвать слушателя событий по истечении срока его действия?
Короткий ответ: НЕТ
Есть несколько странностей, которые люди склонны игнорировать о сеансах. С обработчиком по умолчанию сеанс не истекает, когда заканчивается gc_maxlifetime
- это просто время, когда данные становятся доступными для автоматического удаления. Владелец сеанса не предпринимает никаких действий, который вызывает последующее удаление сеанса - это побочный эффект другой сессии.
Когда session_write_close()
вызывается (явно или неявно по завершению кода), если генератор случайных чисел, настроенный соответствующими настройками gc, набрасывает правильный номер, тогда PHP будет искать данные за его TTL и удалять его. Если вы хотите активировать действие в этой точке, вам нужно сломать обработчик по умолчанию и применить свой собственный. Это означает, что вы не только должны обеспечить механизм для выявления и удаления сеансов, но также и способ решить, должен ли ваш обработчик ударить и сколько сеансов он должен удалить, - вы не хотите, чтобы беглый процесс убивал ваш сервер.
В Ubuntu session.gc_probability = 0
, и это задание cron, которое выполняет функцию удаления устаревших файлов данных.
Причина очень важная часть информации, отсутствующая в вашем вопросе, является причиной удаления сеанса.
Если вы хотите, чтобы конфиденциальные данные не сохранялись в файловой системе, лучшим решением является шифрование данных с использованием ключа, хранящегося (только) в другом cookie стороне клиента. Таким образом, вы полностью исключаете хранение незащищенных данных на своем сервере. (обратите внимание, что в зашифрованных сеансах suhosin используется ключ, полученный из данных о клиенте и статический ключ, хранящийся на одном и том же хосте - это значительно менее безопасно, чем случайно сгенерированный ключ). Здесь я подготовил раньше.
Если вы просто хотите предотвратить доступ после gc_maxlifetime
срока действия gc_maxlifetime
, вам следует рассмотреть собственный обработчик сеанса, который рассматривает устаревший сеанс как отсутствующий. т.е. он не выходит из системы по истечении срока действия, но любые последующие запросы больше не могут быть связаны с сеансом. Уровень безопасности в примерах обработчика сеанса Stackable реализует такой элемент управления.
OTOH, если вы хотите использовать данные из сеанса в своем прослушивателе событий, то это другая история - вы, конечно, не сможете использовать ни Сухосин, ни мое шифрование данных. Но еще одно осложнение состоит в том, что формат (по умолчанию) для данных отличается от формата, используемого в других местах. Вам нужно использовать session_encode() и session_decode(). Первый будет читать данные только из массива $ _SESSION, поэтому прослушивание на сеансах требует некоторого тщательного подрывного действия session_id()
и session_start()
. session_decode()
однако, с радостью преобразует все, что вы бросаете на него.
В последних версиях PHP вы можете указать другую пару функций для сериализации/десериализации.
Крайне важно учитывать потенциальное влияние методов __wakeup()
при рассмотрении сборщика мусора сеанса, который будет считывать данные в файлах сеансов. В связи с этим необходимо, чтобы процесс, который обрабатывает такие сборки мусора, работает под тем же uid, что и исходный процесс PHP, который создал данные сеанса (в противном случае у вас есть привилегия эскалации бэкдора). Но если субстанция хранения сеанса основана на файлах, это должно быть так или иначе.
Существуют реализаторы десериализатора данных сеанса, написанные на языках, отличных от PHP, которые будут обеспечивать защиту от __wakeup()
(попробуйте Google), хотя это может быть излишним для решения проблемы, и они, вероятно, не активно поддерживаются. Если это вызывает беспокойство, более подходящим решением может быть использование сериализатора WDDX (xml) и использование обычного анализатора XML для чтения данных в вашем движке GC.
Если вы используете собственный обработчик для нормального чтения и записи данных, но хотите реализовать свой собственный сборщик мусора, тогда вам понадобится код для сопоставления session_id
с файловым путем. Если вы следуете ссылке, которую я передал вышеприведенным классам PHP, вы увидите чистую реализацию PHP нескольких обработчиков сеансов, включая те, которые совместимы с нативным обработчиком.
Но я настоятельно рекомендовал бы вам исчерпать все другие возможности для решения всех проблем, лежащих в основе проблемы, прежде чем выбирать чтение данных сеанса во время удаления.
Ответ 2
Похоже, вы хотите стереть сеанс в определенный момент времени на стороне сервера. То, что вы хотите сделать, это определить свой собственный обработчик сеанса и поместить данные сеанса в полностью контролируемую систему. Итак, скажем, вы перемещаете обработку сеанса в базу данных. Теперь все ваши данные сеанса полностью находятся под вашим контролем. Ниже приведен сокращенный пользовательский обработчик сеанса
class Sessions implements \SessionHandlerInterface {
/**
* Write Session Data
* @param string $id Session ID to delete
* @param string $data Data to write into the session
*/
public function write($id, $data) {
$time = time() + 3600; // 1 hour for the sake of example
$sql = 'REPLACE INTO your_session_table
SET session_id = ?,
data = ?,
expires = ?';
$this->db->query($sql);
$prep = $this->db->prepare($sql);
$prep->bind_param('ssi', $id, $data, $time);
$prep->execute();
}
}
Здесь вы можете запустить собственный скрипт очистки. Теперь я предлагаю вам использовать промежуточный магазин памяти (memcached, Redis и т.д.), Поэтому вы НЕ ДОЛЖНЫ загружаться из базы данных каждый раз. Вы захотите очистить это при запуске сценария очистки (т.е. Вывести все сеансы, срок действия которых истекает и удалить из кеша). Но простой оператор SQL здесь (выполняется, скажем, 5-минутное задание cron) очищает сеансы по требованию
DELETE FROM your_session_table
WHERE expires < now();
Ответ 3
Я делаю несколько предположений здесь.
Я предполагаю, что по какой-то причине вы хотите отслеживать просроченный сеанс холода, то есть никакого дополнительного отслеживания данных сеанса через базу данных или второго "скрытого" сеанса, который действует как структура, чтобы определить, когда псевдо - истек срок действия и действует надлежащим образом.
Я также предполагаю, что попытки взлома на вашем сеансе не важны на данный момент. Атаки "Человек-в-середине" и XSS могут захватывать идентификатор сеанса и подключать их к вашей системе, и это будет трудно обнаружить.
По умолчанию этот тип обрабатывается cookie сеанса в php. Я также предполагаю, что ваши идентификаторы сеанса и сеанс сеанса также обрабатываются с помощью файлов cookie.
Практически нет никакого способа сделать это "живым", т.е. Держать сокет открытым для сервера, чтобы определить момент окончания сеанса. PHP не был предназначен для работы таким образом; вопросы безопасности являются экспансивными. Кроме того, если вы разрешаете кому-либо удаленно получать доступ к вашему серверу через безопасный канал, почему вы беспокоитесь о сеансах в первую очередь?
$sessionCookie = 'myPHPSessCookieName';
$isSessionExpired = false;
if (isset($_COOKIE[$sessionCookie])) {
// check cookie expiry time to show warnings / near expiry behaviours
} else {
// handle missing cookie / session
$isSessionExpired = true;
}
define('SESSION_EXPIRED', $isSessionExpired);
session_start(['name' => $sessionCookie]);
Проверка для файла cookie должна произойти до начала сеанса, иначе вы рискуете дать себе ложный результат.
[edit: решение для javascript]
Если вы хотите создать поведение, имитирующее сокет, javascript может это сделать. Клиентский браузер будет проверять сервер с помощью запросов AJAX, чтобы проверить состояние их сеанса, и как только он обнаружит, что он истек, вы можете вызвать поведение по вашему выбору. Примечание: javascript в его текущем состоянии принципиально небезопасен. Все работы, связанные с данными и безопасностью, должны выполняться сервером, если это вообще возможно.
client.php:
<script>
$(function(){
var messageElem = $('#selectorForDisplayElementHere');
var timeoutID = null;
var checkSession = function(){
$
.ajax({/* your ajax params: url, data, dataType, method etc. */})
.then(function(response){
messageElem.html(response.html);
if (response.stop === 1) {
clearTimeout(timeoutID);
}
});
};
var timeoutID = setInterval(checkSession, 5000); // Every 5 seconds
});
</script>
ajax.php:
$response = ['html' => '', 'stop' => 0];
if (SESSION_EXPIRED) {
$response ['html'] = '<b>Your session has expired. Please log in again.</b>';
$response['stop'] = 1;
}
echo(json_encode($response));
Это очень простая система обработки, которая может быть легко улучшена с любой функциональностью. Он использует вездесущую библиотеку jQuery и стандартные функции php и html/javascript.
Ответ 4
Вы можете сохранить время соединения где-нибудь (таблица,...), чтобы вы могли видеть, с того момента, когда пользователь был подключен и выполнял регулярную проверку (cron или service), чтобы узнать, прошла ли дата определенной продолжительности (5 минут,...)
Но если вы хотите предупредить пользователя (потеря документа,...), вы можете захотеть сделать Javascript window.setTimeout
на стороне клиента.
Ответ 5
Задайте начальную сессию на одной странице.
пример: Login.php
<?php
session_start();
if(...){
// success
$_SESSION['logged_time'] = time();
}
?>
теперь проверяйте, что сеанс истек или нет на другой странице
пример: Index.php
<?php
session_start();
$login_session_duration = 60; // 1 minute
if($_SESSION['logged_time']){
if(((time() - $_SESSION['logged_time']) > $login_session_duration)){
echo 'session expired';
// session will be exired after 1 minutes
}else{
echo 'session alive';
}
}
?>
Ответ 6
Каждый раз, когда вы отправляете HTTP-запрос на сервер, проверяйте время истечения сеанса. если сеанс действителен, делайте свои вещи, другие мудрые перенаправления, где вы хотите.
Или
Вы можете сделать одно, чтобы сэкономить ваше время. Создайте метод проверки текущей сессии и вызовите его в своем HTTP-запросе.
Ответ 7
Вы также можете использовать это :)
<?
session_start();
$time = 3600; // Set expire time with secends.
// Star session here
if (isset($_SESSION['time']) && (time() - $_SESSION['time']) > $time) {
// Your Code Here to logout
header('location: /auth/logout');
exit();
} else {
$_SESSION['time'] = time();
}
Ответ 8
Я думаю, что вы можете найти здесь: Доступ к активным сеансам в PHP
Подведя итог, вы должны создать свой собственный обработчик сеанса. Это серверная сторона.
Если вы хотите добавить оповещения на стороне клиента, вы можете сохранить ограничение срока действия сеанса, используемое в таймере javascript. Если осталось только x минут, появится сообщение (возможно, с обратным отсчетом), отображаемое пользователю. "В вашей сессии будет время: (покажите таймер здесь)".
Ответ 9
Ну, очень простой способ сделать это
получить current_time
$current_time=time();
получить время истечения сеанса, установленное в ini файле.
$maxlifetime = ini_get("session.gc_maxlifetime");
Используйте это значение в javascript/query, и когда время истекает по манниальному расчету, используйте предупреждение, чтобы уведомить пользователя или написать сценарий, который вы хотите сделать.
ИЛИ
Вы можете сохранить эти даты в отдельной переменной cookie:
session_expire = 1525357483057
Но пользователь может изменить эту переменную.
Ответ 10
Попробуйте проверить его на session_cache_expire(), если он равен нулю, тогда ваша сессия закончилась. Вероятно, это должно быть реализовано в вашем обработчике действий. Это не устанавливает сеанс на сервере, а только решает проблему браузера ваших клиентов, зная, когда он истечет, что служит вашим автоматическим обнаружением...
http://php.net/manual/en/function.session-cache-expire.php
Ответ 11
Мы можем использовать переменную сеанса, которую вы определили.
if(isset($_SESSION['variable'])){
//do something
}
пример:
if(isset($_SESSION['name'])){
echo "Session has not expired";
}
Ответ 12
Что бы вы сделали, так это запустить запрос jQuery AJAX на временной интервал, чтобы проверить, истек ли сеанс, и когда вы можете отправить пользователей на выход.
Код Ajax
var checkSession;
function SessionCheck(){
var str="sessionCheck=true";
jQuery.ajax({
type:"POST",
URL:"sessionCheck.php"
data: str,
success: function(res){
if(res==1){
//do session expired logic here
}
}
});
}
sessions = setInterval(SessionCheck, 1000); //This will run the SessionCheck function every second
PHP-код
session_start();
$data = $_SESSION["sessionVariable"];
if($data == ''){
echo "1";
}
else{
echo "0";
}