amazon web services – WebSockets – send json data via php-ThrowExceptions

Exception or error:

I’m trying to send a fire-and-forget request from PHP to my websocket aws api gateway.

I’ve set up an action called “sendmessage”.

This is the code I’m using:

$protocol = "ssl";
$host = "<myendpoint>";
$port = 443;
$path = "/<mystage>/";
$timeout = 2000;

$socket = pfsockopen($protocol . "://" . $host, $port,
                    $errno, $errstr, $timeout);

$content = "{'action': 'sendmessage', 'data': 'test'}";
$body = "POST $path HTTP/1.1\r\n";
$body .= "Host: $host\r\n";
$body .= "Content-Type: application/json\r\n";
$body .= "Content-Length: " . strlen($content) . "\r\n";
$body .= "Connection: Close\r\n\r\n";
$body .= $content;
$body .= "\r\n";

fwrite($socket, $body);

However, nothing happens.

If I use wscat, like:

wscat -c wss://<my-endpoint><my-stage>

> {'action': 'sendmessage', 'data': 'test'}

it works just fine.

What am I doing wrong in my php code?

Note: I need the socket connection to be persistent (the way it is when using the pfsockopen function).

How to solve:

Since you didn’t provide a handpoint link, here is some notes, following own tests!

I guess the issue comes from the wss part, php needs to retrieve the certificate first, so it can encrypt the data.

Your code should work just fine on a ws:// stream.

To connect to a regular ws:// stream, one can simply use fsockopen().

$fp = fsockopen("udp://", 13, $errno, $errstr);
if (!$fp) {
    echo "ERROR: $errno - $errstr<br />\n";
} else {
    fwrite($fp, "\n");
    echo "Connected!";
    echo fread($fp, 26);

But to connect to a wss:// secure websocket stream, using php, without libraries, we need to create a tunnel first, by querying the public key with stream_socket_client.

This is a handshake mechanism. This can be done as follow.

Notice the first ssl:// call. This is the TLS 1.0 protocol.

$sock = stream_socket_client("ssl://",$e,$n,30,STREAM_CLIENT_CONNECT,stream_context_create(null));
} else {
  fwrite($sock,"GET / HTTP/1.1\r\nHost:\r\nAccept: */*\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: ".rand(0,999)."\r\n\r\n");

The output should looks like:

string(44) "HTTP/1.1 101 Web Socket Protocol Handshake"
string(21) "Connection: Upgrade"
string(37) "Date: Thu, 12 Dec 2019 04:06:27 GMT"
string(52) "Sec-WebSocket-Accept: fTYwcEa6D9kJBtghptkz1e9CtBI="
string(25) "Server: Kaazing Gateway"
string(20) "Upgrade: websocket"

Same base code, another example, pulling data from Binance wss:// stream.

We can also use TLS 1.2, with a tls:// handshake instead. Works on most servers.

$sock = stream_socket_client("tls://",$error,$errnum,30,STREAM_CLIENT_CONNECT,stream_context_create(null));
if (!$sock) {
    echo "[$errnum] $error" . PHP_EOL;
} else {
  echo "Connected - Do NOT get rekt!" . PHP_EOL;
  fwrite($sock, "GET /stream?streams=btcusdt@kline_1m HTTP/1.1\r\nHost:\r\nAccept: */*\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: ".rand(0,999)."\r\n\r\n");
  while (!feof($sock)) {
    var_dump(explode(",",fgets($sock, 512)));

Here is a way to retrieve only the ssl RSA public key of a remote handpoint, from php. Can be used to speed up later connections.

$opt = [
  "capture_peer_cert" => true,
  "capture_peer_cert_chain" => true
$a = stream_context_create(["ssl"=>$opt]);
$b = stream_socket_client("ssl://", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $a);
$cont = stream_context_get_params($b);
$key = openssl_pkey_get_public($cont["options"]["ssl"]["peer_certificate"]);
$c = openssl_pkey_get_details($key);

Output something like:

-----END PUBLIC KEY-----

There is possibly other quircks, to be sure, we need the main handpoint^. Would be glad to test that. Otherwise good luck, there is a big lack of documentation on the subject.

This is still a new born protocol (2011!). Best details are in the RFC specification:

The WebSocket protocol was standardized by the IETF as RFC 6455 in

About the handshake, it must be initiated by a GET request.

The client will send a pretty standard HTTP request with headers that
looks like this (the HTTP version must be 1.1 or greater, and the
method must be GET)


In short:

If unencrypted WebSocket traffic flows through an explicit or a
transparent proxy server without WebSockets support, the connection
will likely fail.




You need to use PHP websocket client for your requirement. Below is one of the client which can be used for your requirements:

Sample 1:

if( $sp = websocket_open('',80) ) {
  websocket_write($sp,"hello server");
  echo "Server responed with: " . websocket_read($sp,$errstr);

Sample 2:

$headers = ["Cookie: SID=".session_id()];
$sp = websocket_open('',80,$headers,$errstr,16);
   $bytes_written = websocket_write($sp,"hello server");
     $data = websocket_read($sp,$errstr);
     echo "Server responed with: " . $errstr ? $errstr : $data;

Hope this helps.


You probably need to use http_build_query(); function like :

$content = http_build_query($content);

and use form post to send message, so try the following code to check if socket connection is success, probably mistake in your code is pfsockopen() should be @fsockopen()

Edit this for your requirements :

$protocol = "ssl";
$host = "<myendpoint>";
$port = 443;
$path = "/<mystage>/";
$timeout = 2000;

$socket = @fsockopen($protocol . "://" . $host, $port,
            $errno, $errstr, $timeout);

if($socket === false) { return false; };

$content = "{'action': 'sendmessage', 'data': 'test'}";
$body  = "POST $path HTTP/1.1\r\n";
$body .= "Host: $host\r\n";
$body .= "Referer: yourClass (v.".version() .")\r\n";
$body .= "Content-type: application/json\r\n";
$body .= "Content-Length: ".strlen($content)."\r\n";
$body .= "Connection: Close\r\n\r\n";
$body .= "$content";
fwrite($socket, $body);

This code works fine in my site as a function with

$out .= “Content-type: application/x-www-form-urlencoded\r\n”; instead of json

function flexy_Request($url, $_data) {
    // parse the given URL
    $url = parse_url($url);
    if ($url === false || !isset($url['host']) || !isset($url['path'])) {
        return false;
    // extract host and path:
    $host = $url['host'];
    $path = $url['path'];
    // open a socket connection on port 80
    // use localhost in case of issues with NATs (hairpinning)
    $fp = @fsockopen($host, 80);

    if($fp===false) { return false; };

    $data = http_build_query($_data);
    $out  = "POST $path HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= "Referer: Myclass (v.". flexy_version() .")\r\n";
    $out .= "Content-type: application/json\r\n";
    $out .= "Content-Length: ".strlen($data)."\r\n";
    $out .= "Connection: Close\r\n\r\n";
    $out .= "$data";
    $number_bytes_sent = fwrite($fp, $out);
    return $number_bytes_sent; // or false on fwrite() error


I would recommend using the cURL extension for PHP. The cURL lib maintains a pool of persistent connections by default.

$proto     = 'https';
$host      = 'FQDN';         
$path      = '/path/to/file';

$post_data_array = array(
 'action'  => 'sendmessage',
 'data'    => 'test',

$payload = json_encode($post_data_array);

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $proto.'://'.$host.$path);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($payload),
    'Connection: Keep-Alive',
    'Keep-Alive: 300',
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);



Leave a Reply

Your email address will not be published. Required fields are marked *