* @version 2011-10-18 */class websocketclient{private $_host;private $_port;private $_path;private $_origin;private $_ Socket = null;private $_connected = false;public function __construct () {}public function __destruct () {$this->disconn ECT ();} Public Function SendData ($data, $type = ' text ', $masked = True) {if ($this->_connected = = = False) {Trigger_error ("not con Nected ", e_user_warning); return false;} if (!is_string ($data)) {Trigger_error ("not a string data is given.", e_user_warning); return false;} if (strlen ($data) = = 0) {return false;} $res = @fwrite ($this->_socket, $this->_hybi10encode ($data, $type, $masked)); if ($res = = = 0 | | $res = = = False) {return false;} $buffer = ", while ($buffer!==") {$buffer = Fread ($this->_socket, 512);} return true;} Public function Connect ($host, $port, $path, $origin = False) {$this->_host = $host; $this->_port = $port; $this->_ Path = $path; $this->_origin = $origin; $key = Base64_encode ($this->_generaterandomstring (+, False, True)); $heAder = "GET". $path. "http/1.1\r\n"; $header. = "Host:". $host. ":". $port. " \ r \ n "; $header. =" upgrade:websocket\r\n "; $header. =" connection:upgrade\r\n ";//$header. =" Sec-websocket-extensions: Permessage-deflate; Client_max_window_bits\r\n "; $header. =" Sec-websocket-key: ". $key. "\ r \ n", if ($origin!== false) {$header. = "Sec-websocket-origin:". $origin. "\ r \ n";} $header. = "sec-websocket-version:13\r\n\r\n"; $this->_socket = Fsockopen ($host, $port, $errno, $ERRSTR, 2); socket_ Set_timeout ($this->_socket, 2, 10000)//socket_write ($this->_socket, $header); $res = @fwrite ($this->_ Socket, $header), if ($res = = = False) {echo "fwrite false \ n";} $response = @fread ($this->_socket),//$response = Socket_read ($this->_socket);p reg_match (' # Sec-websocket-accept:\s (. *) $ #mU ', $response, $matches), if ($matches) {$keyAccept = Trim ($matches [1]); $ Expectedresonse = Base64_encode (Pack (' h* ', SHA1 ($key. ' 258eafa5-e914-47da-95ca-c5ab0dc85b11 ')); $this->_connected = ($keyAccept = = = $expeCtedresonse)? True:false;} return $this->_connected;} Public Function checkconnection () {$this->_connected = false;//Send ping: $data = ' ping '; @fwrite ($this->_socket, $this->_hybi10encode ($data, ' ping ', true)); $response = @fread ($this->_socket, 300); if (empty ($response)) {return false;} $response = $this->_hybi10decode ($response), if (!is_array ($response)) {return false;} if (!isset ($response [' type ']) | | $response [' type ']!== ' pong ') {return false;} $this->_connected = True;return true;} Public Function Disconnect () {$this->_connected = False;is_resource ($this->_socket) and fclose ($this->_ Socket);} Public Function Reconnect () {sleep], $this->_connected = False;fclose ($this->_socket); $this->connect ($ This->_host, $this->_port, $this->_path, $this->_origin);} Private Function _generaterandomstring ($length = ten, $addSpaces = True, $addNumbers = True) {$characters = ' abcdefghijklm nopqrstuvwxyzabcdefghijklmnopqrstuvwxyz! " ยง$%&/() =[]{} '; $useChars =Array ();//select some random chars:for ($i = 0; $i < $length; $i + +) {$useChars [] = $characters [Mt_rand (0, strlen ($ch Aracters)-1)];} Add spaces and numbers:if ($addSpaces = = = True) {Array_push ($useChars, ' ', ' ', ' ', ', ', ');} if ($addNumbers = = = True) {Array_push ($useChars, Rand (0,9), Rand (0,9), Rand (0,9));} Shuffle ($useChars); $randomString = Trim (Implode (", $useChars)); $randomString = substr ($randomString, 0, $length); return $randomString;} Private 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 Indic Ates 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 is 0 (close connection if frame too big) if ($frameHead [2] > 127) {$this->close (1004); Retu rn false;}} ElseIf ($payloadLength >) {$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 + +: $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: $framePayload = Array (), for ($i = 0; $i < $payloadLength; $i + +) {$frame. = ($masked = = = true)? $payload [$i] ^ $mask [$i% 4]: $payload [$i];} return $frame;} Private Function _hybi10decode ($data) {$payloadLength = "; $mask ="; $unmaskedPayload = "; $decodedData = Array ();//Esti Mate frame type: $firstByteBinary = sprintf ('%08b ', ord ($data [0])), $secondByteBinary = sprintf ('%08b ', Ord ($data [1])); opcode = Bindec (substr ($firstByteBinary, 4, 4)), $isMasked = ($secondByteBinary [0] = = ' 1 ')? true:false; $payloadLength = Ord ($data [1]) & 127;switch ($opcode) {//Text Frame:case 1: $decodedData [' type '] = ' text '; Break;case 2: $decodedData [' type '] = ' binary '; break;//connection close frame:case 8: $decodedData [' type '] = ' close '; break;//Ping frame:case 9: $decodedData [' type '] = ' ping '; break;//pong frame:case: $decodedData [' type '] = ' pong '; break ;d Efault:return False;break;} if ($payloadLength = = = 126) {$mask = substr ($data, 4, 4); $payloadOffset = 8; $dataLength = Bindec (sprintf ('%08b ', Ord ($data [2])). sprintf ('%08b ', Ord ($data [3])) + $payloadOffset;} ElseIf ($payloadLength = = = 127) {$mask = substr ($data, ten, 4); $payloadOffset = +; $tmp = "; for ($i = 0; $i < 8; $i + +) {$tm P. = sprintf ('%08b ', ord ($data [$i +2]);} $dataLength = Bindec ($tmp) + $payloadOffset; unset ($tmp);} else{$mask = substr ($data, 2, 4); $payloadOffset = 6; $dataLength = $payloadLength + $payloadOffset;} if ($isMasked = = = True) {for ($i = $payloadOffset; $i < $dataLength; $i + +) {$j = $i-$payloadOffset; if (Isset ($data [$i])) {$ Unmaskedpayload. = $data [$i] ^ $mask [$j% 4];} $decodedData [' payload '] = $unmaskedPayload;} else{$payloadOffset = $payloadOffset-4; $decodedData [' payload '] = substr ($data, $payloadOffset);} return $decodedData;}}
Examples of Use:
Use WebSocket to notify the client $client = new \common\library\websocketclient (); $client->connect ($_server[' http_host '], 943, ' /'); $payload = Json_encode (Array (' Code ' = ' xxx ', ' id ' = ' 1 ')), $rs = $client->senddata ($payload); if ($rs!== tru e) {echo "SendData error...\n";} Else{echo "ok\n";}
From: http://my.oschina.net/skq/blog/552923