简体   繁体   中英

Websockets with PHP and Node.js

Is it possible to have PHP scripts send data through to a Node.js server through websockets?

I'm planning a side project that would have PHP scripts running in the background working some magic and the front end application that end users would use would be in Node.js. There would be some socket.io interaction just in Node.js but I'd like the ability to push data into socket.io from the PHP scripts.

The answer is yes, but exact implementation depends on your environment / requirements.

Here is one example I've hacked from a recent project: it sends a message, then waits for a response to end in chr(10) ("\\n"). That response must be received within 0.5 seconds otherwise it assumes failure (see the timing loop). You can fiddle with those bits as needed.

Note: $ip and $port need to be passed in.

        $retval = false; // final return value will conatin something if it all works

        $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if ($socket === false || !is_resource($socket)) {
            $socket = false;
            $this->lastErrorNum = socket_last_error();
            $this->lastErrorMsg = 'Unable to create socket: ' . socket_strerror(socket_last_error());
        } elseif (!@socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
            $this->lastErrorNum = socket_last_error($socket);
            $this->lastErrorMsg = 'Unable to set options on socket: ' . socket_strerror($this->lastErrorNum);
            @socket_clear_error ( $socket );
        } elseif (!@socket_connect($socket, $ip, $port)) {
            $this->lastErrorNum = socket_last_error($socket);
            $this->lastErrorMsg = 'Unable to connect socket: ' . socket_strerror($this->lastErrorNum);
            @socket_clear_error ( $socket );
        } else {
            // Socket connected - send message
            if (!@socket_write($socket, $message, strlen($message))) {
                $this->lastErrorNum = socket_last_error($socket);
                $this->lastErrorMsg = 'Unable to write to socket: ' . socket_strerror($this->lastErrorNum);
                @socket_clear_error ( $socket );
            } else {
                // Read a response
                $receiveStartTime = microtime(true);
                $response = '';
                socket_set_nonblock ($socket);
                while(microtime(true) - $receiveStartTime < 0.5) {
                    $n = @socket_recv($socket, $dataIn, 1024, 0);  // Assume max return value is 1024 bytes.
                    if ($n) {
                        $response .= $dataIn;
                    }
                    if (strpos($dataIn, "\n") !== false) {
                        @socket_clear_error ( $socket );
                        $response = str_replace("\n", '', $response);
                        break;
                    }
                }
                if (socket_last_error($socket) > 0) {
                    $this->lastErrorNum = socket_last_error($socket);
                    $this->lastErrorMsg = 'Unable to read from socket: ' . socket_strerror($this->lastErrorNum);
                    @socket_clear_error ( $socket );
                } else {
                    $retval = $response;
                }
            }
            @socket_close($socket);
        }

I am also working on this. My implementation is a little different than others. Most people use php & curl + nodejs & express & socketio

I've done it the following way:

  • memcache in both php and nodejs (to share the userid and cookie) (you can also use redis)
  • a custom PHP class to send a request via websocket to localhost, where the nodejs server broadcasts to a user room (all sessions from the same user).

Here is the class I used to communicate from php to socketio (sends only data to nodejs and not the way around!)

When I connect to socket.io, my script reads my php cookie and sends it to the node server, where it accesses the memcache json sessions and identifies the user, joining him to a room.

Here is a php json-serialized memcached session handler class. It is similar to the one I used.

To make a request in php --> socket.io i do the following:

$s = new SocketIO('127.0.0.1', 8088);

$adata = "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain.";

$msg = json_encode(array('event'=> 'passdata','data'=> $adata, 'to'=> 1));

$tr = 0;
$fl = 0;
for ($i = 0 ; $i < 1000; $i++) {
    $s->send( 'broadcast', $msg ) ? $tr++ : $fl++;
}
echo "HIT : " . $tr . PHP_EOL;
echo "MISS: " . $fl;

When a (socket.io) request from localhost goes to the server, i run this code:

var is_local = (this_ip === '127.0.0.1' ? true : false);
socket.on('broadcast', function(data) {
    if (data.length === 0 ) return;
    if (is_local && typeof data === 'string') {
        try {
            var j = JSON.parse(data);
        } catch (e) {
            console.log("invalid json @ broadcast".red);
            return false;
        }
        if (!j.hasOwnProperty('to') && !j.hasOwnProperty('event')) return false;
        io.to(j.to).emit(j.event, j.data);
        console.log('brc'.blue + ' to: ' + j.to + ' evt: ' + j.event);
        /** @todo remove disconnect & try to create permanent connection */
        socket.disconnect();
    } else { console.log('brc ' + 'error'.red ); }
});

If i want to pass data from node to php, I simply exec php code on my nodejs server. like this:

 socket.on('php', function(func, data, callback) {
    /* some functions */
    if (check_usr(session) === false) return;
    console.log('php'.green + ' act:' + func);
    var cmd = 'php -r \'$_COOKIE["MONSTER"]="' + session + '"; require(\"' + __dirname + '/' + php_[func].exec + '\");\'';
    console.log(cmd);
    cp.exec(cmd ,
    function(err, stdout, stderr) { 
        if (err == null) {
            console.log(typeof callback);
            console.log(JSON.parse(callback));
            if (callback != null) callback(stdout);
            console.log(stdout);
            //socket.emit('php', {uid: uid, o: stdout});
            console.log('emitted');
        } else { 
            console.log('err '.red + stdout + ' ' + stderr);
        }
    });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM