1

I understand that command line is no web server, so you can't access $_SESSION. But I don't know what else to do.

I've been following this tutorial to create a chat using websockets: http://www.phpbuilder.com/articles/application-architecture/optimization/creating-real-time-applications-with-php-and-websockets.html

My problem is that, I do not know how to get the username of the message sender securely. I could include it in the message send function but since it's in Javascript, everyone can just edit their username to someone elses.

How could I securely get the username of the user, which is $_SESSION['username']?

var Server;
Server = new FancyWebSocket('ws://0.0.0.0:9000');
send( "test" );

I'm open to all kind of suggestions, like alternatives to websockets. I'm creating a realtime chat for my website.

1
  • 1
    The HTTP headers, including cookies, are available to the WS server during the handshake. In that specific server, the headers are available in the user class under the property $headers implemented as an array. I'll add a thorough answer later (and add a feature request to parse cookies), but that should help get you going in the right direction. Commented Jul 20, 2015 at 23:51

1 Answer 1

1

First alternative is, of course, AJAX requests. AJAX doesn't have the problems of not being able to quickly and easily access the sessions that WebSockets has. Any sufficiently frequent sample rate is indistinguishable from real time.

Now, to my rather long-winded solution implemented in WebSockets:

The HTTP headers are available to the WebSocket server during the handshake, including the cookies. In the server that you're using, PHP-Websockets, the headers are stored in the $headers property.

For instance:

var_dump($user->headers);
array(14) {
  ["get"]=>
  string(8) "/echobot"
  ["host"]=>
  string(14) "127.0.0.1:9000"
  ...snip...
  ["cookie"]=>
   string(100) "PHPSESSID=jan9uknpc06mk4ddghph4870t1; MyCookie=My+Value%21%40%23%24%25; MyNonhttponlyCookie=My+Value"
}

These cookies were generated from

session_start();
$_SESSION['Hi!'] = array('Hello!', 'where' => 'world!');
setcookie('MyCookie', 'My Value;!@#$%', 0, '/', '127.0.0.1', false, true);
setcookie('MyNonhttponlyCookie', 'My Value', 0, '/', '127.0.0.1', false, false);

Thus, the value of $user->headers['cookie'] is a semicolon and space (;) delimited collection of key value pairs, where the values are URL encoded and separated from its key with an equal sign. (PHP complains if you put reserved characters in the cookie name. Thus the cookie key can not contain any url encoded values.)

A quick way to extract these are as follows

$cookies = array();
$cookiesParts = explode('; ', $user->headers['cookie']);
foreach ($cookiesParts as $cookieParts) {
    $interimCookie = explode('=', $cookieParts);
    $cookies[$interimCookie[0]] = urldecode($interimCookie[1]);
}
var_dump($cookies);

array(3) {
  ["PHPSESSID"]=>
  string(26) "jan9uknpc06mk4ddghph4870t1"
  ["MyCookie"]=>
  string(14) "My Value;!@#$%"
  ["MyNonhttponlyCookie"]=>
  string(8) "My Value"
}

We now have the session ID. Double check with session_name(), which will give you the key of the cookie that actually holds the session ID.

We could serialize and unserialize the session file as stored in the server, which is pointed at by session_save_path()... but I want to cheat.

Because the built-in session system locks the session files, we can't just keep the session file open and constantly watch for changes, nor can we lock the file ourselves for long periods of time.

It would be ideal if we could use the __get() and __set() magic methods here in the same way we'd use the $_SESSION superglobal (such as $myUser->_session['key'] = 'value';), but PHP does not allow treating these methods as arrays. Instead, we have to set a more mundanely named method.

<?php
class MyUser extends WebSocketUser {
    public $session_id; // gets set somewhere. Good place is probably is your implementation of the `connected($user)` abstract method.

    public getSession($key) {
        session_id($this->session_id);
        session_start();
        $val = $_SESSION[$key];
        session_write_close(); // very important!
        return $val;
    }

    public setSession($key, $value) {
        session_id($this->session_id);
        session_start();
        $_SESSION[$key] = value;
        session_write_close(); // still very important!
    }
}

(Note: I'm also pointing my feature request at this question, to base my eventual implementation of cookie parsing and session handling here, so that I can remember my research tonight as I work.)

Sign up to request clarification or add additional context in comments.

8 Comments

Hi, thank you for the help! I don't really know how to implement and use the MyUser class. Could you help me out?
In your FancyWebSocket class, you'll need to assign the protected property $userClass to be the name of your new user class. Other than that, it's basic OOP.
I'm sorry but I'm not following you. I do not have a FancyWebSocket class, I have a PHPWebSocket class. And there's nothing called $userClass in any of my files?
@kopa Sorry, was looking at the snippet of JS you shared above, and assumed you'd named your PHP class the same, which is where the FancyWebSocket came from. When you said you were following the tutorial from phpbuilder.com/articles/application-architecture/optimization/… ... Did you mean the only actual tutorial on that page, which uses github.com/ghedipunk/PHP-Websockets ? Or, did you mean one of the several others listed as alternatives?
That certainly looks like a valid PHP session ID. Give it a try and see what you get.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.