Як закінчити сеанс PHP через 30 хвилин?


1047

Мені потрібно тримати сеанс живим 30 хвилин, а потім знищити його.


35
Зверніть увагу, що принаймні два налаштування мають вирішальне значення для встановлення часу сеансу, а може бути і трьох. Два безумовно важливих з них - session.gc_maxlifetime та session.cookie_lifetime (де 0 не є таким, як деяке довге число). Для повної, 100% впевненості в тому, що дозволяти тривалий час, може знадобитися також встановити session.save_path через різний час очищення, керований ОС, в каталозі / tmp, де файли сеансу зберігаються за замовчуванням.
Kzqai

1
Я не розумію, чому ви хочете закінчити сесію. Якщо ви переживаєте, що користувач залишає свій комп’ютер, не виходячи з нього, а несанкціонований користувач бере його комп’ютер, закінчення сеансу на вашому веб-сайті не завадить викрадачеві отримати доступ до файлів жертви на диску.
Gqqnbig

Незрозуміло, що ви тут просите. Ви маєте на увазі, що хочете реалізувати жорсткий час бездіяльності (наразі PHP з радістю дозволить вам використовувати сеанс, який не торкався більше сесії.gc_maxlifetime) або ви маєте на увазі, що хочете обмежити сеанс на 30 хвилин незалежно від бездіяльність? Чесно кажучи, я вважаю, що прийнята відповідь тут є досить поганою порадою для будь-якої проблеми - в обох випадках логіка повинна бути реалізована за допомогою спеціального обробника сесії.
symcbean

Відповіді:


1663

Ви повинні реалізувати власний тайм-аут сеансу. Обидва варіанти, згадані іншими ( session.gc_maxlifetime та session.cookie_lifetime ), не є надійними. Я поясню причини цього.

Спочатку:

session.gc_maxlifetime
session.gc_maxlifetime визначає кількість секунд, після яких дані будуть розглядатися як "сміття" та очищатись. Збір сміття відбувається під час початку сеансу.

Але сміттєзбірник розпочинається лише з вірогідністю session.gc_probability, розділеною на session.gc_divisor . І використовуючи значення за замовчуванням для цих параметрів (1 і 100 відповідно), шанс становить лише 1%.

Ну, ви могли просто відрегулювати ці значення, щоб частіше запускати сміттєзбірник. Але коли запуститься сміттєзбірник, він перевірятиме дійсність для кожного зареєстрованого сеансу. І це затратно.

Крім того, при використанні файлів PHP за замовчуванням session.save_handler дані сеансу зберігаються у файлах шляхом, визначеним у session.save_path . За допомогою цього обробника сеансу вік даних сеансу обчислюється за останньою датою модифікації файлу, а не останньою датою доступу:

Примітка. Якщо ви використовуєте за замовчуванням файловий обробник сеансу, ваша файлова система повинна відслідковувати час доступу (atime). У Windows FAT це не так, що вам доведеться придумати інший спосіб поводження зі сміттям, збираючи сеанс, якщо ви застрягли з файловою системою FAT або будь-якою іншою файловою системою, де відстеження анімації недоступне. З PHP 4.2.3 він використовував mtime (модифіковану дату) замість atime. Таким чином, у вас не буде проблем з файловими системами, де відстеження atime недоступне.

Таким чином, додатково може статися, що файл даних сеансу видалено, тоді як сам сеанс все ще вважається дійсним, оскільки дані сеансу нещодавно не оновлювалися.

І друге:

session.cookie_lifetime
session.cookie_lifetime визначає тривалість файлу cookie в секундах, які надсилаються браузеру. […]

Так, правильно. Це впливає лише на час cookie, і сам сеанс може бути дійсним. Але завдання сервера - визнати недійсним сеанс, а не клієнта. Тож це нічого не допомагає. Насправді, встановлення сесії.cookie_lifetime0 зробить печиво сеансу справжнім сеансу файлом cookie сеансу, який діє лише до закриття браузера.

Висновок / найкраще рішення:

Найкраще рішення - реалізувати власний тайм-аут сеансу. Використовуйте просту позначку часу, яка позначає час останньої активності (тобто запиту) та оновлюйте її з кожним запитом:

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
    // last request was more than 30 minutes ago
    session_unset();     // unset $_SESSION variable for the run-time 
    session_destroy();   // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp

Оновлення даних сеансу з кожним запитом також змінює дату зміни файлу сеансу, щоб сеанс не був видалений сміттєзбірником передчасно.

Ви також можете використовувати додаткову позначку часу для періодичного відновлення ідентифікатора сеансу, щоб уникнути атак на сеанси, як-от виправлення сеансу :

if (!isset($_SESSION['CREATED'])) {
    $_SESSION['CREATED'] = time();
} else if (time() - $_SESSION['CREATED'] > 1800) {
    // session started more than 30 minutes ago
    session_regenerate_id(true);    // change session ID for the current session and invalidate old session ID
    $_SESSION['CREATED'] = time();  // update creation time
}

Примітки:

  • session.gc_maxlifetime має бути принаймні рівним терміну експлуатації цього користувальницького терміну дії терміну дії (1800 у цьому прикладі);
  • якщо ви хочете закінчити сеанс після 30 хвилин активності, а не через 30 хвилин з початку , вам також знадобиться скористатись setcookieтерміном дії, time()+60*30щоб зберегти cookie сеансу активним.

3
Як ви могли це змінити, якщо хочете перевірити "неактивний час"? Іншими словами, користувач входить у систему, і поки вони продовжують використовувати сайт, він не виходитиме з системи. Однак якщо вони неактивні протягом 30 хвилин, це вийде з системи?
Метрополіс

14
@Metropolis: Використовуйте щось $_SESSION['LAST_ACTIVITY']подібне до того, $_SESSION['CREATED']де ви зберігаєте час останньої активності користувача, але оновлюйте це значення з кожним запитом. Тепер, якщо відмінність цього часу від поточного часу перевищує 1800 секунд, сеанс не використовується більше 30 хвилин.
Gumbo

3
@Metropolis: session_unsetробить те саме, що і $_SESSION = array().
Гамбо

14
@Gumbo - я трохи заплутався, чи не варто вам використовувати свій код у поєднанні з ini_set('session.gc-maxlifetime', 1800)? Інакше інформація про ваш сеанс може бути знищена, поки ваш сеанс все ще повинен бути дійсним, принаймні, якщо параметр ini є стандартним 24 хвилини. Або я щось пропускаю?
jeroen

10
@jeron: Так, слід. Але зауважте, що сесія.gc_maxlifetime залежить від дати останньої модифікації файлу, якщо використовується обробник збереження сеансу files. Тож session.gc_maxlifetime має бути принаймні рівним терміну служби цього користувальницького терміну дії.
Гумбо

135

Простий спосіб закінчення сеансу PHP через 30 хвилин.

Примітка: якщо ви хочете змінити час, просто змініть 30 на потрібний час і не змінюйте * 60: це дасть хвилини.


У хвилинах: (30 * 60)
У днях: (n * 24 * 60 * 60) n = ні днів


Login.php

<?php
    session_start();
?>

<html>
    <form name="form1" method="post">
        <table>
            <tr>
                <td>Username</td>
                <td><input type="text" name="text"></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><input type="password" name="pwd"></td>
            </tr>
            <tr>
                <td><input type="submit" value="SignIn" name="submit"></td>
            </tr>
        </table>
    </form>
</html>

<?php
    if (isset($_POST['submit'])) {
        $v1 = "FirstUser";
        $v2 = "MyPassword";
        $v3 = $_POST['text'];
        $v4 = $_POST['pwd'];
        if ($v1 == $v3 && $v2 == $v4) {
            $_SESSION['luser'] = $v1;
            $_SESSION['start'] = time(); // Taking now logged in time.
            // Ending a session in 30 minutes from the starting time.
            $_SESSION['expire'] = $_SESSION['start'] + (30 * 60);
            header('Location: http://localhost/somefolder/homepage.php');
        } else {
            echo "Please enter the username or password again!";
        }
    }
?>

HomePage.php

<?php
    session_start();

    if (!isset($_SESSION['luser'])) {
        echo "Please Login again";
        echo "<a href='http://localhost/somefolder/login.php'>Click Here to Login</a>";
    }
    else {
        $now = time(); // Checking the time now when home page starts.

        if ($now > $_SESSION['expire']) {
            session_destroy();
            echo "Your session has expired! <a href='http://localhost/somefolder/login.php'>Login here</a>";
        }
        else { //Starting this else one [else1]
?>
            <!-- From here all HTML coding can be done -->
            <html>
                Welcome
                <?php
                    echo $_SESSION['luser'];
                    echo "<a href='http://localhost/somefolder/logout.php'>Log out</a>";
                ?>
            </html>
<?php
        }
    }
?>

LogOut.php

<?php
    session_start();
    session_destroy();
    header('Location: http://localhost/somefolder/login.php');
?>

42
Поєднання логіки та викладу є недоцільним у цей день та вік, коли MVC є нормою.
bcosca

Можливо, я пропускаю щось елементарне у сесіях, але що корисного це робить, якщо сеанси знищуються кожні 30 хвилин ОС?

25
@ незрозумілий Говори сам [усмішка] Я розглядаю MVC як гидоту.

2
Чи хороша ідея MVC, навіть коли проект невеликий, з одним програмістом? Я відчуваю, що мені слід створювати власні проекти у моделі MVC (або вирішувати проблему, АБО зробіть це MVC), але при відсутності досвіду роботи з MVC це просто стає ментальним блоком "Як мені зробити цей MVC?" і відволікання від початкової мети / проблеми, що вимагає вирішення.
MrVimes

@stillstanding ще одна згадка полягає в тому, що Login.phpзаголовки надсилаються ПІСЛЯ вмісту, що погано.
машинобудівний вирок

43

Це для виходу користувача через встановлений час? Встановлення часу створення сеансу (або закінчення терміну дії) під час його реєстрації, а потім перевірки, чи може на цьому завантажуватися завантаження кожної сторінки.

Наприклад:

$_SESSION['example'] = array('foo' => 'bar', 'registered' => time());

// later

if ((time() - $_SESSION['example']['registered']) > (60 * 30)) {
    unset($_SESSION['example']);
}

Редагувати: У мене є відчуття, що ти маєш на увазі щось інше.

Ви можете сканувати сеанси після певного періоду життя, використовуючи session.gc_maxlifetimeналаштування ini:

Редагувати: ini_set ('session.gc_maxlifetime', 60 * 30);


1
session.gc-maxlifetime, мабуть, найкращий шлях.
Powerlord

2
Існує кілька проблем із тривалістю файлу cookie сеансу, особливо це, що він покладається на клієнта для його виконання. Термін експлуатації файлів cookie існує для того, щоб клієнт міг очистити непотрібні файли cookie, його не можна плутати ні з чим, пов’язаним із безпекою.
Жакко

Є чи це gc_maxlifetimeабо gc-maxlifetime. Чи підтримує це як підкреслення, так і дефіси?
Майк Каузер

24

У цій публікації показано кілька способів контролю затримки сеансу: http://bytes.com/topic/php/insights/889606-setting-timeout-php-sesions

IMHO другий варіант - хороше рішення:

<?php
/***
 * Starts a session with a specific timeout and a specific GC probability.
 * @param int $timeout The number of seconds until it should time out.
 * @param int $probability The probablity, in int percentage, that the garbage 
 *        collection routine will be triggered right now.
 * @param strint $cookie_domain The domain path for the cookie.
 */
function session_start_timeout($timeout=5, $probability=100, $cookie_domain='/') {
    // Set the max lifetime
    ini_set("session.gc_maxlifetime", $timeout);

    // Set the session cookie to timout
    ini_set("session.cookie_lifetime", $timeout);

    // Change the save path. Sessions stored in teh same path
    // all share the same lifetime; the lowest lifetime will be
    // used for all. Therefore, for this to work, the session
    // must be stored in a directory where only sessions sharing
    // it's lifetime are. Best to just dynamically create on.
    $seperator = strstr(strtoupper(substr(PHP_OS, 0, 3)), "WIN") ? "\\" : "/";
    $path = ini_get("session.save_path") . $seperator . "session_" . $timeout . "sec";
    if(!file_exists($path)) {
        if(!mkdir($path, 600)) {
            trigger_error("Failed to create session save path directory '$path'. Check permissions.", E_USER_ERROR);
        }
    }
    ini_set("session.save_path", $path);

    // Set the chance to trigger the garbage collection.
    ini_set("session.gc_probability", $probability);
    ini_set("session.gc_divisor", 100); // Should always be 100

    // Start the session!
    session_start();

    // Renew the time left until this session times out.
    // If you skip this, the session will time out based
    // on the time when it was created, rather than when
    // it was last used.
    if(isset($_COOKIE[session_name()])) {
        setcookie(session_name(), $_COOKIE[session_name()], time() + $timeout, $cookie_domain);
    }
}

19

Добре, я розумію, що відповіді aboves правильні, але вони є на рівні програми, чому ми не просто використаємо .htaccessфайл для встановлення терміну придатності?

<IfModule mod_php5.c>
    #Session timeout
    php_value session.cookie_lifetime 1800
    php_value session.gc_maxlifetime 1800
</IfModule>

1
@ Відповідь Лоде ідеально пояснює, чому ця відповідь недостовірна не повинна використовуватися.
emix

15
if (isSet($_SESSION['started'])){
    if((mktime() - $_SESSION['started'] - 60*30) > 0){
        //Logout, destroy session, etc.
    }
}
else {
    $_SESSION['started'] = mktime();
}

15

Використовуйте функціонал session_set_cookie_paramsдля цього.

Потрібно викликати цю функцію раніше session_start() викликом.

Спробуйте це:

$lifetime = strtotime('+30 minutes', 0);

session_set_cookie_params($lifetime);

session_start();

Детальніше дивіться в: http://php.net/manual/function.session-set-cookie-params.php


11

Насправді це легко з такою функцією, як наступна. Він використовує назву таблиці бази даних "сеанси" з полями "id" і "time".

Кожен раз, коли користувач знову відвідує ваш веб-сайт або послугу, ви повинні викликати цю функцію, щоб перевірити, чи є її повернене значення ІСТИНА. Якщо це FALSE, у користувача закінчився термін дії, і сеанс буде знищено (Примітка. Ця функція використовує клас бази даних для підключення та запиту бази даних; звичайно, ви також можете це зробити у своїй функції або щось подібне):

function session_timeout_ok() {
    global $db;
    $timeout = SESSION_TIMEOUT; //const, e.g. 6 * 60 for 6 minutes
    $ok = false;
    $session_id = session_id();
    $sql = "SELECT time FROM sessions WHERE session_id = '".$session_id."'";
    $rows = $db->query($sql);
    if ($rows === false) {
        //Timestamp could not be read
        $ok = FALSE;
    }
    else {
        //Timestamp was read succesfully
        if (count($rows) > 0) {
            $zeile = $rows[0];
            $time_past = $zeile['time'];
            if ( $timeout + $time_past < time() ) {
                //Time has expired
                session_destroy();
                $sql = "DELETE FROM sessions WHERE session_id = '" . $session_id . "'";
                $affected = $db -> query($sql);
                $ok = FALSE;
            }
            else {
                //Time is okay
                $ok = TRUE;
                $sql = "UPDATE sessions SET time='" . time() . "' WHERE session_id = '" . $session_id . "'";
                $erg = $db -> query($sql);
                if ($erg == false) {
                    //DB error
                }
            }
        }
        else {
            //Session is new, write it to database table sessions
            $sql = "INSERT INTO sessions(session_id,time) VALUES ('".$session_id."','".time()."')";
            $res = $db->query($sql);
            if ($res === FALSE) {
                //Database error
                $ok = false;
            }
            $ok = true;
        }
        return $ok;
    }
    return $ok;
}

9

Зберігати часову позначку в сеансі


<?php    
$user = $_POST['user_name'];
$pass = $_POST['user_pass'];

require ('db_connection.php');

// Hey, always escape input if necessary!
$result = mysql_query(sprintf("SELECT * FROM accounts WHERE user_Name='%s' AND user_Pass='%s'", mysql_real_escape_string($user), mysql_real_escape_string($pass));

if( mysql_num_rows( $result ) > 0)
{
    $array = mysql_fetch_assoc($result);    

    session_start();
    $_SESSION['user_id'] = $user;
    $_SESSION['login_time'] = time();
    header("Location:loggedin.php");            
}
else
{
    header("Location:login.php");
}
?>

Тепер перевірте, чи мітка часу знаходиться у межах дозволеного часового вікна (1800 секунд - 30 хвилин)

<?php
session_start();
if( !isset( $_SESSION['user_id'] ) || time() - $_SESSION['login_time'] > 1800)
{
    header("Location:login.php");
}
else
{
    // uncomment the next line to refresh the session, so it will expire after thirteen minutes of inactivity, and not thirteen minutes after login
    //$_SESSION['login_time'] = time();
    echo ( "this session is ". $_SESSION['user_id'] );
    //show rest of the page and all other content
}
?>

8

Будь ласка, використовуйте наступний блок коду у вашому файлі включення, який завантажується на всі сторінки.

$expiry = 1800 ;//session expiry required after 30 mins
    if (isset($_SESSION['LAST']) && (time() - $_SESSION['LAST'] > $expiry)) {
        session_unset();
        session_destroy();
    }
    $_SESSION['LAST'] = time();

1

Використовуйте цей клас протягом 30 хв

class Session{
    public static function init(){
        ini_set('session.gc_maxlifetime', 1800) ;
        session_start();
    }
    public static function set($key, $val){
        $_SESSION[$key] =$val;
    }
    public static function get($key){
        if(isset($_SESSION[$key])){
            return $_SESSION[$key];
        } else{
            return false;
        }
    }
    public static function checkSession(){
        self::init();
        if(self::get("adminlogin")==false){
            self::destroy();
            header("Location:login.php");
        }
    }
    public static function checkLogin(){
        self::init();
        if(self::get("adminlogin")==true){
            header("Location:index.php");
        }
    }
    public static function destroy(){
        session_destroy();
        header("Location:login.php");
    }
}

0

Використання позначки часу ...

<?php
if (!isset($_SESSION)) {
    $session = session_start();
} 
if ($session && !isset($_SESSION['login_time'])) {
    if ($session == 1) {
        $_SESSION['login_time']=time();
        echo "Login :".$_SESSION['login_time'];
        echo "<br>";
        $_SESSION['idle_time']=$_SESSION['login_time']+20;
        echo "Session Idle :".$_SESSION['idle_time'];
        echo "<br>";
    } else{
        $_SESSION['login_time']="";
    }
} else {
    if (time()>$_SESSION['idle_time']){
        echo "Session Idle :".$_SESSION['idle_time'];
        echo "<br>";
        echo "Current :".time();
        echo "<br>";
        echo "Session Time Out";
        session_destroy();
        session_unset();
    } else {
        echo "Logged In<br>";
    }
}
?>

Я використав 20 секунд, щоб закінчити сеанс за допомогою часової позначки .

Якщо вам потрібно 30 хв, додайте 1800 (30 хв за секунди) ...


0

Ви можете прямо використовувати БД, щоб зробити це як альтернативу. Для цього я використовую функцію БД, яку я називаю chk_lgn.

Перевірте чеки входу, щоб побачити, чи вони ввійшли чи ні, і при цьому він встановлює позначку часу дати перевірки як останню активну в рядку / стовпці db користувача.

Я також там перевіряю час. Це працює для мене на даний момент, оскільки я використовую цю функцію для кожної сторінки.

PS Ніхто, кого я бачив, не пропонував чистого рішення БД.



-1

Просто збережіть поточний час і якщо він перевищує 30 хвилин, порівнюючи, тоді знищити поточний сеанс.


Єдиний раз, коли ви це оціните, це при використанні сеансу, правда?
Ерік Крамер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.