Как изменить тайм-аут сеанса в PHP?

Я хотел бы увеличить тайм-аут сеанса в php

Я знаю, что это можно сделать, изменив файл php.ini. Но у меня нет доступа к нему.

Так можно ли это сделать только с php-кодом?

Ответ 1

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

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

Удобство в расслабленной среде: как и почему

Если ваши сеансы реализованы с помощью куки файлов (они, вероятно, есть), а , если, клиенты не вредны, вы можете установить верхнюю границу продолжительности сеанса на настройка определенных параметров. Если вы используете обработку сеанса PHP по умолчанию с помощью файлов cookie, настройка session.gc_maxlifetime вместе с session_set_cookie_params должна работать для вас вот так:

// server should keep session data for AT LEAST 1 hour
ini_set('session.gc_maxlifetime', 3600);

// each client should remember their session id for EXACTLY 1 hour
session_set_cookie_params(3600);

session_start(); // ready to go!

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

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

    GC - это потенциально дорогостоящий процесс, поэтому, как правило, вероятность довольно мала или даже равна нулю (веб-сайт, получающий огромное количество обращений, вероятно, полностью откажется от вероятностного GC и планирует, чтобы это происходило в фоновом режиме каждые X минут). В обоих случаях (при условии отсутствия сотрудничающих клиентов) нижняя граница для эффективного времени жизни сеанса будет session.gc_maxlifetime, но верхняя граница будет непредсказуемой.

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

Уверенность в критических средах

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

Сделайте это, сохранив верхнюю границу вместе с остальными данными сеанса:

session_start(); // ready to go!

$now = time();
if (isset($_SESSION['discard_after']) && $now > $_SESSION['discard_after']) {
    // this session has worn out its welcome; kill it and start a brand new one
    session_unset();
    session_destroy();
    session_start();
}

// either new or old, it should live at most for another hour
$_SESSION['discard_after'] = $now + 3600;

Постоянство идентификатора сеанса

До сих пор мы не интересовались точными значениями каждого идентификатора сеанса, только с требованием, чтобы данные существовали до тех пор, пока они нам нужны. Имейте в виду, что в (маловероятном) случае, что для вас важны сеансы, необходимо позаботиться о необходимости их регенерации при session_regenerate_id.

Ответ 2

Если вы используете обработку сеансов PHP по умолчанию, единственный способ надежно изменить продолжительность сеанса на всех платформах - это изменить php.ini. Это потому, что на некоторых платформах сборка мусора реализуется через скрипт, который запускается каждый определенный момент времени (скрипт cron), который читает непосредственно из php.ini, и, следовательно, любые попытки изменить его во время выполнения, например, через ini_set() ненадежны и, скорее всего, не будут работать.

Например, в системах Debian Linux внутренняя сборка мусора PHP отключена путем установки в конфигурации значения session.gc_probability=0 по умолчанию, а вместо этого выполняется через /etc/cron.d/php, который работает в XX: 09 и XX: 39 ( то есть каждые полчаса). Это задание cron ищет сеансы старше session.gc_maxlifetime, указанного в конфигурации, и, если они найдены, они удаляются. Как следствие, в этих системах ini_set('session.gc_maxlifetime', ...) игнорируется. Это также объясняет, почему в этом вопросе: время сессий PHP слишком быстро, у OP были проблемы на одном хосте, но проблемы прекратились при переключении на другой хост.

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

Доступные альтернативные методы включают в себя:

  1. Установите другой обработчик сеанса (сохранения) в PHP, чтобы сохранить сеансы в другом каталоге или в базе данных, как указано в PHP: пользовательские обработчики сеансов (руководство PHP), чтобы задание cron не доходило до это, и только PHP внутренняя сборка мусора имеет место. Эта опция, вероятно, может использовать ini_set() для установки session.gc_maxlifetime, но я предпочитаю просто игнорировать параметр maxlifetime в моем обратном вызове gc() и самостоятельно определять максимальное время жизни.

  2. Полностью забудьте о внутренней обработке сессий PHP и реализуйте собственное управление сессиями. Этот метод имеет два основных недостатка: вам понадобятся ваши собственные глобальные переменные сеанса, поэтому вы потеряете преимущество суперглобального $_SESSION, и ему потребуется больше кода, таким образом, будет больше возможностей для ошибок и недостатков безопасности. Самое главное, идентификатор сеанса должен быть сгенерирован из криптографически безопасных случайных или псевдослучайных чисел, чтобы избежать предсказуемости идентификатора сеанса (приводящей к возможному угону сеанса), а это не так просто сделать с помощью переносимого PHP. Основным преимуществом является то, что он будет работать согласованно на всех платформах, и вы будете иметь полный контроль над кодом. Что подход принят, например, программным обеспечением форума phpBB (по крайней мере, версия 1; я не уверен насчет более свежих версий).

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

<?php
class FileSessionHandler
{

    private $savePath;
    private $lifetime;

    function open($savePath, $sessionName)
    {
        $this->savePath = 'my_savepath'; // Ignore savepath and use our own to keep it safe from automatic GC
        $this->lifetime = 3600; // 1 hour minimum session duration
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    function close()
    {
        return true;
    }

    function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $this->lifetime < time() && file_exists($file)) { // Use our own lifetime
                unlink($file);
            }
        }

        return true;
    }
}

$handler = new FileSessionHandler();
session_set_save_handler(
    array($handler, 'open'),
    array($handler, 'close'),
    array($handler, 'read'),
    array($handler, 'write'),
    array($handler, 'destroy'),
    array($handler, 'gc')
    );

// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');

session_set_cookie_params(3600); // Set session cookie duration to 1 hour
session_start();
// proceed to set and retrieve values by key from $_SESSION

Подход (2) является более сложным; По сути, вы должны самостоятельно реализовать все функции сеанса. Я не буду вдаваться в подробности здесь.

Ответ 3

Положите $_SESSION['login_time'] = time(); на предыдущую страницу аутентификации. И ниже приведены на каждой другой странице, где вы хотите проверить время ожидания сессии.

if(time() - $_SESSION['login_time'] >= 1800){
    session_destroy(); // destroy session.
    header("Location: logout.php");
    die(); // See https://thedailywtf.com/articles/WellIntentioned-Destruction
    //redirect if the page is inactive for 30 minutes
}
else {        
   $_SESSION['login_time'] = time();
   // update 'login_time' to the last time a page containing this code was accessed.
}

Редактировать: это работает, только если вы уже использовали твики в других сообщениях или отключили сборку мусора и хотите вручную проверить продолжительность сеанса. Не забудьте добавить die() после перенаправления, потому что некоторые скрипты/роботы могут его игнорировать. Кроме того, непосредственное уничтожение сеанса с помощью session_destroy() вместо того, чтобы полагаться на перенаправление, для этого может быть лучшим вариантом, опять же, в случае вредоносного клиента или робота.

Ответ 4

Добавление комментария для любого, у кого Plesk имеет проблемы с любым из вышеперечисленных, поскольку это сводило меня с ума, установка session.gc_maxlifetime из вашего PHP-скрипта не работает, поскольку у Plesk есть собственный скрипт сбора мусора, выполняемый cron.

Я использовал решение, размещенное по ссылке ниже, чтобы перемещать задание cron с почасового на ежедневный, чтобы избежать этой проблемы, тогда верхний ответ выше должен работать:

mv /etc/cron.hourly/plesk-php-cleanuper /etc/cron.daily/

https://websavers.ca/plesk-php-sessions-timing-earlier-expected

Ответ 5

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

Я сомневаюсь, что вам нужно продлить время сеанса. На данный момент у него довольно разумный тайм-аут, и нет причин его продлевать.

Ответ 6

Вы можете переопределить значения в php.ini из вашего PHP-кода, используя ini_set().

Ответ 7

Просто уведомление для сервера общего хостинга или добавлено на доменах =

Чтобы ваши настройки работали, у вас должен быть другой каталог сохранения сеанса для добавленного домена с помощью php_value session.save_path "folderA/sessionA".

Поэтому создайте папку на вашем корневом сервере, а не в public_html, и чтобы не было публичного доступа извне. Для моего cpanel/server нормально работали папки с разрешениями 0700. Дайте попробовать...

  • PHP-код =

     #Session timeout, 2628000 sec = 1 month, 604800 = 1 week, 57600 = 16 hours, 86400 = 1 day
     ini_set('session.save_path', '/home/server/.folderA_sessionsA');
     ini_set('session.gc_maxlifetime', 57600); 
     ini_set('session.cookie_lifetime', 57600);
     ini_set('session.cache_expire', 57600);
     ini_set('session.name', 'MyDomainA');
    

перед session_start();

или

  • .htaccess =

     php_value session.save_path /home/server/.folderA_sessionsA
     php_value session.gc_maxlifetime 57600
     php_value session.cookie_lifetime 57600
     php_value session.cache_expire 57600
     php_value session.name MyDomainA
    

После многих исследований и тестирования это работало нормально для общего сервера cpanel/php7. Большое спасибо: NoiS