1

I got a connection between PHP and Node using Redis working fine, but I'm intrigued by doing it without any external libraries and services and just with sockets.

I'm not sure on how much performance will suffer without having Redis in the middle, but for simpler projects, this would be nice with lesser code.

I got most of the code from this answer in Using PHP with Socket.io but I had to change some of the vars. But it's not working as expected.

I tried both with and without https, since I will be using https, but I tried making a simpler example with http just to get it working.

  • send.php creates and writes to a socket. I can confirm that it connects to node, since I get an error if node isn't running.
  • socket.js doesn't return anything in the console.logs.
  • socket-https.js returns connection from ::ffff:127.0.0.1 but isn't reading the socket.on('data'). What did I miss?

I think I misunderstand something in the var/require section in the http-version.

Can anyone spot why it's not working?

socket.js

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

var listener = app.listen(8080, function(){
    console.log('Listening on port ' + listener.address().port); 
});

http.on("connection", function(socket) {
    console.log("connection");
    if(socket.remoteAddress == "::ffff:127.0.0.1") {
        console.log("connection from " + socket.remoteAddress);
        socket.on('data', function(buf) {
            var js = JSON.parse(buf);
            console.log("on data: " + js); // Not working
        });
    }
});

socket-https.js

var fs = require('fs');
var privateKey  = fs.readFileSync('my-domain-com.key', 'utf8');
var certificate = fs.readFileSync('my-domain-com.crt', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var app = require('express')();
var https = require('https').createServer(credentials, app);
var io = require('socket.io')(https);

https.listen(8080, function(){
  console.log('Server online');
});

https.on("connection", function(socket) {
    console.log("connection"); // Works!
    if(socket.remoteAddress == "::ffff:127.0.0.1") {
        console.log("connection from " + socket.remoteAddress); // Works!
        socket.on('data', function(buf) {
            var js = JSON.parse(buf);
            console.log("on data: " + js); // Not working :(
        });
    }
});

send.php

sio_message("Message","Data");

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);
    } else {
        echo "Connected<br>";
    }
    $bytes = socket_write($socket, json_encode(Array("msg" => $message, "data" => $data)));
    echo " $bytes bytes written";
    socket_close($socket);
}
Niclas
  • 1,362
  • 1
  • 11
  • 24
  • So you got two socket server listening on the same port 8080? – McBern Dec 09 '18 at 04:45
  • Sorry if it was unclear, it’s just two different options, only one running at one time. But php shouldn’t care about this since it’s connection to the socket, right? – Niclas Dec 09 '18 at 04:47
  • Can you confirm that the method is firing at all? does `console.log` ever fire? Is the problem the `json.parse` erroring with your json data? Any errors in your logs? I'm just wondering if it's ever making it into that final message at all. I'd be interested in seeing the raw data that's sent. Maybe https is doing something with it compared to http? I ran the original code on an `http` server so I'm wondering if that's the issue. Let me know what the raw data looks like – user1274820 Dec 09 '18 at 09:40
  • 1
    All console logs run except the most inner one, but I will try and move it above the JSON.parse method. I’m running node interactively and there were no message in the console. Is there any other error logs in node except what you seen on the screen? – Niclas Dec 09 '18 at 09:51
  • Just add a `console.log(buf)` and let me know if you see anything there :3 I don't think so - I'd check your php logs for errors too if you can. – user1274820 Dec 09 '18 at 09:55
  • Nope, no difference, still no response on socket.on('data'). There are no php errors, socket_write is run and returns the number of bytes sent, so it was ok. And on the node side, it sees the connection, the IP is correct, so I guess the format from PHP isn't what would trigger socket.on('data'). Is this socket.io or just http, cause it's inside the https.on("connection"), and in other scripts it's usually io.on("connection") and I have a hard time understanding the difference.. – Niclas Dec 09 '18 at 10:29
  • @Niclas I wish I had an environment to do testing. I'm guessing that maybe the https socket isn't accepting the data sent as "valid data" because it's waiting for certs or the data to be encrypted or whatever else - but that's just my guess. I was reading that `CURL` may be used instead of `socket_create` for https. I'm debating setting up an https server to test this - seems like a lot of work to answer this question. – user1274820 Dec 10 '18 at 03:49
  • Yeah I know, SSL is s bit painful. I’ll stick with Redis, simce it works perfectly, it’s just one extra step to process in the backend. Thanks for the idea though! – Niclas Dec 10 '18 at 05:51
  • @Niclas hey I know this is a super late reply, but I was just thinking that there is one other thing I ended up doing to get everything working. I didn't think it had anything to do with what we were trying to do, but maybe it's what you need? – user1274820 Aug 05 '19 at 22:39

2 Answers2

0

This might not have anything to do with the problem, but I did end up having to configure Apache to handle a Rewrite condition (I'm running Apache and Node.js side by side)

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/"

Maybe missing that is an issue? I'm not sure - also /node becomes a direct link to the node.js server.

user1274820
  • 7,786
  • 3
  • 37
  • 74
-1

Try this:

var fs = require('fs');
var privateKey  = fs.readFileSync('my-domain-com.key', 'utf8');
var certificate = fs.readFileSync('my-domain-com.crt', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var app = require('express')();
var https = require('https').createServer(credentials, app);
var io = require('socket.io')(https);

https.listen(8080, function(){
  console.log('Server online');
});

io.on("connection", function(client) {
    client.on('join', function(data) {

        io.emit('message',{sendto: all, message: 'Hello there! Welcome!'});

    });
    client.on('message', function(data) {
        console.log(data);

        //forward this message to specific user
        io.emit('message',data);
    });
});

PHP Script:

$message = json_encode(Array("msg" => $message, "data" => $data));
$msg_length = strlen($message);
$bytes = socket_write($socket, $message, $msg_length);
McBern
  • 549
  • 1
  • 4
  • 8
  • Thanks, but it still doesn't receive what PHP is sending. I'm confused about the difference between io.on and https.on. Does both get a "connection"? The io.on works when I connect with a frontend client using `var socket = io(host + ':8080/');`but not the direct socket call from PHP. – Niclas Dec 09 '18 at 06:52
  • Nope, no difference, still no response on socket.on('data'). :( What is the "msg" for? Should it all be contained in something called 'data' somehow? – Niclas Dec 09 '18 at 10:24