2014-04-22 11 views
5

Ho cercato molto sul web ma non ho trovato un indizio utile.

Ho un server WebSocket e un server Web in esecuzione insieme sul mio computer locale.

Ho bisogno di passare i dati $ _SESSION al server websocket quando un client si connette ad esso utilizzando il nuovo WebSocket dell'API del browser ("ws: // localhost") '(la richiesta viene inviata al websocket utilizzando un proxy inverso , che lo conosce quando riceve richieste con un'intestazione "Aggiorna").

Il punto è che i client si connettono correttamente al server ws, ma ho bisogno di recuperare anche i loro dati SESSION utilizzando le variabili $ _SESSION settate dal server web HTTP.

In realtà la mia situazione è questa (sto usando la libreria di 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(); 

Il MyAppClass è molto semplice:

<?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(); 
    } 
} 

C'è un modo per farlo con il mio layout attuale o dovrei configurare apache per usare il modulo mod_proxy_wstunnel ?

Grazie per l'aiuto !!!

risposta

8

Come mostrato da altre risposte StackOverflow (Ratchet without Symfony session, Starting a session within a ratchet websocket connection), non è possibile condividere direttamente la variabile $ _SESSION tra Apache e il processo Ratchet. È possibile, tuttavia, avviare una sessione con il server Apache e quindi accedere al cookie di sessione all'interno del codice Ratchet.

index.html del

Apache server avvia la sessione:

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

codice Ratchet MessageComponentInterface accede al token di sessione:

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

Una volta che entrambi i server sanno token di sessione dell'utente, possono utilizzare il token per condividere le informazioni attraverso un database MySQL (che è quello che faccio):

# 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(); 

In alternativa, si potrebbe fare una forma più esotica di comunicazione tra processi: "Chiedi processo di Apache su utente con cookie"

# 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); 
+0

molto intelligente, ma che cosa si intende come puoi ottenere questo? Voglio dire, se non utilizzo un DB per le sessioni, ho bisogno in qualche modo che il server WebSocket chieda a PHP di recuperare la sessione del mittente corrente usando l'id di sessione. Presumo che questo sarebbe il modo sbagliato, ho ragione? 'public function onMessage (ConnectionInterface $ from, $ msg) { $ sessionId = $ from-> WebSocket-> request-> getCookies() ['PHPSESSID']; session_id ($ sessionId); session_start(); echo $ _SESSION ['somekey']; } ' È affidabile? – tonix

+0

Non penso che si possa chiamare session_start() all'interno del server websocket; solo il server Apache può impostare il token di sessione perché il comando set cookie deve andare nell'intestazione della pagina web. Una volta che entrambi i server hanno il token di sessione, sta a te decidere come comunicare i dati della sessione tramite il token di sessione.Poiché Apache e Ratchet sono entrambi server, è possibile "servire" i dati da un processo a un altro rimappando da soli. – dmiller309

+0

Mi spiace di non aver capito, ho capito che non posso usare sesssion_start() come suppongo, ma per fare in modo che Apache e Ratchet comunichino tra loro cosa dovrei implementare? Un servizio web che viene chiamato da Ratchet e indirizzato ad Apache per ottenere i dati corretti in base all'identificatore di sessione o cosa? Grazie per la vostra attenzione e interesse! – tonix

Problemi correlati