Как изменить время ожидания сеанса в PHP? - PullRequest
137 голосов
/ 29 ноября 2011

Я бы хотел увеличить время ожидания сеанса в php

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

Так возможно ли это сделать только с помощью php-кода?

Ответы [ 6 ]

292 голосов
/ 29 ноября 2011

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

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

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

Если ваши сеансы реализованы с помощью файлов cookie (которые они, вероятно, являются), а , если клиенты не являются вредоносными, вы можете установить верхнюю границу продолжительности сеанса, настроив определенные параметры.Если вы используете обработку сеансов 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 - потенциально дорогой процесс, поэтому обычно вероятностьдостаточно мал или даже равен нулю (веб-сайт, получающий огромное количество посещений, вероятно, полностью откажется от вероятностного сбора мусора и запланирует его выполнение в фоновом режиме каждые 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 при необходимости.

29 голосов
/ 02 сентября 2013

Если вы используете обработку сеансов 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() для увеличения времени жизни куки.

<?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 голосов
/ 21 июня 2018

Добавление комментариев для тех, кто использует 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

3 голосов
/ 15 октября 2017

Поместите $_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() вместо того, чтобы полагаться на перенаправление, для этого может быть лучшим вариантом, опять же, в случае вредоносного клиента или робота.

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

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

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

0 голосов
/ 29 ноября 2011

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

...