Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I implement lazy session creation in PHP?

Tags:

php

session

By default, PHP's session handling mechanisms set a session cookie header and store a session even if there is no data in the session. If no data is set in the session then I don't want a Set-Cookie header sent to the client in the response and I don't want an empty session record stored on the server. If data is added to $_SESSION, then the normal behavior should continue.

My goal is to implement lazy session creation behavior of the sort that Drupal 7 and Pressflow where no session is stored (or session cookie header sent) unless data is added to the $_SESSION array during application execution. The point of this behavior is to allow reverse proxies such as Varnish to cache and serve anonymous traffic while letting authenticated requests pass through to Apache/PHP. Varnish (or another proxy-server) is configured to pass through any requests without cookies, assuming correctly that if a cookie exists then the request is for a particular client.

I have ported the session handling code from Pressflow that uses session_set_save_handler() and overrides the implementation of session_write() to check for data in the $_SESSION array before saving and will write this up as library and add an answer here if this is the best/only route to take.

My Question: While I can implement a fully custom session_set_save_handler() system, is there an easier way to get this lazy session creation behavior in a relatively generic way that would be transparent to most applications?

like image 339
Adam Franco Avatar asked Jun 08 '10 14:06

Adam Franco


People also ask

How can you create a session in PHP?

You can start a session in PHP by using the session_start() function. This function will, by default, first check for an existing session. If a session already exists, it will do nothing, but it will create one if there's no pre-existing session available.

What is PHP session_start () and Session_destroy () function?

Output: session_destroy() function: It destroys the whole session rather destroying the variables. When session_start() is called, PHP sets the session cookie in browser. We need to delete the cookies also to completely destroy the session. Example: This example is used to destroying the session.

What is PHP session_start ()?

session_start() creates a session or resumes the current one based on a session identifier passed via a GET or POST request, or passed via a cookie. When session_start() is called or when a session auto starts, PHP will call the open and read session save handlers.

How PHP session is created and destroyed?

A PHP session can be destroyed by session_destroy() function. This function does not need any argument and a single call can destroy all the session variables. If you want to destroy a single session variable then you can use unset() function to unset a session variable.


1 Answers

Well, one option would be to use a session class to start/stop/store data in the session. So, you could do something like:

class Session implements ArrayAccess {
    protected $closed = false;
    protected $data = array();
    protected $name = 'mySessionName';
    protected $started = false;

    protected function __construct() {
        if (isset($_COOKIE[$this->name])) $this->start();
        $this->data = $_SESSION;
    }

    public static function initialize() {
        if (is_object($_SESSION)) return $_SESSION;
        $_SESSION = new Session();
        register_shutdown_function(array($_SESSION, 'close'));
        return $_SESSION;
    }

    public function close() {
        if ($this->closed) return false;
        if (!$this->started) {
            $_SESSION = array();
        } else {
            $_SESSION = $this->data;
        }
        session_write_close();
        $this->started = false;
        $this->closed = true;
    }

    public function offsetExists($offset) { 
        return isset($this->data[$offset]); 
    }

    public function offsetGet($offset) {
        if (!isset($this->data[$offset])) {
            throw new OutOfBoundsException('Key does not exist');
        }
        return $this->data[$offset]; 
    }

    public function offsetSet($offset, $value) {
        $this->set($offset, $value);
    }

    public function offsetUnset($offset) {
        if (isset($this->data[$offset])) unset($this->data[$offset]);
    }

    public function set($key, $value) {
        if (!$this->started) $this->start();
        $this->data[$key] = $value;
    }

    public function start() {
        session_name($this->name);
        session_start();
        $this->started = true;
    }
}

To use, at the start of your script call Session::initialize(). It will replace $_SESSION with the object, and setup the lazy loading. Afterward, you can just do

$_SESSION['user_id'] = 1;

If the session isn't started, it will be, and the user_id key would be set to 1. If at any point you wanted to close (commit) the session, just call $_SESSION->close().

You'll probably want to add some more session management functions (such as destroy, regenerate_id, the ability to change the name of the session, etc), but this should implement the basic functionality you're after...

It's not a save_handler, it's just a class to manage your sessions. If you really wanted to, you could implement ArrayAccess in the class, and on construct replace $_SESSION with that class (The benefit of doing that, is that way legacy code can still use session as they used to without calling $session->setData()). The only downside is that I'm not sure if the serialization routine that PHP uses would work properly (You'd need to put back the array into $_SESSION at some point... Probably with a register_shutdown_function()...

like image 123
ircmaxell Avatar answered Oct 24 '22 16:10

ircmaxell