PHP sending message to Node / Socket.IO server
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/
Justin
Updated on June 25, 2022Comments
-
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 over 9 yearsYes, 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 about 4 yearsI 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 about 4 yearsEventually 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 about 4 yearsInteresting! 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 about 4 yearsThanks. 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 about 4 yearsI'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
tolocalhost
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 about 4 yearsThanks 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 almost 4 yearsHello! 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ü about 3 yearshow we set the channel name?
-
dılo sürücü about 3 yearsı want to use socket. emit with PHP curl ?
-
Alexander Taubenkorb over 2 yearsMaybe this answer is also helpful, explaining this in more depth: stackoverflow.com/a/65572463/936284