如何将$_SESSION变量传递到websocket服务器



我在网上搜索了很多,但没有找到有用的线索。

我有一个websocket服务器和一个web服务器在我的本地机器上一起运行。

当客户端使用浏览器API"new websocket("ws://localhost")"连接到websocket服务器时,我需要将$_SESSION数据传递到该服务器(请求使用反向代理发送到该websocket,该代理在接收到带有"Upgrade"标头的请求时知道该请求)。

关键是客户端成功地连接到了ws服务器,但我还需要使用HTTP web服务器设置的$_SESSION变量来恢复它们的SESSION数据。

事实上,我的情况是这样的(我正在使用棘轮库):

use RatchetServerIoServer;
use RatchetHttpHttpServer;
use RatchetWebSocketWsServer;
use MyAppMyAppClassChat;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(new HttpServer(new WsServer(new MyAppClass())), 8080);
$server->run();

MyAppClass非常简单:

 <?php
namespace MyAppClass;
use RatchetMessageComponentInterface;
use RatchetConnectionInterface;
class MyAppClass implements MessageComponentInterface {
    protected $clients;
    public function __construct() {
        $this->clients = new SplObjectStorage;
    }
    public function onOpen(ConnectionInterface $conn) {
            /* I would like to put recover the session infos of the clients here
               but the session_start() call returns an empty array ($_SESSION variables have been previuosly set by the web server)*/
        session_start();
        var_dump($_SESSION) // empty array...
        echo "New connection! ({$conn->resourceId})n";
    }
    public function onMessage(ConnectionInterface $from, $msg) {
        $numberOfReceivers = count($this->clients) -1;
        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "n", $from->resourceId, $msg, 
                                 $numberOfReceivers, $numberOfReceivers == 1 ? '' : 's');
        $this->clients->rewind();
        while ($this->clients->valid())
        {
            $client = $this->clients->current();
            if ($client !== $from) {
                $client->send($msg);
            }
            $this->clients->next();
        }
    }
    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
        echo "Connection {$conn->resourceId} has disconnectedn";
    }
    public function onError(ConnectionInterface $conn, Exception $e) {
        echo "An error has occurred: {$e->getMessage()}n";
        $conn->close();
    }
}

有没有一种方法可以用我的实际布局做到这一点,或者我应该配置apache以便使用mod_proxy_stunnel模块?

谢谢你的帮助!!!

正如其他StackOverflow答案所示(Ratchet没有Symfony会话,在棘轮websocket连接中启动会话),Apache和Ratchet进程之间无法直接共享$_session变量。但是,可以启动与Apache服务器的会话,然后访问Ratchet代码中的会话cookie。

Apache服务器的index.html启动会话:

<?php
// Get the session ID.
$ses_id = session_id();
if (empty($ses_id)) {
    session_start();
    $ses_id = session_id();
}
?><!DOCTYPE html> ...

Ratchet MessageComponentInterface代码访问会话令牌:

public function onMessage(ConnectionInterface $from, $msg) {
    $sessionId = $from->WebSocket->request->getCookies()['PHPSESSID'];
    # Do stuff with the token...
}

一旦两个服务器都知道用户的会话令牌,他们就可以使用该令牌通过MySQL数据库共享信息(我就是这么做的):

    # Access session data from a database:
    $stmt = $this->mysqli->prepare("SELECT * FROM users WHERE cookie=?");
    $stmt->bind_param('s', $sessionId);
    $stmt->execute();
    $result = $stmt->get_result();

或者,你可以做一种更奇特的进程间通信形式:

    # Ratchet server:
    $opts = array(
        'http'=>array(
            'method'=>'GET',
            'header'=>"Cookie: PHPSESSID=$sessionIdrn"
        )
    );
    $context = stream_context_create($opts);
    $json = file_get_contents('http://localhost:80/get_session_info.php', false, $context);
    $session_data = json_decode($json);
    # Apache server's get_session_info.php
    # Note: restrict access to this path so that remote users can't dump
    # their own session data.
    echo json_encode($_SESSION);

这可能看起来有点古怪,但这是我想办法实现这一点的唯一方法。

假设您已经知道目录和sessionId,则可以直接使用session_encode()session_decode()从会话文件中读取数据,如下所示。我的会话文件以sess_为前缀,其他文件可能不是这样,所以请记住这一点。请注意,从会话文件中提取变量后,这将保存并恢复任何现有的$_SESSION数据

$contents = file_get_contents($sessionDir . 'sess_' . $sessionId);
$sessionData = $this->decodeSession($contents);
return $sessionData;
private function decodeSession($sessionString)
{
   $currentSession = session_encode();
   foreach ($_SESSION as $key => $value){
     unset($_SESSION[$key]);
   }
   session_decode($sessionString);
   $sessionVariables = $_SESSION;
   foreach ($_SESSION as $key => $value){
     unset($_SESSION[$key]);
   }
   session_decode($currentSession);
   return $sessionVariables;
}

要完成dmille309和fred的答案,我还不能发表评论:(

我不会将会话存储在数据库中,我只会使用保存会话的目录,使用session_save_path()搜索我感兴趣的会话。

public function onMessage(ConnectionInterface $from, $msg) {
    $session_file = session_save_path()."/sess_".$from->WebSocket->request->getCookies()['PHPSESSID'];
    if(!file_exists($session_file))
        // The session doesn't exist
        return ;
    $content = file_get_contents($session_file);
    $session_id = "0";
    foreach($sections = explode(";", $content) as $k => $section) {
        $data = explode("|", $section, 2);
        if(isset($data[0]) and $data[0] == "id" and isset($data[1]) and substr_count($data[1], '"') == 2) {
            $session_id = substr($data[1], strpos($data[1], '"')+1, -1);
            break;
        }
    }
    if($session_id == "0")
        // The session has no "id"
        return ;
    // ID stored in $session_id, equivalent to $_SESSION["id"]
}

注意:所有会话都以"开头;sess_;

注意2:我将会话ID存储在字符串中,所以我在引号之间获取它。

注意3:出于安全考虑,我没有使用session_decode(),因为结果存储在$_SESSION中,我认为这可能会导致种族状况。

我没有测试,如果有什么不起作用,你可以告诉我。

当然,也可以对会话中存储的其他值执行同样的操作。

相关内容

  • 没有找到相关文章

最新更新