Как изменить время ожидания сеанса в PHP?


154

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

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

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



1
Связано, это в php.ini, но я думаю, что вы можете использовать ini_set, как @matino сказал stackoverflow.com/questions/520237/…
J-Rou

Ответы:


324

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


Вопрос: если позвонить так, скажем, каждую минуту, увеличит ли он свой лимит? Например, в 10:00 я назвал его так, чтобы его лимит был 11:00, а через 1 минуту, 10:01, лимит будет 11:01?
oneofakind

@oneofakind: Если вы звоните, что именно?
Jon

1
Эти из них: ini_set ('session.gc_maxlifetime', 3600); session_set_cookie_params (3600);
oneofakind

@oneofakind: Да, но только если вы также вызываете session_start()(в противном случае ничего не происходит) и только если вы всегда вызываете эти два раньше session_start(в противном случае gc_maxlifetimeможет повлиять на все открытые сеансы, в то время как session_set_cookie_paramsможет повлиять только на новый сеанс, который начинается с текущий запрос).
Джон

@Jon, если я снова вызову session_start (), все ли в моем $ _SESSION будет сброшено? если вы имеете в виду под "имеет потенциал повлиять на всю сессию", как это так? Спасибо за ответ.
oneofakind

33

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


Кто-нибудь может это подтвердить?
Оли

@ Оли: Это выглядит правильно после беглого прочтения. Вы также можете посмотреть на stackoverflow.com/questions/520237/… , но если у вас нет доступа к php.iniвашим практическим возможностям, они строго ограничены.
Джон

Кроме того, в Ubuntu 14, похоже /usr/lib/php5/maxlifetime, не будет рассчитывать значение ниже 24 минут. Таким образом, вы не можете установить время ожидания вашего сеанса ниже, чем это.
Генри

«Полностью забудьте о внутренней обработке PHP-сессий и реализуйте собственное управление сессиями». Боже мой, это опасный совет. Кошмар безопасности неизбежно приведет к.
Kzqai

@Kzqai Я также отмечаю, что «ему нужно больше кода, поэтому больше возможностей для ошибок и недостатков безопасности». Это не совет, я перечисляю альтернативы, но если у вас есть предложения по улучшению, пожалуйста, сделайте это.
Педро Химено

3

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

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


2

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

Чтобы ваши настройки работали, у вас должен быть другой каталог сохранения сеанса для добавленного домена с помощью 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


1

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

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


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

Насколько я вижу, он был не только закрыт, но и удален. Эти люди не имеют чести. Да, у вашей проблемы есть общее решение, о котором я говорил. Я напишу вам по электронной почте. Короче говоря, речь шла о выполнении 2 дополнительных запросов для получения этих значений prev / next. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
Ваш здравый смысл

0

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


4
-1: session.gc_maxlifetimeэто не параметр, управляющий временем жизни сеанса. Если вы настроены session.gc_divisorна это 1, то можете работать таким образом , но это просто ужасно.
Джон

1
@ Джон Я видел так много ответов на SO, предлагающих обратное, почему это так? stackoverflow.com/questions/514155/… stackoverflow.com/questions/9904105/…
giannis christofakis

2
@yannishristofakis: gc_maxlifetimeзадает интервал, после которого данные сеанса могут быть использованы для сбора мусора - если GC происходит после того, как истекло это время, данные сеанса будут уничтожены (с настройками по умолчанию это то же самое, что истечение сеанса). Но GC запускается вероятностно при каждом запуске сеанса, поэтому нет гарантии, что сеанс действительно истечет - вы можете построить кривую зависимости времени от времени, но она не будет выглядеть как кирпичная стена. Это только верхушка айсберга; см. stackoverflow.com/questions/520237/…
Джон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.