PHP with Socket.io

I desired to construct a real-time notification system using sockets without using any third-party services, such as Pusher, etc. I simply desired the ability to send alerts from PHP to the client and display them quickly on the web application, similar to Facebook notifications. First I came across the ratchet library, which worked well, but a problem arose when I attempted to set it up on a secure connection (https) on my host (siteground). I tried apache proxy module and everything else suggested on the internet, but to no avail (it appears siteground has a problem with ratchet on https), so I ultimately had to abandon ratchet. Then I considered utilizing socket.io with Node+PHP, and in my study I came across the elephant.io library (albeit it hasn't been updated in a while), which worked marvelously well on both non-secure and secure protocols, enabling us to send and receive messages from PHP with a node-based server. Here are the procedures I took to get my notification system to function properly.

php
php coding
javascript
socket.io with php

Install elephant.io

Install elephant.io via composer for your PHP application:

composer require wisembly/elephant.io

Install Node Dependencies

Create a directory at the root of your project and create a package.json file with the following contents:

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

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

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

Execute npm install —save on the newly created directory. This will install the logger and socket.io libraries.

Create a file server js containing the following code in the same freshly created directory:

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

// 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('Elephant.IO 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);

If you execute server.js through node by typing node server.js, you should receive a message indicating that the server has started on the chosen port.

Client Side

Insert the following javascript code into your application's page/footer:

<script src="https://cdn.socket.io/4.5.0/socket.io.min.js" 
    integrity="sha384-7EyYLQZgWBi67fBtVxw60/OWl1kjsfrPFcaU0pp0nAh+i8FD068QogUvg85Ewy1k" crossorigin="anonymous"></script>

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

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>

Transmitting Notification from PHP

Here's how to communicate with all linked clients:

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

use ElephantIOClient;
use ElephantIOEngineSocketIOVersion1X;

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

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

And that concludes the discussion.

Installation and Operation of Node on Production Site

I was running CentOSv6 and installed node using this procedure. Then I built a simple php file that will be executed by cron so that the node server is automatically started or restarted if it is not running:

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

and then set that file in cron to run at your desired intervals.

Important Notes

  • I was experiencing some difficulty obtaining the node path from the PHP script where it was initially installed, so I transferred the nodejs folder to my public html folder (the root of the application).
  • Instead of var socket = io.connect('/127.0.0.1:3001');, it must be var socket = io.connect('/YOUR SERVER IP:3001'); on the production server.
  • Check browse the bugs area if you are having trouble getting it to work over https.
  • Examine the examples folder on elephant.io to learn how to send and receive messages using both PHP and Javascript.