Jak wygasnąć sesję PHP po 30 minutach?


1047

Muszę utrzymać sesję przy życiu przez 30 minut, a następnie ją zniszczyć.


35
Pamiętaj, że co najmniej dwa ustawienia są niezbędne do ustawienia czasu sesji, a może trzy. Dwoma z pewnością kluczowymi są session.gc_maxlifetime i session.cookie_lifetime (gdzie 0 to nie to samo, co jakaś długa liczba). Aby uzyskać pełną, 100% pewność długiego czasu, może być również konieczne ustawienie session.save_path, ze względu na różny czas czyszczenia kontrolowany przez system operacyjny w katalogu / tmp, w którym domyślnie przechowywane są pliki sesji.
Kzqai,

1
Nie rozumiem, dlaczego chcesz wygasnąć sesję. Jeśli martwisz się, że użytkownik opuści swój komputer bez wylogowania, a jego komputer przejmie nieautoryzowany użytkownik, wygaśnięcie sesji w Twojej witrynie nie uniemożliwi porywaczowi dostępu do plików ofiary na dysku.
Gqqnbig

Nie jest jasne, o co tu pytasz. Czy masz na myśli, że chcesz wprowadzić limit czasu bezczynności (obecnie PHP z przyjemnością pozwoli ci skorzystać z sesji, która nie została dotknięta dłużej niż session.gc_maxlifetime), czy masz na myśli, że chcesz ograniczyć sesję do 30 minut niezależnie od bezczynność? Szczerze mówiąc, myślę, że przyjęta tutaj odpowiedź jest raczej złą radą dla któregokolwiek z problemów - w obu przypadkach logika powinna zostać zaimplementowana za pomocą niestandardowego modułu obsługi sesji.
symcbean

Odpowiedzi:


1663

Powinieneś wdrożyć własny limit czasu sesji. Obie opcje wspomniane przez innych ( session.gc_maxlifetime i session.cookie_lifetime ) nie są niezawodne. Wyjaśnię powody tego.

Pierwszy:

session.gc_maxlifetime
session.gc_maxlifetime określa liczbę sekund, po których dane będą widziane jako „śmieci” i czyszczone. Usuwanie śmieci odbywa się podczas uruchamiania sesji.

Ale moduł czyszczenia pamięci jest uruchamiany tylko z prawdopodobieństwem session.gc_probability podzielonym przez session.gc_divisor . Przy zastosowaniu wartości domyślnych dla tych opcji (odpowiednio 1 i 100), szansa wynosi tylko 1%.

Cóż, możesz po prostu dostosować te wartości, aby śmieciarz był uruchamiany częściej. Ale gdy moduł śmieciowy zostanie uruchomiony, sprawdzi poprawność każdej zarejestrowanej sesji. I to jest kosztowne.

Ponadto, gdy używane są domyślne pliki PHP session.save_handler , dane sesji są przechowywane w plikach w ścieżce określonej w session.save_path . W tym module obsługi sesji wiek danych sesji jest obliczany na podstawie daty ostatniej modyfikacji pliku, a nie daty ostatniego dostępu:

Uwaga: Jeśli używasz domyślnego programu obsługi sesji opartego na plikach, twój system plików musi śledzić czasy dostępu (atime). Windows FAT tego nie robi, więc będziesz musiał wymyślić inny sposób radzenia sobie ze śmieciami zbierającymi sesję, jeśli utkniesz w systemie plików FAT lub innym systemie plików, w którym śledzenie atime nie jest dostępne. Od PHP 4.2.3 używa mtime (data modyfikacji) zamiast atime. Dzięki temu nie będziesz mieć problemów z systemami plików, w których śledzenie atime nie jest dostępne.

Może się zatem zdarzyć, że plik danych sesji zostanie usunięty, podczas gdy sama sesja nadal będzie uważana za ważną, ponieważ dane sesji nie zostały ostatnio zaktualizowane.

I drugi:

session.cookie_lifetime
session.cookie_lifetime określa czas życia ciasteczka w sekundach, które są wysyłane do przeglądarki. […]

Tak to prawda. Wpływa to tylko na czas życia plików cookie, a sama sesja może być nadal ważna. Ale zadaniem serwera jest unieważnienie sesji, a nie klienta. To nic nie pomaga. W rzeczywistości ustawienie session.cookie_lifetime0 tak, aby plik cookie sesji był prawdziwym plikiem cookie sesji, który jest ważny tylko do momentu zamknięcia przeglądarki.

Wniosek / najlepsze rozwiązanie:

Najlepszym rozwiązaniem jest wdrożenie własnego limitu czasu sesji. Użyj prostego znacznika czasu oznaczającego czas ostatniej aktywności (tj. Żądania) i aktualizuj go przy każdym żądaniu:

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

Aktualizowanie danych sesji przy każdym żądaniu zmienia również datę modyfikacji pliku sesji, dzięki czemu sesja nie jest usuwana przez moduł czyszczący przedwcześnie.

Możesz także użyć dodatkowego znacznika czasu, aby okresowo generować identyfikator sesji, aby uniknąć ataków na sesje, takich jak utrwalanie sesji :

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
}

Uwagi:

  • session.gc_maxlifetime powinna być co najmniej równa żywotności tego niestandardowego modułu obsługi wygaśnięcia (1800 w tym przykładzie);
  • jeśli chcesz wygasnąć sesję po 30 minutach aktywności zamiast po 30 minutach od rozpoczęcia , musisz także użyć setcookiez wygasaniem, time()+60*30aby utrzymać plik cookie sesji.

3
Jak możesz to zmienić, jeśli chcesz sprawdzić „nieaktywny czas”? Innymi słowy, użytkownik loguje się i dopóki nie będzie korzystał z witryny, nie będzie go wylogowywać. Jeśli jednak będą nieaktywne przez 30 minut, wyloguje ich?
Metropolis

14
@ Metropolis: użyj czegoś $_SESSION['LAST_ACTIVITY']podobnego do $_SESSION['CREATED']miejsca, w którym przechowujesz czas ostatniej aktywności użytkownika, ale aktualizuj tę wartość przy każdym żądaniu. Teraz, jeśli różnica tego czasu do bieżącego czasu jest większa niż 1800 sekund, sesja nie była używana przez ponad 30 minut.
Gumbo,

3
@Metropolis: session_unsetrobi to samo co $_SESSION = array().
Gumbo,

14
@Gumbo - jestem trochę zdezorientowany, czy nie powinieneś używać swojego kodu w połączeniu z ini_set('session.gc-maxlifetime', 1800)? W przeciwnym razie informacje o sesji mogą zostać zniszczone, podczas gdy sesja nadal powinna być ważna, przynajmniej jeśli ustawienie ini to standardowe 24 minuty. A może coś mi brakuje?
jeroen

10
@jeron: Tak, powinieneś. Należy jednak pamiętać, że sesja.gc_maxlifetime zależy od daty ostatniej modyfikacji pliku, jeśli filesużywany jest moduł obsługi zapisywania sesji . Więc session.gc_maxlifetime powinna być co najmniej równy czasowi życia tej obsługi niestandardowych ważności.
Gumbo,

135

Prosty sposób na zakończenie sesji PHP w 30 minut.

Uwaga: jeśli chcesz zmienić czas, po prostu zmień 30 na żądany czas i nie zmieniaj * 60: da to minuty.


W minutach: (30 * 60)
W dniach: (n * 24 * 60 * 60) n = liczba dni


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
Połączenie logiki i prezentacji jest odradzane w dzisiejszych czasach, gdy MVC jest normą.
bcosca

Może brakuje mi czegoś podstawowego w sesjach, ale co to za korzyść, jeśli sesje są niszczone co 30 minut przez system operacyjny?

25
@stillstanding Mów za siebie [uśmiech] Uważam MVC za obrzydliwość.

2
Czy MVC to dobry pomysł, nawet jeśli projekt jest mały, z jednym programistą? Wydaje mi się, że powinienem tworzyć własne projekty w modelu MVC (lub rozwiązać problem NASTĘPNIE sprawić, by stał się MVC), ale przy braku doświadczenia z MVC staje się po prostu mentalnym blokiem „Jak zrobić ten MVC?” i odwrócenie uwagi od pierwotnego celu / problemu wymagającego rozwiązania.
MrVimes,

@stillstanding inna wzmianka jest taka, że Login.phpnagłówki są wysyłane PO treści, co jest złe.
machineaddict

43

Czy to ma wylogować użytkownika po określonym czasie? Ustawienie czasu tworzenia sesji (lub czasu wygaśnięcia), kiedy jest ona rejestrowana, a następnie sprawdzenie, czy ładowanie na każdej stronie może sobie z tym poradzić.

Na przykład:

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

// later

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

Edycja: Mam wrażenie, że masz na myśli coś innego.

Możesz zeskrobać sesje po pewnym okresie użytkowania, używając session.gc_maxlifetimeustawienia ini:

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


1
session.gc-maxlifetime to prawdopodobnie najlepsza droga.
Władca

2
Istnieją pewne problemy z czasem życia plików cookie sesji, w szczególności wymuszenie tego zależy od klienta. Czas życia plików cookie pozwala klientowi wyczyścić niepotrzebne / wygasłe pliki cookie, nie należy go mylić z niczym związanym z bezpieczeństwem.
Jacco

Czy to gc_maxlifetimeczy gc-maxlifetime. Czy obsługuje zarówno podkreślenia, jak i łączniki?
Mike Causer,

24

Ten post pokazuje kilka sposobów kontrolowania limitu czasu sesji: http://bytes.com/topic/php/insights/889606-setting-timeout-php-sessions

IMHO druga opcja to fajne rozwiązanie:

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

Rozumiem, że powyższe odpowiedzi są poprawne, ale są na poziomie aplikacji, dlaczego po prostu nie używamy .htaccesspliku do ustawienia czasu wygaśnięcia?

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

1
Odpowiedź @ Lode daje doskonałe wyjaśnienie, dlaczego ta odpowiedź jest niewiarygodna, nie należy jej używać.
emix

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


11

To jest naprawdę łatwe dzięki takiej funkcji jak poniżej. Używa nazw tabel bazy danych „sesje” z polami „id” i „time”.

Za każdym razem, gdy użytkownik ponownie odwiedza Twoją witrynę lub usługę, powinieneś wywołać tę funkcję, aby sprawdzić, czy jej wartość zwracana jest PRAWDA. Jeśli ma wartość FAŁSZ, użytkownik wygasł, a sesja zostanie zniszczona (Uwaga: ta funkcja korzysta z klasy bazy danych do łączenia się z bazą danych i wysyłania do niej zapytań, oczywiście można to zrobić również w ramach funkcji lub coś w tym rodzaju):

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

Przechowuj znacznik czasu w sesji


<?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");
}
?>

Teraz sprawdź, czy znacznik czasu mieści się w dozwolonym oknie czasowym (1800 sekund to 30 minut)

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

Proszę użyć następującego bloku kodu w pliku dołączanym, który jest ładowany na każdej stronie.

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

1

Użyj tej klasy przez 30 min

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

Korzystanie ze znacznika czasu ...

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

Użyłem 20 sekund do wygaśnięcia sesji przy użyciu znacznika czasu .

Jeśli potrzebujesz 30 min, dodaj 1800 (30 min w sekundach) ...


0

Możesz bezpośrednio użyć DB, aby zrobić to jako alternatywę. Używam do tego funkcji DB, którą nazywam chk_lgn.

Sprawdź kontrole logowania, aby sprawdzić, czy są zalogowani, czy też, ustawiając przy tym datę i godzinę kontroli jako ostatnią aktywną w wierszu / kolumnie db użytkownika.

Tam też sprawdzam czas. Działa to dla mnie na chwilę, ponieważ używam tej funkcji do każdej strony.

PS Nikt, kogo widziałem, nie zaproponował czystego rozwiązania DB.



-1

Po prostu zapisz bieżący czas, a jeśli przekroczy on 30 minut poprzez porównanie, zniszcz bieżącą sesję.


Jedyny moment, który ocenisz to podczas korzystania z sesji, prawda?
Eric Kramer
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.