PHP sending message to Node / Socket.IO server

19,541

Solution 1

im using http://elephant.io/ for comunication between php and socket.io, i have only problems with the time to stablish connection, 3 or 4 seconds to complete sending data.

<?php

require( __DIR__ . '/ElephantIO/Client.php');
use ElephantIO\Client as ElephantIOClient;

$elephant = new ElephantIOClient('http://localhost:8080', 'socket.io', 1, false, true, true);

$elephant->init();
$elephant->emit('message', 'foo');
$elephant->close();

Solution 2

I searched for this quite a bit and finally found a relatively simple solution.

This doesn't require any additional PHP libraries - it just uses sockets.

Instead of trying to connect to the websocket interface like so many other solutions, just connect to the node.js server and use .on('data') to receive the message.

Then, socket.io can forward it along to clients.

Detect a connection from your PHP server in Node.js like this:

//You might have something like this - just included to show object setup
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);

server.on("connection", function(s) {
    //If connection is from our server (localhost)
    if(s.remoteAddress == "::ffff:127.0.0.1") {
        s.on('data', function(buf) {
            var js = JSON.parse(buf);
            io.emit(js.msg,js.data); //Send the msg to socket.io clients
        });
    }
});

Here's the incredibly simple php code - I wrapped it in a function - you may come up with something better.

Note that 8080 is the port to my Node.js server - you may want to change.

function sio_message($message, $data) {
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    $result = socket_connect($socket, '127.0.0.1', 8080);
    if(!$result) {
        die('cannot connect '.socket_strerror(socket_last_error()).PHP_EOL);
    }
    $bytes = socket_write($socket, json_encode(Array("msg" => $message, "data" => $data)));
    socket_close($socket);
}

You can use it like this:

sio_message("chat message","Hello from PHP!");

You can also send arrays which are converted to json and passed along to clients.

sio_message("DataUpdate",Array("Data1" => "something", "Data2" => "something else"));

This is a useful way to "trust" that your clients are getting legitimate messages from the server.

You can also have PHP pass along database updates without having hundreds of clients query the database.

I wish I'd found this sooner - hope this helps! 😉

Late edit: Not sure if this is a requirement, but I added this to my http.conf (Apache config):

I figured I'd put the code here in case it helps anyone.

In httpd.conf I added the following code:

RewriteEngine On
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule .* ws://localhost:8080%{REQUEST_URI} [P]

ProxyRequests Off
ProxyPass        /socket.io http://localhost:8080/socket.io retry=0
ProxyPassReverse /socket.io http://localhost:8080/socket.io retry=0

ProxyPass "/node" "http://localhost:8080/"

Solution 3

With the latest version of ElephantIO, I've managed to send a message with:

include_once("vendor/autoload.php");
use ElephantIO\Exception\ServerConnectionFailureException;

$client = new \ElephantIO\Client(new \ElephantIO\Engine\SocketIO\Version1X('http://localhost:9000'));

try
{
    $client->initialize();
    $client->emit('message', ['title' => 'test']);
    $client->close();
}
catch (ServerConnectionFailureException $e)
{
    echo 'Server Connection Failure!!';
}

Solution 4

Fresh answer that works with socket.io version 3

https://github.com/socketio/socket.io-protocol#sample-session

Example of a working server:

run server direct /usr/local/bin/node /socket_io/server/index.js

or run server via 'forever'

/usr/local/bin/forever -a -l /logs/socket.io/forever-log.log -o /logs/socket.io/forever-out.log -e /media/flashmax/var/logs/socket.io/forever-err.log start /socket_io/server/index.js

index.js file contents (receives requests):

var io = require('/usr/local/lib/node_modules/socket.io')(8000);
//25-01-2021
// socket.io v3
//iptables -I INPUT 45 -p tcp -m state --state NEW -m tcp --dport 8000 -j ACCEPT
//iptables -nvL --line-number
io.sockets.on('connection', function (socket) {
    socket.on('router', function (channel,newmessage) {
//  console.log('router==========='+channel);
//  console.log('router-----------'+newmessage);
    socket.broadcast.to(channel).emit('new_chat',newmessage);
    });
    socket.on('watch_for_me', function (chanelll) {
        socket.join(chanelll);
//console.log('user watch new '+chanelll);
    });
    socket.on('dont_watch', function (del_chanelll) {
        socket.leave(del_chanelll);
//console.log('user go out' +del_chanelll);
    });
}); 

script that sends from PHP

<?php
//  php -n /socket_io/test.php
//  dl('curl.so');
//  dl('json.so');

$site_name='http://127.0.0.1:8000/socket.io/?EIO=4&transport=polling&t=mytest';
// create curl resource
$ch = curl_init();

//Request n°1 (open packet)
// set url
curl_setopt($ch, CURLOPT_URL, $site_name);
//return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// $output contains the output string
$output = curl_exec($ch);
$output=substr($output, 1);
$decod=json_decode($output);

//Request n°2 (namespace connection request):
$site_name2=$site_name.'&sid='.$decod->sid;
curl_setopt($ch, CURLOPT_URL, $site_name2);
curl_setopt($ch, CURLOPT_POST, true);
// 4           => Engine.IO "message" packet type
// 0           => Socket.IO "CONNECT" packet type
curl_setopt($ch, CURLOPT_POSTFIELDS, '40');
$output = curl_exec($ch);

// Request n°3 (namespace connection approval)
if ($output==='ok')  {
  curl_setopt($ch, CURLOPT_URL, $site_name2);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $output = curl_exec($ch);
}

// Request n°4 socket.emit('hey', 'Jude') is executed on the server:
if ($output==='ok')  {
curl_setopt($ch, CURLOPT_URL, $site_name2);
curl_setopt($ch, CURLOPT_POST, true);

$message_send='{\\"uuuuu\\": \\"000\\",\\"ryyyd\\":\\"999\\",\\"hyyya\\":\\"<div class=\'fro9\'>llll</div><div class=\'9ig\'>iiiii</div><div class=\'ti9g\'>iiiii</div>\\"}';

curl_setopt($ch, CURLOPT_POSTFIELDS, "42[\"router\",\"chanel@id\",\"$message_send\"]");
$output = curl_exec($ch);
print_r($output);
}

$message_send='send 2 message';
curl_setopt($ch, CURLOPT_POSTFIELDS, "42[\"router\",\"chanel@id\",\"$message_send\"]");
$output = curl_exec($ch);


$message_send='send 3 message';
curl_setopt($ch, CURLOPT_POSTFIELDS, "42[\"router\",\"chanel@id\",\"$message_send\"]");
$output = curl_exec($ch);

// close curl resource to free up system resources
curl_close($ch);  
?>

bonus: settings for apache -> mod_proxy to access the socket.io which can be used for a virtual host or for the entire server.

RewriteEngine on
RewriteCond %{QUERY_STRING} transport=polling    [NC]
RewriteRule /(.*)$ http://127.0.0.1:8000/$1 [P,L]
ProxyRequests off
ProxyPass /socket.io/ ws://127.0.0.1:8000/socket.io/
ProxyPassReverse /socket.io/ ws://127.0.0.1:8000/socket.io/
Share:
19,541
Justin
Author by

Justin

Updated on June 25, 2022

Comments

  • Justin
    Justin almost 2 years

    I'm not too sure if I'm going about this in the right way. I want to stick with my Socket.IO server, and do not want to create a separate HTTP server within node. With this, can I create a PHP client that can send data (e.g.: player buys item from online shop) to the node Socket.IO server directly?

    I've started with this:

    <?php
    
    class communicator {
       public function connect($address, $port){
          $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    
          if($socket){
              try {
                  socket_connect($socket, $address, $port);
              } catch(Exception $e){
                  throw new Exception($e->getMessage());
              }
          }else{
              throw new Exception('Could not create socket.');
          }
    }
    
    ?>
    

    The socket seems to connect just fine to the node server, but how can I start receiving data directly from the PHP client?

    E.g.: Say I use socket_write to send a message to the server. How do I get that through Socket.IO?

    Hope my question makes sense!

  • Arsha
    Arsha over 9 years
    Yes, it's delay or not send anything. Did you ever try this one? github.com/rase-/socket.io-php-emitter If tried, how is it compare to elephant.io?
  • Shlomo
    Shlomo about 4 years
    I am trying to use your solution, but it doesn't work for me. The message I send from the PHP does get to the socket.io cliend, but it doesn't enter the: s.on('data', function) I fail to understand what will triger it mecause in the PHP I don't see somthing like emit('data',buff) but only some json with one item 'data' that I think it is not related (although I also added a 'data' item to my json).
  • Shlomo
    Shlomo about 4 years
    Eventually I managed to make it work like that: server.on('connection', (socket) => { socket.on('data', function( data) { data+=''; if (data && (data[0] == '{')) { data=JSON.parse(data); console.log(data.data); } }); });
  • user1274820
    user1274820 about 4 years
    Interesting! Thanks for the feedback. I might give this a shot. You might need to play with the s.RemoteAddress portion if that's the issue. Otherwise, console.log the connection to see what address it's coming from. s.on('data' should fire whenever data is sent to the server.
  • Shlomo
    Shlomo about 4 years
    Thanks. Eventually I managed to make it work. but s.on('data') receives many other messages. So I check that the data starts with '{' (JSON) and then it works OK. But I am still invistigating a problem that for some reason, after few messages, the nodejs server get "stuck", and to doesn't release the outgoung messages (from the PHP to the clients).
  • user1274820
    user1274820 about 4 years
    I've run into the same issue (with Node.js picking up extra info). I haven't tested it yet, but I think that before my setup was filtering out ipv6 traffic so it was seeing a difference between the proxied data. I think maybe changing 127.0.0.1 to localhost might solve this - hoping to give it a shot. In the meantime, I did the same thing you did - checking to see if it looks like valid JSON, but obviously this is a bad way to do it.
  • Shlomo
    Shlomo about 4 years
    Thanks for the info. I am not sure about what is the root cause of the problem because it happens very seldom. I will keep investigating it.
  • quiquelhappy
    quiquelhappy almost 4 years
    Hello! Something really weird going on for me, the socket connects without a problem, but no .on('connection') event is triggered on the socket.io server
  • dılo sürücü
    dılo sürücü about 3 years
    how we set the channel name?
  • dılo sürücü
    dılo sürücü about 3 years
    ı want to use socket. emit with PHP curl ?
  • Alexander Taubenkorb
    Alexander Taubenkorb over 2 years
    Maybe this answer is also helpful, explaining this in more depth: stackoverflow.com/a/65572463/936284