4

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

Raidri
  • 17,258
  • 9
  • 62
  • 65
Mehran
  • 15,593
  • 27
  • 122
  • 221
  • In the list of Session functions on the PHP Manual, there is no such function given to access those values. Visit http://www.php.net/manual/en/ref.session.php – Hanky Panky Jun 20 '13 at 07:41
  • This does not make any sense to me. If you are running a PHP-Session, the `$_SESSION` is always present. Do not need to load anything specific. – herrhansen Jun 20 '13 at 07:42
  • I'll update my question so it makes sense. – Mehran Jun 20 '13 at 07:44
  • What do you mean by `it is feasible that they overwrite each other` ?? don't forget session are accessed via sessionID which is unique ? – Baba Jun 23 '13 at 13:10
  • Due to different session names, different projects will have different session ids. Which will help them have their own session storage and this is the key for them not to overwrite each other's sessions. Now I need to access session data of different projects all at once. – Mehran Jun 23 '13 at 13:15
  • Perhaps it helps if I say the projects are all in the same host (the same domain). – Mehran Jun 23 '13 at 13:19
  • Nice eyes. Not match for mine though. – Madara's Ghost Jun 23 '13 at 16:30
  • @MadaraUchiha: Thanks. It might not be a match for yours but it has played its role. – Mehran Jun 23 '13 at 16:58

4 Answers4

5

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;
Peter Pivarc
  • 469
  • 2
  • 6
2

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.

bwoebi
  • 23,637
  • 5
  • 58
  • 79
  • Thank you so much for your effort. But what if some project is using some another session handler itself? What I am looking for is to find a way to fool PHP to start session within a request multiple times, with different session ids each time. That way I won't care how each project handles its session. – Mehran Jun 23 '13 at 16:48
  • @Mehran you cannot do what you'd like without some restrictions to your application(s); there's some hack needed. And most projects don't have their own SessionHandler. – bwoebi Jun 23 '13 at 16:50
  • I know I can not have everything I want (my dad thought me that :)) but it doesn't mean I can not wish for it. ZendFramework comes with a decent SessionHandler, I've never used it myself (I wrote my own) but since ZF is pretty popular among PHP developers it should not be far from truth if I say there are more projects using SessionHandlers than you think. – Mehran Jun 23 '13 at 16:56
  • @Mehran you wish too much ;-P ... But ZF's SessionHandler is, at a first look, mainly for using memcache, database saving etc. nothing that would change an applications behaviour if overwritten by your own SessionHandler. (would only make it slightly slower as my SessionHandler uses disk storage here) – bwoebi Jun 23 '13 at 17:00
  • That's what my question states: each project is free to use whatever handler it wants (file, database etc). I want to touch other projects as minimum as possible. – Mehran Jun 23 '13 at 17:05
  • @Mehran should I have written _impossible_ instead of answering this? The only little restriction I impose here is: no other SessionHandler. And remove all `session_start();` (quick find&replace) (Btw. what would you do if you'd have two projects with two different SessionHandlers here?!) – bwoebi Jun 23 '13 at 17:11
  • I'm sorry if my words sound offensive, I really don't mean that. I really appreciate your time. It's just not the answer that I'm looking for. Perhaps you are right that what I'm looking for is impossible, I was just hoping someone point me to a hack that I couldn't think of myself. What I'm looking for is for each project to operate as it always does while I can use its session data without forcing it to use my SessionHandler. All I want is to restart the session. – Mehran Jun 23 '13 at 17:21
  • @Mehran I'd wonder if there's another solution (less hacky than mine and putting similar restrictions). We'll see. The bounty will be a week here; and when no other better answer is here, I think I'm right? (and have deserved the bounty?) – bwoebi Jun 23 '13 at 17:25
  • Claiming the bounty has nothig to do with being the right answer necessarly. So don't lose hope yet :). – Mehran Jun 24 '13 at 03:15
  • It's possible, but not easy. PHP don't have ready solution fo that. So you can find/write custom PHP extension on C which will work with sessions like you want. This extension can extend current PHP session mechanizm (/usr/lib/php/modules/session.so). – ToxaBes Jun 24 '13 at 08:09
  • @ToxaBes This is the only real option to do exactly what TO wants, without any restriction: writing a module. But this is nothing you write in two hours and everything works like it should... (= too much work for the SO-user; then it would be better to hire some dev) – bwoebi Jun 24 '13 at 14:34
  • 1
    @ bwoebi - fully agree with you. TO search the way how to do what he want. I just show one of correct ways. But writing solution takes few days for C developer. @ Mehran - try to add next tags to your question: c, php-internals, php-extension. Here is good answer how you can start: http://stackoverflow.com/questions/5631231/how-to-write-php-module-in-c – ToxaBes Jun 24 '13 at 19:40
  • @ToxaBes Yeah, you're right, except, it only takes a few days if this PHP dev has no idea about the PHP core when starting. I think I could write this in 8-12 hours... – bwoebi Jun 24 '13 at 20:01
  • @ bwoebi 8-12 working hours is few days for me ) If you want, go ahead and do that. – ToxaBes Jun 24 '13 at 20:08
  • @ToxaBes no, I don't have so much time just for one SO question ^^ – bwoebi Jun 24 '13 at 20:23
0

Use SessionHandler class and its method read($session_id).

See more here: http://www.php.net/manual/en/class.sessionhandler.php

Michael Sivolobov
  • 12,388
  • 3
  • 43
  • 64
0

If your projects work on one server, you can find where is this sessions stored and try to read it manually without loading PHP instance (php is just an example). For example, all php sessions located by path which saved in session.save_path variable in php.ini. So you can read this variable (parse it by some script [bash?]) and then read session as common files. For perl it depends of session module what will be used in project. In any case in the end it will be some folder with files in server file system. And you will need to make own parsing rule for all projects which use different languages.

ToxaBes
  • 1,587
  • 8
  • 17
  • Not all projects make use of files as session storage. And not all session data are read that easily (they might be encrypted). My answer relies on switching sessions among two sessions ids within the same request. Just as you are calling session_start twice. – Mehran Jun 24 '13 at 03:21