Как мне закончить сеанс PHP через 30 минут?

824

Мне нужно сохранить сеанс в течение 30 минут, а затем уничтожить его.

  • 31
    Обратите внимание, что как минимум две настройки имеют решающее значение для установки времени сеанса, и, возможно, три. Двумя определенно важными являются session.gc_maxlifetime и session.cookie_lifetime (где 0 не совпадает с некоторым длинным числом). Для полной 100% -ной уверенности в разрешении длительных периодов может также потребоваться установить session.save_path из-за изменяющегося времени очистки ОС под управлением каталога / tmp, где файлы сеансов сохраняются по умолчанию.
  • 0
    Я не понимаю, почему вы хотите закончить сеанс. Если вы беспокоитесь, что пользователь покидает свой компьютер без выхода из системы, а неавторизованный пользователь захватывает его компьютер, истечение срока сеанса на вашем сайте не помешает угонщику получить доступ к файлам жертвы на диске.
Показать ещё 1 комментарий
Теги:
cookies
session

10 ответов

1368
Лучший ответ

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

Во-первых:

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

Но сборщик мусора запускается только с вероятностью session.gc_probability, деленной на session.gc_divisor. И используя значения по умолчанию для этих опций (1 и 100 соответственно), вероятность составляет всего 1%.

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

Кроме того, при использовании файлов PHP по умолчанию session.save_path. С помощью этого обработчика сеанса возраст данных сеанса рассчитывается на дату последней модификации файла, а не на последнюю дату доступа:

Примечание.. Если вы используете обработчик сеанса по умолчанию для файлов, ваша файловая система должна отслеживать время доступа (atime). Windows FAT не так, вам придется придумать другой способ обработки мусора, собирающего вашу сессию, если вы застряли в файловой системе FAT или в любой другой файловой системе, где отслеживание атима недоступно. Начиная с PHP 4.2.3 он использовал mtime (измененная дата) вместо atime. Таким образом, у вас не будет проблем с файловыми системами, где отслеживание атима недоступно.

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

И второе:

session.cookie_lifetime
session.cookie_lifetime указывает время жизни файла cookie в секундах, которое отправляется в браузер. [...]

Да, это правильно. Это влияет только на время жизни файла cookie, и сам сеанс может быть действительным. Но задача сервера - аннулировать сеанс, а не клиент. Так что это ничего не помогает. Фактически, если session.cookie_lifetime, установленное в 0, сделает сеансы cookie реальным 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 сессии активным.
  • 2
    Как вы можете изменить это, если хотите проверить «неактивное время»? Другими словами, пользователь входит в систему, и пока он продолжает использовать сайт, он не будет выходить из системы. Однако, если они неактивны в течение 30 минут, они выйдут из системы?
  • 12
    @Metropolis: используйте что-то вроде $_SESSION['LAST_ACTIVITY'] аналогичное $_SESSION['CREATED'] где вы сохраняете время последней активности пользователя, но обновляете это значение при каждом запросе. Теперь, если разница этого времени с текущим временем больше 1800 секунд, сеанс не использовался более 30 минут.
Показать ещё 24 комментария
98

Простой способ истечения срока действия 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="text1"></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><input type="password" name="pwd"></td>
            </tr>
            <tr>
                <td><input type="submit" value="SignIn" name="submit1"></td>
            </tr>
        </table>
    </form>
</html>

<?php
    if ($_POST['submit1']) {
        $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');
?>
  • 41
    Сочетание логики и представления не рекомендуется в наши дни и в те времена, когда MVC является нормой.
  • 0
    Может быть, я упускаю что-то элементарное в сеансах, но что хорошего в этом, если сеансы разрушаются ОС каждые 30 минут?
Показать ещё 3 комментария
31

Можно ли зарегистрировать пользователя после установленного времени? Установка времени создания сеанса (или времени истечения срока действия) при его регистрации, а затем проверка того, что на каждой загрузке страницы может справиться с этим.

например:.

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

// later

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

Изменить: У меня есть ощущение, что вы имеете в виду что-то еще.

Вы можете выполнять сеансы после определенной продолжительности жизни, используя параметр session.gc_maxlifetime:

Edit:  ini_set ('session.gc_maxlifetime', 60 * 30);

  • 1
    session.gc-maxlifetime, вероятно, лучший путь.
  • 2
    Существуют некоторые проблемы с временем жизни файлов cookie сеанса, в первую очередь это зависит от клиента, который их применяет. Срок действия файлов cookie позволяет клиенту очищать ненужные / просроченные файлы cookie, его не следует путать с какими-либо вопросами безопасности.
Показать ещё 1 комментарий
16

В этом сообщении показано несколько способов контроля таймаута сеанса: http://bytes.com/topic/php/insights/889606-setting-timeout-php-sessions

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 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);
    }
}
15

Ну, я понимаю, что ответы на ошибки верны, но они находятся на уровне приложений, почему бы нам просто не использовать файл .htaccess для установки времени истечения срока действия?

<IfModule mod_php5.c>
    #Session timeout
    php_value session.cookie_lifetime 1800
    php_value session.gc_maxlifetime 1800
</IfModule>
  • 1
    Ответ Лоде дает прекрасное объяснение, почему этот ответ ненадежен, не должен использоваться.
10
if (isSet($_SESSION['started'])){
    if((mktime() - $_SESSION['started'] - 60*30) > 0){
        //Logout, destroy session, etc.
    }
}
else {
    $_SESSION['started'] = mktime();
}
  • 0
    Так что, если вам нужно собрать это вручную, для чего именно используется gc_maxlifetime ???
9

Используйте session_set_cookie_params funciton для этого.

Необходимо вызвать эту функцию перед вызовом session_start().

Попробуйте следующее:

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

session_set_cookie_params($lifetime);

session_start();

Смотрите еще в: http://php.net/manual/function.session-set-cookie-params.php

8

Это на самом деле легко с такой функцией, как следующая. Он использует имя таблицы таблиц "сеансы" с полями "id" и "time".

Каждый раз, когда пользователь снова посещает ваш сайт или службу, вы должны вызвать эту функцию, чтобы проверить, имеет ли ее возвращаемое значение TRUE. Если это ЛОЖЬ, пользователь истек, и сеанс будет уничтожен (Примечание. Эта функция использует класс базы данных для подключения и запроса базы данных, конечно, вы также можете сделать это внутри своей функции или что-то в этом роде):

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;
}
3

Пожалуйста, используйте следующий блок кода в вашем файле include, который загружается на всех страницах.

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

Сохранение метки времени в сеансе


<?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
}
?>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню