Skip to content

Instantly share code, notes, and snippets.

@x011
Forked from ikwattro/ws-cli.php
Created November 12, 2017 13:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save x011/49ca936a3bc17599b1f4be76818977c0 to your computer and use it in GitHub Desktop.
Save x011/49ca936a3bc17599b1f4be76818977c0 to your computer and use it in GitHub Desktop.
php: simple websocket client
<?php
/*
based on: http://stackoverflow.com/questions/7160899/websocket-client-in-php/16608429#16608429
FIRST EXEC PYTHON SCRIPT TO GET HEADERS
*/
$ws = new ws(array
(
'host' => '127.0.0.1',
'port' => 8080,
'path' => ''
));
$result = $ws->send('message');
$ws->close();
echo $result;
class ws
{
private $params;
private $head;
private $instance;
public function __construct($params)
{
foreach($params as $key => $value)
$this->params[$key] = $value;
$local = "http://".$this->params['host'];
if(isset($_SERVER['REMOTE_ADDR']))
$local = "http://".$_SERVER['REMOTE_ADDR'];
$this->head = "GET / HTTP/1.1\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"Host: ".$this->params['host']."\r\n" .
"Origin: ".$local."\r\n" .
"Sec-WebSocket-Key: TyPfhFqWTjuw8eDAxdY8xg==\r\n" .
"Sec-WebSocket-Version: 13\r\n";
}
public function send($method)
{
$this->head .= "Content-Length: ".strlen($method)."\r\n\r\n";
$this->connect();
fwrite($this->instance, $this->hybi10Encode($method));
$wsdata = fread($this->instance, 2000);
return $this->hybi10Decode($wsdata);
}
public function close()
{
if($this->instance)
{
fclose($this->instance);
$this->instance = NULL;
}
}
private function connect()
{
$sock = fsockopen($this->params['host'], $this->params['port'], $errno, $errstr, 2);
fwrite($sock, $this->head);
$headers = fread($sock, 2000);
$this->instance = $sock;
}
private 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;
}
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 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;
}
}
# FIRST exec this script to get the headers to put then in the php script ;)
#
# requirements:
# pip install websocket-client
import websocket
if __name__ == "__main__":
websocket.enableTrace(True)
ws = websocket.create_connection("ws://127.0.0.1:8080")
ws.send("message")
result = ws.recv()
print result
ws.close()
/*
websocket server
requirements:
npm install ws
*/
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer(
{
host: '127.0.0.1',
port: 8080
});
wss.on('connection', function(ws)
{
console.log('connect');
ws.on('message', function(message)
{
console.log('received: %s', message);
});
ws.send('something');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment