How to change the session timeout in PHP?
Asked Answered
A

7

186

I would like to extend the session timeout in php

I know that it is possible to do so by modifying the php.ini file. But I don't have access to it.

So is it possible to do it only with php code?

Attitudinarian answered 29/11, 2011 at 13:13 Comment(2)
php.net/manual/en/function.ini-set.phpCathern
Related, this is in php.ini, but I think yo can use ini_set like @Cathern said #520737Kablesh
K
372

Session timeout is a notion that has to be implemented in code if you want strict guarantees; that's the only way you can be absolutely certain that no session ever will survive after X minutes of inactivity.

If relaxing this requirement a little is acceptable and you are fine with placing a lower bound instead of a strict limit to the duration, you can do so easily and without writing custom logic.

Convenience in relaxed environments: how and why

If your sessions are implemented with cookies (which they probably are), and if the clients are not malicious, you can set an upper bound on the session duration by tweaking certain parameters. If you are using PHP's default session handling with cookies, setting session.gc_maxlifetime along with session_set_cookie_params should work for you like this:

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

This works by configuring the server to keep session data around for at least one hour of inactivity and instructing your clients that they should "forget" their session id after the same time span. Both of these steps are required to achieve the expected result.

  • If you don't tell the clients to forget their session id after an hour (or if the clients are malicious and choose to ignore your instructions) they will keep using the same session id and its effective duration will be non-deterministic. That is because sessions whose lifetime has expired on the server side are not garbage-collected immediately but only whenever the session GC kicks in.

    GC is a potentially expensive process, so typically the probability is rather small or even zero (a website getting huge numbers of hits will probably forgo probabilistic GC entirely and schedule it to happen in the background every X minutes). In both cases (assuming non-cooperating clients) the lower bound for effective session lifetimes will be session.gc_maxlifetime, but the upper bound will be unpredictable.

  • If you don't set session.gc_maxlifetime to the same time span then the server might discard idle session data earlier than that; in this case, a client that still remembers their session id will present it but the server will find no data associated with that session, effectively behaving as if the session had just started.

Certainty in critical environments

You can make things completely controllable by using custom logic to also place an upper bound on session inactivity; together with the lower bound from above this results in a strict setting.

Do this by saving the upper bound together with the rest of the session data:

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 id persistence

So far we have not been concerned at all with the exact values of each session id, only with the requirement that the data should exist as long as we need them to. Be aware that in the (unlikely) case that session ids matter to you, care must be taken to regenerate them with session_regenerate_id when required.

Kubiak answered 29/11, 2011 at 13:19 Comment(11)
Question: if call this, let's jsut say every minute, will it increase its limit? example at 10:00 I called it so its limit would be 11:00, after 1 miutes, 10:01, will the limit be 11:01?Polyphyletic
@oneofakind: If you call what exactly?Kubiak
These ones: ini_set('session.gc_maxlifetime', 3600); session_set_cookie_params(3600);Polyphyletic
@oneofakind: Yes, but only if you call session_start() as well (otherwise no effect at all) and only if you always call those two before session_start (otherwise gc_maxlifetime has the potential to affect all sessions currently open, while session_set_cookie_params can only affect a new session that starts with the current request).Kubiak
@Kubiak if I call session_start() again will it reset everything in my $_SESSION? if you mean by by "has the potential to affect all session" how so? Thanks for the reply.Polyphyletic
Just curious why did the question appear to be tl;dr?)Sexdecillion
Really help me, but if don't use cookies I don't need to write it right? @KubiakTrip
@Trip well you may not need to set the cookie timer if oyu are using with the session ID as a GET parameter but you would need to tun either the GC or the custom logic (depending on how critical it is) so people cannot reuse the ID (and it's certainly possible even accidentially because it will show ip for the user in urlbar and history)Drawstring
I think this answer is particulary great because it shows critical and non critical. I personally use the PHP-session just for mostly non-crit stuff anyway like error messages and whatever and use a database based session with its own cookie for the real critical stuff, that way a delete command with proper filter kicks out all old sessionsDrawstring
One of the best answers on stackoverflow!!! Thanks @Jon! So many people forgo the why and just jump into the how. That leaves lots of people copying/pasting. Your "why" made me a better coder—not just a better copier. Wish there were more answers like this.Testate
You may also have to set the "session.save_path" to get it to work, especially if you're on a shared server. Good answer besides missing that point.Jere
L
41

If you use PHP's default session handling, the only way to reliably change the session duration in all platforms is to change php.ini. That's because in some platforms, garbage collection is implemented through a script that runs every certain time (a cron script) that reads directly from php.ini, and therefore any attempts at changing it at run time, e.g. via ini_set(), are unreliable and most likely won't work.

For example, in Debian Linux systems, PHP's internal garbage collection is disabled by setting session.gc_probability=0 by default in the configuration, and is instead done via /etc/cron.d/php, which runs at XX:09 and XX:39 (that is, every half hour). This cron job looks for sessions older than the session.gc_maxlifetime specified in the configuration, and if any are found, they are deleted. As a consequence, in these systems ini_set('session.gc_maxlifetime', ...) is ignored. That also explains why in this question: PHP sessions timing out too quickly, the OP had problems in one host but the problems ceased when switching to a different host.

So, given that you don't have access to php.ini, if you want to do it portably, using the default session handling is not an option. Apparently, extending the cookie lifetime was enough for your host, but if you want a solution that works reliably even if you switch hosts, you have to use a different alternative.

Available alternative methods include:

  1. Set a different session (save) handler in PHP to save your sessions in a different directory or in a database, as specified in PHP: Custom Session Handlers (PHP manual), so that the cron job doesn't reach it, and only PHP's internal garbage collection takes place. This option probably can make use of ini_set() to set session.gc_maxlifetime but I prefer to just ignore the maxlifetime parameter in my gc() callback and determine maximum lifetime on my own.

  2. Completely forget about PHP internal session handling and implement your own session management. This method has two main disadvantages: you will need your own global session variables, so you lose the advantage of the $_SESSION superglobal, and it needs more code thus there are more opportunities for bugs and security flaws. Most importantly, the session identifier should be generated out of cryptographically secure random or pseudorandom numbers to avoid session ID predictability (leading to possible session hijacking), and that is not so easy to do with PHP portably. The main advantage is that it will work consistently in all platforms and you have full control over the code. That's the approach taken e.g. by the phpBB forum software (at least version 1; I'm not sure about more recent versions).

There is an example of (1) in the documentation for session_set_save_handler(). The example is long but I'll reproduce it here, with the relevant modifications necessary to extend the session duration. Note the inclusion of session_set_cookie_params() to increase the cookie lifetime as well.

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

Approach (2) is more complicated; basically, you have to re-implement all session functions on your own. I won't go into details here.

Lusty answered 2/9, 2013 at 12:30 Comment(6)
Could anyone confirm that?Attitudinarian
@Oli: It looks correct after a cursory read. You might also want to look at #520737, but if you don't have access to php.ini your practical options are severely restricted.Kubiak
Also, on Ubuntu 14 it looks like /usr/lib/php5/maxlifetime won't calculate a value below 24 minutes. So you can't set your session timeouts to lower than that.Hindrance
"Completely forget about PHP internal session handling and implement your own session management." good god man, that is dangerous advice. A security nightmare would inevitably result.Fougere
@Fougere I also note that "it needs more code thus there are more opportunities for bugs and security flaws". It's not advice, I'm enumerating the alternatives, but if you have a suggestion to improve it, please do.Lusty
session.gc_probability defaults to 1 according to docs - php.net/manual/en/…Saiz
A
14

Just a notice for a sharing hosting server or added on domains =

For your settings to work you must have a different save session dir for added domain by using php_value session.save_path folderA/sessionsA.

So create a folder to your root server, not into the public_html and not to be publicity accessed from outside. For my cpanel/server worked fine the folder permissions 0700. Give a try...

# 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);
# session.cache_expire is in minutes unlike the other settings above         
ini_set('session.cache_expire', 960);
ini_set('session.name', 'MyDomainA');

before session_start();

or put this in your .htaccess file.

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

After many researching and testing this worked fine for shared cpanel/php7 server. Many thanks to: NoiS

Amends answered 19/10, 2019 at 16:36 Comment(1)
I just had to change save_path as you said, it worked on my shared hosting serverColet
L
4

Put $_SESSION['login_time'] = time(); into the previous authentication page. And the snipped below in every other page where you want to check the session time-out.

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

Edit : This only works if you already used the tweaks in other posts, or disabled Garbage Collection, and want to manually check the session duration. Don't forget to add die() after a redirect, because some scripts/robots might ignore it. Also, directly destroying the session with session_destroy() instead of relying on a redirect for that might be a better option, again, in case of a malicious client or a robot.

Llywellyn answered 15/10, 2017 at 8:8 Comment(0)
B
4

Adding comment for anyone using Plesk having issues with any of the above as it was driving me crazy, setting session.gc_maxlifetime from your PHP script wont work as Plesk has it's own garbage collection script run from cron.

I used the solution posted on the link below of moving the cron job from hourly to daily to avoid this issue, then the top answer above should work:

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

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

Bowing answered 21/6, 2018 at 9:40 Comment(0)
U
0

No. If you don't have access to the php.ini, you can't guarantee that changes would have any effect.

I doubt you need to extend your sessions time though.
It has pretty sensible timeout at the moment and there are no reasons to extend it.

Ulla answered 29/11, 2011 at 13:16 Comment(7)
Hi Col, I have been looking all over this place to find a way to contact you. I saw that you gave me some suggestions on my last post that was closed (Sunday.) I got busy on another project and now it's gone. I would really like to try your suggestions. This there anyway to find what you wrote?Empson
As far I can see, it was not only closed, but also deleted. These people have no honor. Yes, your problem has a common solution I was talking about. I'll write you by email. In short, it was about running 2 additional queries to get these prev/next values. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1Ulla
As pointed our in the other answers there are actually solutions for this. Also there are good reasons for preserving sessions for longer times (like storing view settings).Benzel
@Benzel you are surely confusing sessions with cookies (or database)Ulla
@YourCommonSense sessions are based on cookies (except for the url-param way which is not secure, though).Benzel
@Benzel please learn what a session is and how it's different from a cookie it is based on. It is not hardUlla
@YourCommonSense sure I know the difference between cookies and sessions. You might just have a different understanding about the lifetime of a session (i.e. ending on browser close). But this matter of discussion should not be undergone here.Benzel
T
-1

You can override values in php.ini from your PHP code using ini_set().

Tatiana answered 29/11, 2011 at 13:16 Comment(4)
-1: session.gc_maxlifetime is not the setting that controls session lifetime. It can be bludgeoned to work like that if you set session.gc_divisor to 1, but that's just horrible.Kubiak
@Kubiak I have seen so many answers on SO suggesting the opposite,why is that? #514655 #9904605Apotropaic
@yannishristofakis: gc_maxlifetime sets the interval after which session data is eligible for garbage collection -- if GC occurs after that much time has elapsed, the session data will be destroyed (with default settings this is the same as expiring the session). But GC is triggered probabilistically on each session start, so there is no guarantee the session will actually expire -- you can plot a curve of prob vs time, but it won't look like a brickwall. That's just the tip of the iceberg; see #520737Kubiak
This works only if you have one single session management (i.e. one single website) on the hosting. Otherwise the shortest garbage collection timeout rules about the others.Benzel

© 2022 - 2024 — McMap. All rights reserved.