Як змінити час очікування сеансу в PHP?


154

Я хотів би продовжити час сеансу в php

Я знаю, що це можна зробити, змінивши файл php.ini. Але я не маю до нього доступу.

То чи можна це робити тільки за допомогою php-коду?



1
Пов'язаний, це в php.ini, але я думаю , що роки можуть використовувати ini_set як @matino сказав stackoverflow.com/questions/520237 / ...
J-Роу

Відповіді:


324

Час очікування сеансу - це поняття, яке потрібно реалізувати в коді, якщо ви хочете суворих гарантій; це єдиний спосіб, коли ви можете бути абсолютно впевнені, що жоден сеанс не переживе після Хвилини бездіяльності.

Якщо розслабити цю вимогу трохи прийнятно, і ви добре ставите нижню межу замість суворого обмеження тривалості, ви можете це зробити легко і без написання спеціальної логіки.

Зручність у невимушеній обстановці: як і чому

Якщо ваші сеанси реалізовані за допомогою файлів 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: Якщо ви телефонуєте, що саме?
Джон

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 (тобто кожні півгодини). Це завдання на роботу з хроном шукає сесії, старші за вказаний у конфігурації сеанс.gc_maxlifetime , і якщо такі знайдені, вони видаляються. Як наслідок, у цих системах ini_set('session.gc_maxlifetime', ...)ігнорується. Це також пояснює, чому в цьому питанні: PHP-сесії закінчилися занадто швидко , у ОП були проблеми в одному хості, але проблеми припинилися при переході на інший хост.

Отже, зважаючи на те, що у вас немає доступу до 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) складніший; По суті, вам доведеться самостійно реалізовувати всі функції сеансу. Я тут не буду вникати в деталі.


Хтось може це підтвердити?
Олі

@Oli: Це виглядає правильно після побіжного читання. Ви також можете подивитися 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-sesions-timing-earlier- очікується


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

Просто повідомлення про розміщення хостинг- сервера або додане на домени =

Щоб ваші налаштування працювали, ви повинні мати інший dir-сеанс збереження для доданого домену, використовуючи php_value session.save_path "папкаA / sessionA".

Тож створіть папку на своєму кореневому сервері, а не в public_html та не публікуйтеся ззовні. Для мого cpanel / сервера відмінно працювали дозволи на папки 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 додаткових запитів для отримання цих попередніх / наступних значень. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
Твій здоровий глузд

0

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


4
-1: session.gc_maxlifetimeне є настройкою, яка контролює час роботи сеансу. Це може бути здивовано працювати так, якщо ви налаштовані session.gc_divisorна це 1, але це просто жахливо.
Jon

1
@Jon Я бачив так багато відповідей на SO, що напрошується протилежне, чому це так? stackoverflow.com/questions/514155 / ... stackoverflow.com/questions/9904105 / ...
Янніс christofakis

2
@yannishristofakis: gc_maxlifetimeвстановлює інтервал, через який дані сеансу підлягають збору сміття - якщо GC відбудеться після того, як пройде багато часу, дані сеансу будуть знищені (для налаштувань за замовчуванням це те саме, що закінчується сеанс). Але GC спрацьовує ймовірнісно на кожному запуску сеансу, тому немає гарантії, що сеанс дійсно закінчиться - ви можете побудувати криву зондування проти часу, але він не буде схожий на цегляну стіну. Ось лише верхівка айсберга; см stackoverflow.com/questions/520237 / ...
Jon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.