7

I have a PHP websocket server (https://github.com/lemmingzshadow/php-websocket/).

When an user connects, I want to set/get some session data.

The problem is that I can't use $_SESSION because if I do that, instead of clients' session I get the session of my websocket server.

I have managed to get clients' SESSID:

private function handshake($data) { 
    $this->log('Performing handshake');  
    if(preg_match("/PHPSESSID=(.*?)(?:;|\r\n)/", $data, $matches)){
        $sessid = $matches[1];
    }
    /* Do handshake */
}

But now I don't know how to get the session data related to that SESSID.

Steven V
  • 16,357
  • 3
  • 63
  • 76
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • 2
    Sounds like you need some sort of session database that allows you to share sessions between the two instances. – Steven V Aug 09 '13 at 17:19
  • @StevenV But, must I use my own db, or can I access the db where php saves session data? – Oriol Aug 09 '13 at 17:22
  • have the client send their session ID over the socket, then you can use it to set the ID in php before doing session_start – Marc B Aug 09 '13 at 17:28
  • 1
    PHP just stores files in a directory for sessions, no database used. You maybe able to use [`session_id()`](http://php.net/manual/en/function.session-id.php) and/or [`session_save_path()`](http://php.net/manual/en/function.session-save-path.php) to gain access to the session directory and set the session ID. You do have to be on the same physical server, and even then it may or may not work (especially with permissions). If all else fails, you'll need your own database to handle the session data. – Steven V Aug 09 '13 at 17:30
  • 2
    Permissions are not the problem, but session locking is. There can only be one instance of PHP running that has access to the session file. The best idea would be to actually pass necessary data via the connection instead of reading it from the session. – Sven Aug 09 '13 at 17:42
  • @Sven You were right, session locking prevented me from using `session_start` in other scripts after websocket server used it. But I have solved it with `session_write_close()` – Oriol Aug 09 '13 at 23:06

1 Answers1

5

It seems I have solved it (but I have to test it more):

private function handshake($data) { 
    $this->log('Performing handshake');
    if(preg_match("/PHPSESSID=(.*?)(?:;|\r\n)/", $data, $matches)){
        $this->sessID = $matches[1];
        session_id($this->sessID);
        @session_start();
        if(isset($_SESSION['userName'])){
            $this->userName = $_SESSION['userName'];
        }else{
            $_SESSION['userName'] = $this->userName;
        }
        session_write_close();
    }else{
        $this->log('No SESSID');    
        return false;
    }
    /* Do handshake */
}

And to enable session cookies, on my client page index.php

<?php
session_start();
?>
<!DOCTYPE html>
<!-- Page's HTML -->

Explanation

First, I use session_id so that the following session_start() will give me the session related to the given SESSID.

Then, I can use @session_start() to start the session. It needs @ because the websocket server has already started, so not using it produces:

  • PHP Warning: session_start(): Cannot send session cookie - headers already sent
  • PHP Warning: session_start(): Cannot send session cache limiter - headers already sent

Now I can do what I want with $_SESSION.

Finally, I use session_write_close() in order to close the session. It must be used because:

  • session_id must be called before session_start(). If the session isn't closed, when a second client connects, a session will be already open, so session_id won't work.

  • To avoid session locking. As @Sven said, there can only be one instance of PHP running that has access to the session file. Since the websocket server's script should be running for a long time, once it opens a session, you can't use session in other scripts if you don't close it.

Oriol
  • 274,082
  • 63
  • 437
  • 513
  • @Oriol You can also use `session_start(['read_and_close' => true]);` to immediately close the session and avoid session locking. – ubomb Oct 16 '15 at 20:54
  • @Oriol Er... nevermind. That's what it claims to do in the docs, but it seems that it still keeps it open during testing. `session_write_close();` does work in my testing though. – ubomb Oct 16 '15 at 21:46
  • @ubomb It seems the `options` parameter is added in PHP 7, which is still unstable. Note it will prevent writing session data, so it will be useful only to read data. – Oriol Oct 16 '15 at 22:16
  • @Oriol One of the best answers I ever saw on stackoverflow. You saved my life so thank you so much! – Piet Sep 05 '16 at 19:01
  • session_id(): Cannot change session id when headers already sent –  Apr 13 '21 at 17:34