2011-08-23 12 views
30

Esiste una libreria o un client per la connessione a un server WebSocket da PHP? Se no, c'è una ragione per cui?Client WebSocket in PHP?

(phpwebsocket solo sembrano avere codice client JavaScript.)

+0

Avevo anche bisogno di un client Websocket PHP e non ne ho trovato uno, quindi ho creato la mia piccola classe PHP. Speriamo che ti possa aiutare: Github: https://github.com/lemmingzshadow/php-websocket Post del blog (tedesco): http://lemmingzshadow.net/379/php-websocket-client/ – lemmingzshadow

risposta

7

bene, è facile e si può fare in questa Grazie a tutte le fonti in cui abbiamo trovato le risposte (mi dispiace, non riesco a ricordare tutti)

<?php 
$host = '10.9.8.173'; //where is the websocket server 
$port = 8575; 
$local = "http://mypc"; //url where this script run 
$data = "first message"; //data to be send 

$head = "GET/HTTP/1.1"."\r\n". 
     "Upgrade: WebSocket"."\r\n". 
     "Connection: Upgrade"."\r\n". 
     "Origin: $local"."\r\n". 
     "Host: $host"."\r\n". 
     "Sec-WebSocket-Key: asdasdaas76da7sd6asd6as7d"."\r\n". 
     "Content-Length: ".strlen($data)."\r\n"."\r\n"; 
//WebSocket handshake 
$sock = fsockopen($host, $port, $errno, $errstr, 2); 
fwrite($sock, $head) or die('error:'.$errno.':'.$errstr); 
$headers = fread($sock, 2000); 
echo $headers; 
fwrite($sock, hybi10Encode($data)) or die('error:'.$errno.':'.$errstr); 
$wsdata = fread($sock, 2000); 
var_dump(hybi10Decode($wsdata)); 
fclose($sock); 


function hybi10Decode($data) 
{ 
    $bytes = $data; 
    $dataLength = ''; 
    $mask = ''; 
    $coded_data = ''; 
    $decodedData = ''; 
    $secondByte = sprintf('%08b', ord($bytes[1])); 
    $masked = ($secondByte[0] == '1') ? true : false; 
    $dataLength = ($masked === true) ? ord($bytes[1]) & 127 : ord($bytes[1]); 

    if($masked === true) 
    { 
     if($dataLength === 126) 
     { 
      $mask = substr($bytes, 4, 4); 
      $coded_data = substr($bytes, 8); 
     } 
     elseif($dataLength === 127) 
     { 
      $mask = substr($bytes, 10, 4); 
      $coded_data = substr($bytes, 14); 
     } 
     else 
     { 
      $mask = substr($bytes, 2, 4);  
      $coded_data = substr($bytes, 6);   
     } 
     for($i = 0; $i < strlen($coded_data); $i++) 
     {  
      $decodedData .= $coded_data[$i]^$mask[$i % 4]; 
     } 
    } 
    else 
    { 
     if($dataLength === 126) 
     {   
      $decodedData = substr($bytes, 4); 
     } 
     elseif($dataLength === 127) 
     {   
      $decodedData = substr($bytes, 10); 
     } 
     else 
     {    
      $decodedData = substr($bytes, 2);  
     }  
    } 

    return $decodedData; 
} 


function hybi10Encode($payload, $type = 'text', $masked = true) { 
    $frameHead = array(); 
    $frame = ''; 
    $payloadLength = strlen($payload); 

    switch ($type) { 
     case 'text': 
      // first byte indicates FIN, Text-Frame (10000001): 
      $frameHead[0] = 129; 
      break; 

     case 'close': 
      // first byte indicates FIN, Close Frame(10001000): 
      $frameHead[0] = 136; 
      break; 

     case 'ping': 
      // first byte indicates FIN, Ping frame (10001001): 
      $frameHead[0] = 137; 
      break; 

     case 'pong': 
      // first byte indicates FIN, Pong frame (10001010): 
      $frameHead[0] = 138; 
      break; 
    } 

    // set mask and payload length (using 1, 3 or 9 bytes) 
    if ($payloadLength > 65535) { 
     $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8); 
     $frameHead[1] = ($masked === true) ? 255 : 127; 
     for ($i = 0; $i < 8; $i++) { 
      $frameHead[$i + 2] = bindec($payloadLengthBin[$i]); 
     } 

     // most significant bit MUST be 0 (close connection if frame too big) 
     if ($frameHead[2] > 127) { 
      $this->close(1004); 
      return false; 
     } 
    } elseif ($payloadLength > 125) { 
     $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8); 
     $frameHead[1] = ($masked === true) ? 254 : 126; 
     $frameHead[2] = bindec($payloadLengthBin[0]); 
     $frameHead[3] = bindec($payloadLengthBin[1]); 
    } else { 
     $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength; 
    } 

    // convert frame-head to string: 
    foreach (array_keys($frameHead) as $i) { 
     $frameHead[$i] = chr($frameHead[$i]); 
    } 

    if ($masked === true) { 
     // generate a random mask: 
     $mask = array(); 
     for ($i = 0; $i < 4; $i++) { 
      $mask[$i] = chr(rand(0, 255)); 
     } 

     $frameHead = array_merge($frameHead, $mask); 
    } 
    $frame = implode('', $frameHead); 
    // append payload to frame: 
    for ($i = 0; $i < $payloadLength; $i++) { 
     $frame .= ($masked === true) ? $payload[$i]^$mask[$i % 4] : $payload[$i]; 
    } 

    return $frame; 
} 

?> 
+0

Questa risposta non è aggiornata . Molti server richiedono l'intestazione 'Sec-WebSocket-Version' nell'handshake. – singpolyma

+0

Questa risposta funziona anche solo per pacchetti una tantum. Per interi flussi, il 'fread' può mangiare nel pacchetto successivo – singpolyma

+1

basato su questo post: https://gist.github.com/ZiTAL/40bb7bafad693dc99c5c – ZiTAL

20

Nessuno dei precedenti è una buona risposta. Molti di loro riguardano un server, mentre la domanda riguarda un cliente. Il codice di Rodislav non ha funzionato per me, dal momento che non parlava al mio server WebSockets su Heroku. Tuttavia, questa libreria ha funzionato molto bene:

https://github.com/Devristo/phpws

UPDATE: Anche se questo codice ha funzionato quando tutto andava bene, sembra che ci sia nessun ritorni di errore o eccezioni a tutti, e di conseguenza è inutilizzabile quando c'è un errore (ad esempio, il server non è in esecuzione, l'indirizzo è errato, la porta è bloccata, ecc.). Quindi, mentre è stato divertente sperimentare, non è utilizzabile nel codice di produzione.

+2

Questo dovrebbe essere contrassegnato come la soluzione, grazie! – P0rnflake

+0

Corretto: la domanda riguarda l'utilizzo di un server php come client su un altro server, non su come scrivere un server websocket php. – noderman

2

Una libreria PHP websocket con un esempio di applicazione di chat. Con demo e descrizione completa dell'implementazione.

http://www.techzonemind.com/php-websocket-library-two-way-real-time-communication/

+0

Sfortunatamente quel nome di dominio è scaduto ... –

+0

@GwynethLlewelyn, il collegamento è aggiornato, è ora disponibile. –

+1

Questo è un esempio per creare un server websocket php, ma la domanda è come creare un client in php per inviare dati ad altro websocket (remoto/locale). –

1

Ho cercato di usare molti di quanto sopra da includere nel tivoka (JSON-RPC), ma o non era buono abbastanza leggere i pacchetti più grandi (non ottenere l'intera struttura o la lettura in quella successiva) o aveva grandi dipendenze.

Così, ho scritto https://github.com/Textalk/websocket-php

Invece di prima lettura tutti i dati disponibili dalla presa e poi la decodifica, si legge l'intestazione del telaio e analizza la lunghezza di carico utile, e quindi i carichi proprio questo.

Manca il supporto ping/pong, ma penso che faccia buona parte delle altre cose. Funziona bene con tivoka ed è autotest almeno al 92% :) Potrebbero essere necessarie alcune funzioni extra per verificare se c'è un altro frame senza leggerlo.

Fatemi sapere cosa ne pensate.

+0

Non funziona – Volatil3

+0

grazie! Funziona alla grande .. e molto semplice da usare e installare. Un suggerimento è che nella sezione di esempio dovresti specificare che il metodo send() è spesso usato per i comandi 'subscribe', non per inviare 'hello world' :) Oltre a questo, ottimo lavoro! –

Problemi correlati