Search code examples
phpwebsocketratchetphpwebsocket

PHP Secure Websocket Client Trouble, Needs to be Non Blocking


I'm building a dashboard that allows me to visualise my crontab as it runs (Think a queue of upcoming tasks, those that are running currently and those that have finished and whether the outcome was successful.) To do this, I need to send messages from the tasks (running or monitored by PHP) on my server, to the client browsers that run the dashboard using javascript. It also has to be secure.

To solve this issue I implemented a Twisted/Autobahn socket server in Python, which worked fine once I had paid for proper security certificates. The problem I have however is getting the PHP running the crontasks to be able to send messages to the webSocket server which passes them on to the client browsers, so far I have hacked this by writing a Python client that accepts the message to send as an argument and run this as an exec from PHP.

Obviously this is not a robust solution (which is also relatively slow to execute) and I'd now like to send logfile entries from the crontasks over websockets to my dashboards so I can see what's happening on my servers as tasks run. I've been looking for a while and tried various approaches (most are too long to post) however they range from tutorials, to segments from the PHP website to libraries such as Thruway (which seems too over-engineered for my use case, specialised and hard to adapt).

The best progress I have so far is Pawl, and using the following code I'm able to successfully send three messages to the Python Socket Server using wss:

<?php

    require __DIR__ . '/vendor/autoload.php';

    \Ratchet\Client\connect('wss://127.0.0.1:9000')->then(function($conn) {
        $conn->on('message', function($msg) use ($conn) {
            echo "Received: {$msg}\n";
            $conn->close();
        });

        $conn->send('MSG 1');

        $conn->send('MSG 2');

        $conn->send('MSG 3');

    }, function ($e) {
        echo "Could not connect: {$e->getMessage()}\n";
    });
?>

(Note that this depends on the libraries found here)

The problem I have is that I would like to be able to open and close the connection and send messages as separate steps, in the code example (which I've had difficulty adapting) it seems that as open, send and close are all wrapped in the then method and anonymous function I cannot call these methods seperately. Ideally I'd like to open the connection at the beginning of my crontask execution, each time a message is logged call the send method and close the connection at the end without wasting time opening and closing a connection to my socket server for each and every message. Please note that listening for replies isn't necessary.

Also, any solutions that work to 127.0.0.1:9000 over WSS and don't need libraries or use a different one I'm happy to consider. Please also note (after seeing other posts) this question specifically refers to a websocket client, not a server.

Many thanks,

James


Solution

  • Leaving this in case anybody else finds this final solution welcome:

    In the end I wrapped a module called Textalk by Fredrik Liljegren et al in a small class to make it more accesible and this solved my issue.

    Here is the code I used in the end:

     require('vendor/autoload.php');
    
     use WebSocket\Client;
    
            class secureSocketClient {
    
                    private $OClient;
    
                    function __construct($VProtocol, $VLocation, $VPort, $VDir) {
    
                            $this->OClient = new Client("$VProtocol://$VLocation:$VPort" . ($VDir != null ? "/$VDir" : ""));
                    }
    
                    function sendMessage($ORequestData) {
    
                            $VLocalMessage = json_encode($ORequestData);
    
                            $this->OClient->send($VLocalMessage);
                    }
    
                    function __destruct() {
    
                            $this->OClient->close();
                    }
            }
    

    Which can be invoked as so:

    require_once <class location>
    
    $this->OSecureSocketClient = new secureSocketClient("wss", "127.0.0.1", "9000", null);
    
    $this->OSecureSocketClient->sendMessage($OMSG1);
    $this->OSecureSocketClient->sendMessage($OMSG2);
    $this->OSecureSocketClient->sendMessage($OMSG3);
    

    To install textTalk (on linux), you can use the following commands in the directory where the class will reside:

    curl -sS https://getcomposer.org/installer | php
    

    add the following to composer.json (in the same directory):

    {
        "require": {
            "textalk/websocket": "1.0.*"
        }
    }
    

    then run the following:

    sudo php composer.phar install
    

    Regards,

    James