WebSockets - send json data via php

前端 未结 4 814
生来不讨喜
生来不讨喜 2021-01-05 07:05

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

相关标签:
4条回答
  • 2021-01-05 07:18

    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.

    0 讨论(0)
  • 2021-01-05 07:25

    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);
    
    0 讨论(0)
  • 2021-01-05 07:30

    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
    }
    
    0 讨论(0)
  • 2021-01-05 07:32

    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

    0 讨论(0)
提交回复
热议问题