Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading PHP's session data without loading it

Tags:

php

session

I have got a session_id and I would like to read its data without loading it into $_SESSION array. Please bear in mind that I've not confined my question to some specific session handler.

[UPDATE]

Here's my scenario:

I've got two (or more) different open source projects that I want to merge into one. These projects make use of session but it is feasible that they overwrite each other (since they are all in the same host and in the same domain). To prevent this from happening I'm setting different session_names for each so they'll have their own sessions. But there are glue codes I need to write in which I have to have access to both sessions. I can load one into $_SESSION but I have to read others without loading.

[UPDATE]

Considering the answers given so far, I thought to clarify things a little more. The solution I look for is to start session twice (or more) within the same request. And each time with a different session_id. That way I can make a copy of the session and load another one. Having this said, it is not necessary the only solution but it's closest to what I'm looking for (just a hint).

like image 900
Mehran Avatar asked Mar 23 '23 11:03

Mehran


2 Answers

I would start both sessions one by one and store $_SESSION value in local arrays.

i.e.

// Loading the first session.
session_name('first_session_name');
session_start();
// Now we have first session variables available in $_SESSION
$_FIRST_SESSION = $_SESSION;
// End current session.
session_write_close();
// Just to make sure nothing remains in the session.
unset($_SESSION);
// Now set the second session name.
session_name('second_session_name');
// Check and see if the second session name has a session id.
if (isset($_COOKIE['second_session_name']))
    // There's already a session id for this name.
    session_id($_COOKIE['second_session_name']);
else
    // We need to generate a new session id as this is the first time.
    session_id(sha1(mt_rand()));
session_start();
$_SECOND_SESSION = $_SESSION;
like image 128
Peter Pivarc Avatar answered Mar 26 '23 02:03

Peter Pivarc


I'd hide to the projects whose $_SESSION you use. The projects should use simply $_SESSION like before, but you manage what data is read. Also use your own SessionHandler so that when the one project's $_SESSION is destroyed, the other's isn't.

This file you should include at the moment where you start your session. Then, don't use anywhere session_start().

class SessionAccess implements ArrayAccess {
    protected $handler;
    public $session;

    public function __construct (SharedSessionHandler $handler) {
        $this->handler = $handler;
        $this->session = $_SESSION;
        if (!isset($this->session[NULL]))
            $this->session[NULL] = [];
    }

    public function __get ($project) {
        return $this->session[$project];
    }

    public function offsetGet ($id) {
        return $this->getKey($id)[$id];
    }

    public function __set ($project, $val) {
        $this->session[$project] = $val;
    }

    public function offsetSet ($id, $val) {
        return $this->getKey($id)[$id] = $val;
    }

    public function __isset ($project) { // don't think it should be used with empty() ...
        return isset($this->session[$project]);
    }

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

    public function __unset ($project) {
        $this->session[$project] = [];
    }

    public function offsetUnset ($id) {
            unset($this->getKey($id)[$id]);
    }

    protected function &getKey ($id) {
        return isset($this->session[NULL][$id])?$this->session[NULL]:$this->session[$this->handler->projectMapper()];
    }
}

class SharedSessionHandler extends SessionHandler { // we want to preserve write/read functions etc., only put a thin layer of abstraction between
    protected $projects = [];
    private $writing = false;
    private $tmpSessionStore;

    public function registerProject ($project_name, $base) {
        $this->projects[$base] = $project_name;
        if (!isset($_SESSION->$project_name))
            $_SESSION->$project_name = [];
    }

    public function projectMapper () {
        $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2];
        foreach ($this->projects as $base => $name) {
            if (substr_compare(realpath($base), realpath($bt["file"]), 0, strlen($base)) === 0)
                return $name;
        }
        return NULL;
    }

    public function write ($session_id, $session_data) {
        if (!$this->writing) {
            $this->writing = true;
            $this->tmpSessionStore = $_SESSION;
            $_SESSION = $_SESSION->session;
            session_write_close();
        } else {
            parent::write($session_id, $session_data);
            $_SESSION = $this->tmpSessionStore;
            $this->writing = false;
        }
    }

    public function close () { // as session_write_close() _will_ trigger this (prevent writing to closed stream)
        return true;
    }

    public function destroy ($session_id) {
        $key = $this->projectMapper();
        if ($key === null) {
            foreach ($this->projects as $project)
                unset($_SESSION->$project);
        } else {
            unset($_SESSION->$key);
        }
    }
}

session_set_save_handler($sessionHandler = new SharedSessionHandler());
session_start();
$_SESSION = new SessionAccess($sessionHandler);

If you use this, you'll have one single big session for all your projects. You don't have to change anything (except removing all the session_start()).

I suppose that every of your projects is in it's own path, so, to distinguish the different $_SESSIONs, use:

$sessionHandler->registerProject("projectName", __DIR__); // __DIR__ or the path to the project

For accessing your other sessions, use $_SESSION->projectName[$variable].

Everything that is not in any registered directory will use a same global session storage. If any key is not set in this global storage, it will take the key from your local storage - or fail with a notice.

like image 36
bwoebi Avatar answered Mar 26 '23 00:03

bwoebi