Я много искал в Интернете, но не нашел полезной подсказки.
У меня есть сервер websocket и веб-сервер, работающий вместе на моем локальном компьютере.
Мне нужно передать данные $ _SESSION на сервер websocket, когда клиент подключается к нему с помощью нового API WebSocket браузера («ws: // localhost») (запрос отправляется на веб-сайт с использованием обратного прокси-сервера, который знает это когда получает запросы с заголовком «Upgrade»).
Дело в том, что клиенты успешно подключаются к серверу ws, но мне нужно также восстановить их данные SESSION, используя переменные $ _SESSION, установленные веб-сервером HTTP.
На самом деле это моя ситуация (я использую библиотеку Ratchet):
use Ratchet\Server\IoServer; use Ratchet\Http\HttpServer; use Ratchet\WebSocket\WsServer; use MyApp\MyAppClassChat; require dirname(__DIR__) . '/vendor/autoload.php'; $server = IoServer::factory(new HttpServer(new WsServer(new MyAppClass())), 8080); $server->run();
MyAppClass очень прост:
<?php namespace MyAppClass; use Ratchet\MessageComponentInterface; use Ratchet\ConnectionInterface; 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 disconnected\n"; } public function onError(ConnectionInterface $conn, \Exception $e) { echo "An error has occurred: {$e->getMessage()}\n"; $conn->close(); } }
Есть ли способ сделать это с моим фактическим макетом или мне нужно настроить apache для использования модуля mod_proxy_wstunnel?
Спасибо за помощь!!!
Как показывают другие ответы StackOverflow ( Ratchet без сеанса Symfony , начиная сеанс в соединении с храповым websocket ), нет возможности напрямую делиться переменной $ _SESSION между Apache и процессом Ratchet. Однако можно начать сеанс с сервера Apache, а затем получить доступ к куки-файлу сеанса в коде Ratchet.
Сервер index.html сервера Apache запускает сеанс:
<?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=$sessionId\r\n" ) ); $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);