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
You need to use PHP websocket client for your requirement. Below is one of the client which can be used for your requirements:
https://github.com/paragi/PHP-websocket-client
Sample 1:
if( $sp = websocket_open('echo.websocket.org',80) ) {
websocket_write($sp,"hello server");
echo "Server responed with: " . websocket_read($sp,$errstr);
}
Sample 2:
$headers = ["Cookie: SID=".session_id()];
$sp = websocket_open('echo.websocket.org',80,$headers,$errstr,16);
if($sp){
$bytes_written = websocket_write($sp,"hello server");
if($bytes_written){
$data = websocket_read($sp,$errstr);
echo "Server responed with: " . $errstr ? $errstr : $data;
}
}
Hope this helps.
I would recommend using the cURL extension for PHP. The cURL lib maintains a pool of persistent connections by default.
<?php
$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);
curl_exec($ch);
curl_close($ch);
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>.amazonaws.com";
$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);
fclose($socket);
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);
fclose($fp);
return $number_bytes_sent; // or false on fwrite() error
}
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().
<?php
$fp = fsockopen("udp://echo.websocket.org", 13, $errno, $errstr);
if (!$fp) {
echo "ERROR: $errno - $errstr<br />\n";
} else {
fwrite($fp, "\n");
echo "Connected!";
echo fread($fp, 26);
fclose($fp);
}
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.
<?php
$sock = stream_socket_client("ssl://echo.websocket.org:443",$e,$n,30,STREAM_CLIENT_CONNECT,stream_context_create(null));
if(!$sock){
echo"[$n]$e".PHP_EOL;
} else {
fwrite($sock,"GET / HTTP/1.1\r\nHost: echo.websocket.org\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(fgets($sock,2048));
}
}
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.
<?php
$sock = stream_socket_client("tls://stream.binance.com:9443",$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: stream.binance.com:9443\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.
<?php
$opt = [
"capture_peer_cert" => true,
"capture_peer_cert_chain" => true
];
$a = stream_context_create(["ssl"=>$opt]);
$b = stream_socket_client("ssl://stream.binance.com:9443", $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);
var_dump($c["key"]);
Output something like:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhki(...)7aEsFtUNkwM5R5b1mpqzAwqHyvdamJx20bT6SS6
PYXSr/dv8ak1d4e2Q0nIa1O7l3w0bZZ4wnp5B8Z+tjPd1W8uaZoRO2iVkPMh2yPl
j0mmtUw1YlfDyutH/t4FlRCDiD4JjdREQGs381/+jbkdjl2SIb1IyNiCdAXA6zsq
xwIDAQAB
-----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 2011
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)
Writing_WebSocket_servers#Client_handshake_request
In short:
If unencrypted WebSocket traffic flows through an explicit or a transparent proxy server without WebSockets support, the connection will likely fail.
WebSocket#Proxy_traversal
Transport_Layer_Security#Digital_certificates