Jak zmienić limit czasu sesji w PHP?

Odpowiedzi:

324

Limit czasu sesji to pojęcie, które należy zaimplementować w kodzie, jeśli chcesz uzyskać ścisłe gwarancje; To jedyny sposób, można mieć pewność, że sesja nigdy nie przetrwa po X minutach bezczynności.

Jeśli trochę złagodzenie tego wymogu jest do zaakceptowania i nie ma problemu z umieszczeniem dolnej granicy zamiast ścisłego ograniczenia czasu trwania, możesz to zrobić łatwo i bez pisania niestandardowej logiki.

Wygoda w spokojnym otoczeniu: jak i dlaczego

Jeśli Twoje sesje są zaimplementowane za pomocą plików cookie (którymi prawdopodobnie są) i jeśli klienci nie są złośliwi, możesz ustawić górną granicę czasu trwania sesji, dostosowując określone parametry. Jeśli używasz domyślnej obsługi sesji PHP z plikami cookie, ustawienie session.gc_maxlifetimewraz z session_set_cookie_paramspowinno działać w następujący sposób:

// 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!

Działa to poprzez skonfigurowanie serwera tak, aby przechowywał dane sesji przez co najmniej jedną godzinę bezczynności i poinstruowanie klientów, że powinni „zapomnieć” o swoim identyfikatorze sesji po tym samym czasie. Oba te kroki są wymagane, aby osiągnąć oczekiwany rezultat.

  • Jeśli nie powiesz klientom, aby zapomnieli identyfikator sesji po godzinie (lub jeśli klienci są złośliwi i zdecydują się zignorować Twoje instrukcje), będą nadal używać tego samego identyfikatora sesji, a jej efektywny czas trwania będzie niedeterministyczny. Dzieje się tak, ponieważ sesje, których czas życia wygasł po stronie serwera, nie są natychmiast zbierane, ale tylko wtedy, gdy uruchomi się sesja GC .

    GC jest potencjalnie kosztownym procesem, więc zwykle prawdopodobieństwo jest raczej małe lub nawet zerowe (strona internetowa, która otrzyma ogromną liczbę trafień, prawdopodobnie całkowicie zrezygnuje z probabilistycznego GC i zaplanuje, aby miało to się odbywać w tle co X minut). W obu przypadkach (zakładając niewspółpracujących klientów) dolna granica efektywnych czasów trwania sesji będzie session.gc_maxlifetime, ale górna granica będzie nieprzewidywalna.

  • Jeśli nie ustawisz session.gc_maxlifetimetego samego przedziału czasu, serwer może odrzucić dane sesji bezczynnych wcześniej; w takim przypadku klient, który nadal pamięta swój identyfikator sesji, przedstawi go, ale serwer nie znajdzie żadnych danych związanych z tą sesją, zachowując się tak, jakby sesja właśnie się rozpoczęła.

Pewność w krytycznych środowiskach

Możesz całkowicie kontrolować rzeczy, używając niestandardowej logiki, aby również umieścić górną granicę dla braku aktywności sesji; razem z dolną granicą z góry daje to ścisłe ustawienie.

Zrób to, zapisując górną granicę wraz z resztą danych sesji:

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;

Trwałość identyfikatora sesji

Do tej pory nie zajmowaliśmy się w ogóle dokładnymi wartościami każdego identyfikatora sesji, a jedynie wymaganiem, aby dane istniały tak długo, jak ich potrzebujemy. Pamiętaj, że w (mało prawdopodobnym) przypadku, gdy identyfikatory sesji mają dla Ciebie znaczenie, należy zadbać o ich regenerację w session_regenerate_idrazie potrzeby.

Jon
źródło
Pytanie: jeśli zadzwonisz, powiedzmy, co minutę, czy zwiększy to swój limit? na przykład o 10:00 zadzwoniłem do niego, więc jego limit będzie wynosił 11:00, po 1 minucie, 10:01, czy limit będzie wynosił 11:01?
oneofakind
@oneofakind: Jeśli zadzwonisz, co dokładnie?
Jon
1
Te: ini_set ('session.gc_maxlifetime', 3600); session_set_cookie_params (3600);
oneofakind
@oneofakind: Tak, ale tylko wtedy, session_start()gdy również dzwonisz (w przeciwnym razie nie ma żadnego efektu) i tylko wtedy, gdy zawsze dzwonisz do tych dwóch wcześniej session_start(w przeciwnym razie gc_maxlifetimemoże wpłynąć na wszystkie aktualnie otwarte sesje, podczas gdy session_set_cookie_paramsmoże wpływać tylko na nową sesję, która zaczyna się od aktualny wniosek).
Jon
@Jon, jeśli ponownie wywołam session_start (), czy zresetuje to wszystko w mojej $ _SESSION? jeśli masz na myśli "ma potencjał, aby wpłynąć na wszystkie sesje", to jak to? Dziękuję za odpowiedź.
oneofakind
33

Jeśli używasz domyślnej obsługi sesji PHP, jedynym sposobem niezawodnej zmiany czasu trwania sesji na wszystkich platformach jest zmiana pliku php.ini . Dzieje się tak, ponieważ na niektórych platformach zbieranie elementów bezużytecznych jest implementowane za pomocą skryptu uruchamianego za każdym razem ( skrypt cron ), który czyta bezpośrednio z php.ini , a zatem wszelkie próby zmiany go w czasie wykonywania, np. Przez ini_set(), są zawodne i najprawdopodobniej nie zadziała.

Na przykład w systemach Debian Linux wewnętrzne czyszczenie pamięci PHP jest wyłączone przez ustawienie session.gc_probability=0domyślne w konfiguracji i zamiast tego odbywa się za pośrednictwem /etc/cron.d/php, który działa o XX: 09 i XX: 39 (czyli co pół godziny). To zadanie crona szuka sesji starszych niż sesja.gc_maxlifetime określona w konfiguracji, a jeśli takie zostaną znalezione, są one usuwane. W konsekwencji w tych systemach ini_set('session.gc_maxlifetime', ...)jest ignorowane. To wyjaśnia również, dlaczego w tym pytaniu: sesje PHP zbyt szybko wygasały , operacja miała problemy na jednym hoście, ale problemy ustały po przełączeniu się na inny host.

Tak więc, biorąc pod uwagę, że nie masz dostępu do php.ini , jeśli chcesz to zrobić przenośnie, użycie domyślnej obsługi sesji nie jest opcją. Wydaje się, że wydłużenie czasu życia plików cookie wystarczyło Twojemu hostowi, ale jeśli chcesz, aby rozwiązanie działało niezawodnie nawet przy zmianie hostów, musisz użyć innej alternatywy.

Dostępne metody alternatywne obejmują:

  1. Ustaw inną procedurę obsługi sesji (zapisywania) w PHP, aby zapisywać sesje w innym katalogu lub w bazie danych, jak określono w PHP: Niestandardowe moduły obsługi sesji (podręcznik PHP) , aby zadanie cron do niego nie docierało i tylko w PHP ma miejsce wewnętrzne usuwanie śmieci. Ta opcja prawdopodobnie przydaje sięini_set() do ustawienia session.gc_maxlifetime, ale wolę po prostu zignorować parametr maxlifetime w moim gc()wywołaniu zwrotnym i samodzielnie określić maksymalny czas życia.

  2. Całkowicie zapomnij o wewnętrznej obsłudze sesji PHP i zaimplementuj własne zarządzanie sesjami. Ta metoda ma dwie główne wady: będziesz potrzebować własnych globalnych zmiennych sesyjnych, więc tracisz przewagę $_SESSIONsuperglobalnego i wymaga ona więcej kodu, przez co jest więcej okazji do błędów i luk w zabezpieczeniach. Co najważniejsze, identyfikator sesji powinien być generowany z zabezpieczonych kryptograficznie liczb losowych lub pseudolosowych, aby uniknąć przewidywalności identyfikatora sesji (prowadzącej do możliwego przechwycenia sesji), a to nie jest tak łatwe do zrobienia w przenośnym PHP. Główną zaletą jest to, że będzie działał spójnie na wszystkich platformach i masz pełną kontrolę nad kodem. Takie podejście przyjęło np. Oprogramowanie forum phpBB (przynajmniej wersja 1; nie jestem pewien co do nowszych wersji).

W dokumentacji dla programusession_set_save_handler() znajduje się przykład (1) . Przykład jest długi, ale powielę go tutaj, z odpowiednimi modyfikacjami niezbędnymi do wydłużenia czasu trwania sesji. Zwróć uwagę na włączenie, session_set_cookie_params()aby wydłużyć czas życia plików 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

Podejście (2) jest bardziej skomplikowane; w zasadzie musisz samodzielnie ponownie zaimplementować wszystkie funkcje sesji. Nie będę tutaj wchodził w szczegóły.

Pedro Gimeno
źródło
Czy ktoś mógłby to potwierdzić?
Oli
@Oli: Wygląda poprawnie po pobieżnym przeczytaniu. Możesz również zajrzeć na stackoverflow.com/questions/520237/… , ale jeśli nie masz dostępu do php.iniswoich praktycznych opcji, są poważnie ograniczone.
Jon,
Ponadto na Ubuntu 14 wygląda na to, że /usr/lib/php5/maxlifetimenie obliczy wartości poniżej 24 minut. Więc nie możesz ustawić limitów czasu sesji na niższe niż to.
Henry
„Całkowicie zapomnij o wewnętrznej obsłudze sesji PHP i zaimplementuj własne zarządzanie sesjami”. dobry Boże człowieku, to niebezpieczna rada. Skutkiem byłby koszmar bezpieczeństwa.
Kzqai
@Kzqai Zwracam również uwagę, że "potrzebuje więcej kodu, więc jest więcej możliwości błędów i luk w zabezpieczeniach". To nie jest rada, wyliczam alternatywy, ale jeśli masz sugestie, jak to poprawić, zrób to.
Pedro Gimeno
3

Dodanie komentarza dla każdego, kto używa Pleska, ma problemy z którymkolwiek z powyższych, ponieważ doprowadzało mnie to do szaleństwa, ustawienie session.gc_maxlifetime z twojego skryptu PHP nie zadziała, ponieważ Plesk ma swój własny skrypt do czyszczenia pamięci uruchamiany z crona.

Użyłem rozwiązania zamieszczonego pod linkiem poniżej, aby przenieść zadanie cron z godzinnych na codzienne, aby uniknąć tego problemu, wtedy górna odpowiedź powyżej powinna działać:

mv /etc/cron.hourly/plesk-php-cleanuper /etc/cron.daily/

https://websavers.ca/plesk-php-sessions-timing-earlier-expected

Neil Walden
źródło
3

Umieść $_SESSION['login_time'] = time();na poprzedniej stronie uwierzytelniania. A poniżej na każdej innej stronie, na której chcesz sprawdzić limit czasu sesji.

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

Edycja: Działa to tylko wtedy, gdy użyłeś już poprawek w innych postach lub wyłączyłeś Garbage Collection i chcesz ręcznie sprawdzić czas trwania sesji. Nie zapomnij dodać die()po przekierowaniu, ponieważ niektóre skrypty / roboty mogą je zignorować. Ponadto bezpośrednie niszczenie sesji za pomocą session_destroy()zamiast polegania na przekierowaniu może być lepszą opcją, ponownie w przypadku złośliwego klienta lub robota.

mohamadRezaSamadi
źródło
2

Tylko powiadomienie o udostępniającym serwerze hostingowym lub dodaniu do domeny =

Aby ustawienia działały, musisz mieć inny katalog zapisywania sesji dla dodanej domeny, używając php_value session.save_path "folderA / sessionA".

Więc stwórz folder na swoim serwerze głównym, a nie na public_html i nie udostępniaj go z zewnątrz. Dla mojego cpanel / serwera działały dobrze uprawnienia do folderu 0700. Spróbuj ...

  • kod 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');

przed session_start ();

lub

  • .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

Po wielu badaniach i testach działało to dobrze na współdzielonym serwerze cpanel / php7. Podziękowania dla: NoiS

ChriStef
źródło
1

Nie. Jeśli nie masz dostępu do php.ini, nie możesz zagwarantować, że zmiany przyniosą jakikolwiek skutek.

Wątpię jednak, żebyś przedłużył czas swoich sesji.
W tej chwili ma dość rozsądny limit czasu i nie ma powodów, aby go przedłużać.

Twój zdrowy rozsądek
źródło
Cześć płk, rozglądałem się po całym tym miejscu, aby znaleźć sposób na skontaktowanie się z tobą. Widziałem, że dałeś mi kilka sugestii dotyczących mojego ostatniego postu, który był zamknięty (niedziela). Byłem zajęty innym projektem i teraz go nie ma. Bardzo chciałbym wypróbować Twoje sugestie. To w każdym razie, aby znaleźć to, co napisałeś?
Stary pies
O ile widzę, był nie tylko zamknięty, ale także usunięty. Ci ludzie nie mają honoru. Tak, twój problem ma wspólne rozwiązanie, o którym mówiłem. Napiszę do Ciebie e-mailem. Krótko mówiąc, chodziło o uruchomienie 2 dodatkowych zapytań, aby uzyskać te poprzednie / następne wartości. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
Twój zdrowy rozsądek
0

Możesz przesłonić wartości w php.ini z kodu PHP za pomocą ini_set().

Nathan Q
źródło
4
-1: session.gc_maxlifetimenie jest ustawieniem, które kontroluje czas trwania sesji. To może być pobity do pracy jak że jeśli ustawisz session.gc_divisorsię 1, ale to jest po prostu straszne.
Jon
1
@Jon Widziałem tak wiele odpowiedzi na SO sugerujących coś przeciwnego, dlaczego tak jest? stackoverflow.com/questions/514155/… stackoverflow.com/questions/9904105/…
giannis christofakis
2
@yannishristofakis: gc_maxlifetimeustawia interwał, po którym dane sesji kwalifikują się do czyszczenia pamięci - jeśli GC nastąpi po upływie tego czasu, dane sesji zostaną zniszczone (przy domyślnych ustawieniach jest to to samo, co wygaśnięcie sesji). Ale GC jest wyzwalane probabilistycznie przy każdym rozpoczęciu sesji, więc nie ma gwarancji, że sesja faktycznie wygaśnie - możesz wykreślić krzywą prawdopodobieństwa względem czasu, ale nie będzie ona wyglądać jak ściana z cegieł. To tylko wierzchołek góry lodowej; zobacz stackoverflow.com/questions/520237/…
Jon,