2011-08-23 29 views
30

¿Existe una biblioteca o cliente para conectarse a un servidor WebSocket desde PHP? Si no, ¿hay alguna razón por la cual?Cliente WebSocket en PHP?

(phpwebsocket sólo parecen tener código de cliente Javascript.)

+0

También necesitaba un PHP Websocket Client y no encontré uno, así que hice mi propia pequeña clase PHP. Con suerte lo ayudará: Github: https://github.com/lemmingzshadow/php-websocket Publicación del blog (alemán): http://lemmingzshadow.net/379/php-websocket-client/ – lemmingzshadow

Respuesta

7

así, es fácil y se puede hacer en este Gracias a todas las fuentes de donde nos encontramos respuestas (lo siento, no puedo recordar todos)

<?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

Esta respuesta está desactualizada . Muchos servidores requieren el encabezado 'Sec-WebSocket-Version' en el handshake. – singpolyma

+0

Esta respuesta también solo funciona para paquetes únicos. Para las transmisiones enteras, el 'fread' puede comerse en el siguiente paquete – singpolyma

+1

basado en esta publicación: https://gist.github.com/ZiTAL/40bb7bafad693dc99c5c – ZiTAL

20

Ninguno de los anteriores es una buena respuesta. Varios de ellos son sobre un servidor, mientras que la pregunta es sobre un cliente. El código de Rodislav no funcionó para mí, ya que no hablaba con mi servidor WebSockets en Heroku. Sin embargo, esta biblioteca funcionó muy bien:

https://github.com/Devristo/phpws

ACTUALIZACIÓN: Si bien este código funcionaba cuando todo iba bien, no parece haber ningún retorno de error o excepciones en absoluto, y como resultado es inutilizable cuando hay un error (por ejemplo, el servidor no se está ejecutando, la dirección es incorrecta, el puerto está bloqueado, etc.). Por lo tanto, aunque fue divertido experimentar, no es utilizable en el código de producción.

+2

Esto debe marcarse como la solución, ¡gracias! – P0rnflake

+0

Correcto: la pregunta es sobre usar un servidor php como cliente para otro servidor, no cómo escribir un servidor php websocket. – noderman

2

Una biblioteca de PHP WebSocket con un ejemplo de aplicación de chat. Con demostración y descripción completa de la implementación.

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

+0

Desafortunadamente ese nombre de dominio expiró ... –

+0

@GwynethLlewelyn, el enlace se ha actualizado, ya está disponible. –

+1

Este es un ejemplo para crear un servidor websocket php, pero la pregunta es cómo crear un cliente en php para enviar datos a otro websocket (remoto/local). –

1

He intentado utilizar muchos de los anteriores para incluir en tivoka (JSON-RPC), pero, o no era lo suficientemente buena lectura de los paquetes más grandes (no conseguir todo el marco o la lectura en la siguiente) o tenía grandes dependencias.

Así, escribí https://github.com/Textalk/websocket-php

En lugar de primera lectura de todos los datos disponibles de la toma y luego descifrarlo, lee el encabezado de la trama y analiza longitud de carga útil, y luego cargas sólo eso.

Carece de soporte para ping/pong, pero creo que hace bien la mayoría de las otras cosas. Funciona bien con tivoka y tiene al menos un 92% de autotestas :) Puede necesitar algunas funciones adicionales para verificar si hay otro marco sin leerlo realmente.

Déjame saber lo que piensas.

+0

No funciona – Volatil3

+0

¡gracias! Funciona muy bien ... y muy sencillo de usar e instalar. Una sugerencia es que en la sección de ejemplo, debe especificar que el método send() a menudo se usa para comandos 'suscribir', no para enviar 'hello world' :) Aparte de eso, ¡buen trabajo! –