Problem with SessionProvider

403 views
Skip to first unread message

lukas...@gmail.com

unread,
Feb 3, 2015, 2:57:51 PM2/3/15
to ratch...@googlegroups.com
I'm having a problem with the SessionProvider module to read session data. Both servers are in the same domain. This is the code:

index.php
<?php
require __DIR__.'/vendor/php/autoload.php';

use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler;

$redis
= new Redis();
$redis
->connect('127.0.0.1:6379');

$storage
= new NativeSessionStorage(array(), new RedisSessionHandler($redis,array(),"PHPREDIS_SESSION"));
$session
= new Session($storage);
$session
->start();
$session
->set( "name", "Lucas" );
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Document</title>
<script>
var conn = new WebSocket('ws://www.nstock.com.ar:8080');
conn
.onopen = function(e) {
    console
.log("Connection established!");
};
conn
.onmessage = function(e) {
    console
.log(e.data);
};
</script>
</head>
<?php
var_dump
( $_SESSION );
var_dump
( $session->all() );
?>
<body>
</body>
</html>

OUTPUT var_dump():
array(3) {
  ["_sf2_attributes"]=>
  &array(1) {
    ["name"]=>
    string(5) "Lucas"
  }
  ["_sf2_flashes"]=>
  &array(0) {
  }
  ["_sf2_meta"]=>
  &array(3) {
    ["u"]=>
    int(1422985597)
    ["c"]=>
    int(1422977071)
    ["l"]=>
    string(1) "0"
  }
}
array(1) {
  ["name"]=>
  string(5) "Lucas"
}

Linux Redis:
root@ubuntu:/usr/share/nginx/html# redis-cli
127.0.0.1:6379> KEYS *
1) "PHPREDIS_SESSION:lvb0bqcen2ngmkf77pfmmqsui6"
127.0.0.1:6379> get PHPREDIS_SESSION:lvb0bqcen2ngmkf77pfmmqsui6
"\x84\xc0\x01\xaf_sf2_attributes\x82\xc0\x01\xa4name\xa5Lucas\xac_sf2_flashes\x90\xa9_sf2_meta\x84\xc0\x01\xa1u\xceT\xd1\t}\xa1c\xceT\xd0\xe8/\xa1l\xa10"


As you can see, session is stored and retrieved with no problem.

MyApp.php
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class MyApp implements MessageComponentInterface {
   
public function onOpen(ConnectionInterface $conn) {
        var_dump
( $conn->WebSocket->request->getCookies() );
        var_dump
( $conn->Session );
        $conn
->send( "Hello!" );
   
}
   
   
public function onMessage(ConnectionInterface $from, $msg) {
   
}
   
   
public function onClose(ConnectionInterface $conn) {
   
}
   
   
public function onError(ConnectionInterface $conn, \Exception $e) {
   
}
}
?>

OUTPUT var_dump( $conn->WebSocket->request->getCookies() ):
array(1) {
 
["PHPSESSID"]=>
 
string(26) "lvb0bqcen2ngmkf77pfmmqsui6"
}

Cookies are being sent with no problem either: http://image.gxzone.com/images/4/7/47ea267dd88.png

But $conn->Session don't have the value for "name".

OUTPUT var_dump( $conn->Session ):
object(Symfony\Component\HttpFoundation\Session\Session)#76 (3) {
 
["storage":protected]=>
 
object(Ratchet\Session\Storage\VirtualSessionStorage)#77 (6) {
   
["_serializer":protected]=>
   
object(Ratchet\Session\Serialize\PhpHandler)#9 (0) {
   
}
   
["bags":protected]=>
    array
(2) {
     
["attributes"]=>
     
object(Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag)#80 (3) {
       
["name":"Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag":private]=>
       
string(10) "attributes"
       
["storageKey":"Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag":private]=>
       
string(15) "_sf2_attributes"
       
["attributes":protected]=>
        array
(0) {
       
}
     
}
     
["flashes"]=>
     
object(Symfony\Component\HttpFoundation\Session\Flash\FlashBag)#81 (3) {
       
["name":"Symfony\Component\HttpFoundation\Session\Flash\FlashBag":private]=>
       
string(7) "flashes"
       
["flashes":"Symfony\Component\HttpFoundation\Session\Flash\FlashBag":private]=>
        array
(0) {
       
}
       
["storageKey":"Symfony\Component\HttpFoundation\Session\Flash\FlashBag":private]=>
       
string(12) "_sf2_flashes"
     
}
   
}
   
["started":protected]=>
   
bool(false)
   
["closed":protected]=>
   
bool(false)
   
["saveHandler":protected]=>
   
object(Ratchet\Session\Storage\Proxy\VirtualProxy)#78 (6) {
     
["_sessionId":protected]=>
     
string(26) "lvb0bqcen2ngmkf77pfmmqsui6"
     
["_sessionName":protected]=>
     
string(9) "PHPSESSID"
     
["handler":protected]=>
     
object(Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler)#7 (8) {
       
["redis":protected]=>
       
object(Redis)#2 (1) {
         
["socket"]=>
          resource
(11) of type (Redis Socket Buffer)
       
}
       
["ttl":protected]=>
       
int(0)
       
["prefix":protected]=>
       
string(16) "PHPREDIS_SESSION"
       
["locking":"Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler":private]=>
       
bool(true)
       
["locked":"Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler":private]=>
       
bool(false)
       
["lockKey":"Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler":private]=>
        NULL
       
["spinLockWait":"Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler":private]=>
       
int(150000)
       
["lockMaxWait":"Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler":private]=>
       
int(30)
     
}
     
["wrapper":protected]=>
     
bool(false)
     
["active":protected]=>
     
bool(false)
     
["saveHandlerName":protected]=>
     
string(4) "user"
   
}
   
["metadataBag":protected]=>
   
object(Symfony\Component\HttpFoundation\Session\Storage\MetadataBag)#79 (5) {
     
["name":"Symfony\Component\HttpFoundation\Session\Storage\MetadataBag":private]=>
     
string(10) "__metadata"
     
["storageKey":"Symfony\Component\HttpFoundation\Session\Storage\MetadataBag":private]=>
     
string(9) "_sf2_meta"
     
["meta":protected]=>
      array
(3) {
       
["c"]=>
       
int(0)
       
["u"]=>
       
int(0)
       
["l"]=>
       
int(0)
     
}
     
["lastUsed":"Symfony\Component\HttpFoundation\Session\Storage\MetadataBag":private]=>
      NULL
     
["updateThreshold":"Symfony\Component\HttpFoundation\Session\Storage\MetadataBag":private]=>
     
int(0)
   
}
 
}
 
["flashName":"Symfony\Component\HttpFoundation\Session\Session":private]=>
 
string(7) "flashes"
 
["attributeName":"Symfony\Component\HttpFoundation\Session\Session":private]=>
 
string(10) "attributes"
}


In fact, if I do a var_dump( $conn->Session->all() ) it crashes (it seems that there is no method called "all()")

This is the source code of my server:

server.php
<?php
require __DIR__.'/vendor/php/autoload.php';

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Session\SessionProvider;
use Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler;
use Ratchet\App;

$redis
= new Redis();
$redis
->connect('127.0.0.1:6379');

$server
= IoServer::factory(
   
new HttpServer(
       
new WsServer(
           
new SessionProvider(
               
new MyApp,
               
new RedisSessionHandler($redis,array(),"PHPREDIS_SESSION")
           
)
       
)
   
),
   
8080
);
       
$server
->run();
?>

I tried everything with no success... any clues?

cboden

unread,
Feb 3, 2015, 6:41:53 PM2/3/15
to ratch...@googlegroups.com, lukas...@gmail.com
Unfortunately Ratchet can not support native session storage. 
...

lukas...@gmail.com

unread,
Feb 3, 2015, 9:21:43 PM2/3/15
to ratch...@googlegroups.com, lukas...@gmail.com
Thanks for your answer cboden, but I don't understand what to change to fix the code. Is it possible to use Redis to store the session data and share it between the web server and the websocket server? How should I do not to use NativeSessionStorage? Like this?

<?php
require __DIR__.'/vendor/php/autoload.php';

use Symfony\Component\HttpFoundation\Session\Session;

$session
= new Session();

$session
->start();
$session
->set( "name", "Lucas" );
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Document</title>
<script>
var conn = new WebSocket('ws://www.nstock.com.ar:8080');
conn
.onopen = function(e) {
    console
.log("Connection established!");
};
conn
.onmessage = function(e) {
    console
.log(e.data);
};
</script>
</head>
<?php
var_dump
( $_SESSION );
var_dump
( $session->all() );
?>
<body>
</body>
</html>

It would be very helpful if you could write a short and simple example, I read a lot of questions regarding sessions and I saw many source codes using NativeSessionSorage, that's why I thought this was the correct way to do it.

lukas...@gmail.com

unread,
Feb 4, 2015, 4:07:16 PM2/4/15
to ratch...@googlegroups.com, lukas...@gmail.com
Hi cboden, I finally found out what was the problem.

1) You should fix the examples because none of them are in try/catch blocks. The problem was not the Native* sessions handlers, the code was ok, the problem was that I'm using msgpack as a session serialize handler, but I wasn't catching the RuntimeException that SessionProvider could throw. I know that I should do it always, but when you start using a library you don't know, you just copy/paste example code and start trying new thing from there.

2) You should also enumerate somewere in your site which serializers Ratchet supports. Php and PhpBinary are the most common, but msgpack and igbinary are also very common! Redis, Pinterest and other very popular sites use msgpack to serialiaze their data.

3) I'm running Nginx with php-fpm. The php.ini of the php-fpm is not the same as php-cli (this is on Ubuntu at least). When the SessionProvider checks the value of the serializer with ini_get('session.serialize_handler'), the value returned is the one in the php.ini of the php-cli. This is because we run the websocket server from command line. The problem is that this value could or could not be the same as the value in php.ini that process the requests of the webserver, which is the php-fpm. It would be nice if you write a warning about this because it seems it's pretty common (http://stackoverflow.com/a/10665920)

4) This is simple, but it works. Maybe you could add it to Ratchet :)

<?php
namespace Ratchet\Session\Serialize;

class MsgpackHandler implements HandlerInterface {

   
function serialize(array $data) {
       
throw new \RuntimeException("Serialize PhpHandler:serialize code not written yet, write me!");
   
}

   
public function unserialize($raw) {
       
return msgpack_unpack($raw);
   
}
}
?>


Cheers!
...

cboden

unread,
Mar 3, 2015, 12:16:19 PM3/3/15
to ratch...@googlegroups.com, lukas...@gmail.com
Thanks for the info Lukas. I've created a ticket and will update the documentation. 
Reply all
Reply to author
Forward
0 new messages