Sockets with PHP and Node

Sarfraz Ahmed    July 22, 2017 02:19 AM

I was looking to implement real time notifications system via sockets without having to use any third party services such as Pusher, etc. I just wanted to be able to send notifications from PHP side to the client and instantly show them on the web application similar to Facebook notifications.

First I came across ratchet library, it worked great but problem emerged when setting it up on secure connection (https) on my host (siteground), tried apache proxy module and everything else told on the internet but to no avail (it seems siteground has problem with ratchet on https) so in the end I had to drop ratchet.

Then I thought of using socket.io with Node+PHP and with my research I came across elephant.io library (though it isn't updated recently) and this one worked wonderfully well both on non-secure and secure protocols allowing us to send and receive messages from PHP with node-based server.

Here are the steps that I followed to get my notification system working.

Install elephant.io

For your PHP application, install elephant.io via composer:

composer require wisembly/elephant.io

Install Node Dependencies

Create a directory in your project root and under it create a file named package.json with these contents:

{
    "name": "elephantIO_example_emitter",
    "version": "3.0.0",
    "main": "server.js",

    "scripts": {
        "start": "supervisor --debug server.js"
    },

    "dependencies": {
        "socket.io": "~1",
        "winston": "*"
    }
}

On newly created directory run command npm install --save. This will install socket.io and logger library.

In same newly created directory, create a file server.js with these contents:

var server     = require('http').createServer(),
    io         = require('socket.io')(server),
    logger     = require('winston'),
    port       = 1337;

// Logger config
logger.remove(logger.transports.Console);
logger.add(logger.transports.Console, { colorize: true, timestamp: true });
logger.info('SocketIO > listening on port ' + port);

io.on('connection', function (socket){
    var nb = 0;

    logger.info('SocketIO > Connected socket ' + socket.id);

    socket.on('broadcast', function (message) {
        ++nb;
        logger.info('ElephantIO broadcast > ' + JSON.stringify(message));

        // send to all connected clients
        io.sockets.emit("broadcast", message);
    });

    socket.on('disconnect', function () {
        logger.info('SocketIO : Received ' + nb + ' messages');
        logger.info('SocketIO > Disconnected socket ' + socket.id);
    });
});

server.listen(port);

Run server.js file through node by typing node server.js, you should see message that server has started on specified port.

Client Side

Put following javascript code in your application's page/footer:

<script src='//cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.4/socket.io.min.js'></script>

<script>
var socket = io.connect('//127.0.0.1:1337');

socket.on('connect', function () {
    console.log('connected');

    socket.on('broadcast', function (data) {
        //console.log(data);
        //socket.emit("broadcast", data);
        alert(data.text);
    });

    socket.on('disconnect', function () {
        console.log('disconnected');
    });
});
</script>

Sending Notification from PHP

Here is how you can send a message to all connected clients:

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

use ElephantIO\Client;
use ElephantIO\Engine\SocketIO\Version1X;

$client = new Client(new Version1X('//127.0.0.1:1337'));

$client->initialize();
// send message to connected clients
$client->emit('broadcast', ['type' => 'notification', 'text' => 'Hello There!']);
$client->close();

and that's all there is to it.

Installing and Running Node on Production Site

I was on CentOSv6 and I installed node by following this guide. Then I created simple php file that will be run by cron so that node server is automatically started/restarted if it is not running:

$nodePath = 'your node binary path here';
$filePath = 'your server.js file path';
shell_exec($nodePath . ' ' . $filePath);

and then specify that file in cron to run at your specified time intervals.

Important Notes

  • I was having bit of issue getting node path from PHP script where I initially installed it so I copied the nodejs folder to my public_html folder (app's root).
  • On production site, I had to type actual server IP rather than 127.0.0.1 on client side code eg instead of var socket = io.connect('//127.0.0.1:1337');, it has to be var socket = io.connect('//SERVER_IP_HERE:1337');
  • If you are having issue getting it to work on https, check out issues section to fix it.
  • Check out examples folder of elephant.io to know how to send or receive messages both from PHP as well as Javascript.