97

I have recently been looking around, to find a good way to communicate between nodeJS and PHP. Here is the idea : nodeJS is still quite new, and it can be kind of tricky to develop a full application only with it. Moreover, you may need it only for one module of your project, like realtime notifications, chat, ... And you want to manage all the other stuff with PHP, because it is probably more easy for you (and you can take advantage of the existing frameworks, like CodeIgniter or Symfony).

I would like to have an easy solution ; I don't want to use cURL, or a third server to communicate between Apache and Node servers. What I want is to be able to catch events from node in simple Javascript, client-side.

I didn't find any answers that where complete, most of the time client-side was running by the node server and so not applicable in my case. So I crawled all the possible topics, and finally find my answer ; I'll try to share this, and to have a point where it's all clear.

Hope this can help some people ! ;)

Jérémy Dutheil
  • 6,099
  • 7
  • 37
  • 52
  • this might be helpful to someone: https://stackoverflow.com/questions/23447413/websockets-php-ajax-javascript-refresh-client – user3050478 Dec 15 '21 at 23:51

3 Answers3

131

So, to begin with, I put my project on github, if you want access to the full code: https://github.com/jdutheil/nodePHP

It is a very simple example project: a web chat. You just have an author and message, and when you press send it is saved in a mysql database. The idea is to send real time updates, and have a real conversation. ;) We'll use nodeJS for that.

I won't talk about PHP code, it is really simple and not interesting here; what I want to show you is how to integrate your nodeJS code.

I use express and Socket.IO, so be sure to install those modules with npm. Then, we create a simple nodeJS server:

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

var app = express();
var server = http.createServer( app );

var io = socket.listen( server );

io.sockets.on( 'connection', function( client ) {
    console.log( "New client !" );

    client.on( 'message', function( data ) {
        console.log( 'Message received ' + data.name + ":" + data.message );

        io.sockets.emit( 'message', { name: data.name, message: data.message } );
    });
});

server.listen( 8080 );

We registered our events callback when a new user is connected ; every time we receive a message (represents a chat message), we broadcast it to every users connected. Now, the tricky part: client-side! That the part that took me most of the time, because I didn't know which script include to be able to run Socket.IO code without the nodeServer (because client page will be served by Apache).

But everything is already done; when you install Socket.IO module with npm, a script is available in /node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js; that the script we will include in our PHP page, in my case:

    <script src="js/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js"></script>
    <script src="js/nodeClient.js"></script>

And to finish, my nodeClient.js, where we simply connect to the node server and wait for event to update our page. ;)

var socket = io.connect( 'http://localhost:8080' );

$( "#messageForm" ).submit( function() {
    var nameVal = $( "#nameInput" ).val();
    var msg = $( "#messageInput" ).val();

    socket.emit( 'message', { name: nameVal, message: msg } );

    // Ajax call for saving datas
    $.ajax({
        url: "./ajax/insertNewMessage.php",
        type: "POST",
        data: { name: nameVal, message: msg },
        success: function(data) {

        }
    });

    return false;
});

socket.on( 'message', function( data ) {
    var actualContent = $( "#messages" ).html();
    var newMsgContent = '<li> <strong>' + data.name + '</strong> : ' + data.message + '</li>';
    var content = newMsgContent + actualContent;

    $( "#messages" ).html( content );
});

I'll try to update and improve my code as soon as possible, but I think it already open to all of cool things! I am really open for advice and reviews on this stuff, is it the good way to do it, .. ?

Hope this can help some people!

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Jérémy Dutheil
  • 6,099
  • 7
  • 37
  • 52
  • 18
    Well, when you write a question there is an option "answer your own question, share knowledge Q&A style", so I thought we can share like this, sorry if I'm wrong :) – Jérémy Dutheil Jun 20 '13 at 12:05
  • Hi Jérémy, how about using Redis Pub/Sub with PHP driver for Redis and pushing things that's happening in PHP application in to the channel and in Node.js do what ever you want by listening to those channels? I just want to know the Pub/Sub comparisons with your code. Appreciate your sharing. – Maziyar Sep 10 '13 at 04:30
  • Hi, I made a web chat application, but in my routings I have a problem. when I use this routing `app.get('/', function (req,res) { res.sendfile(__dirname + 'index.php'); });` it opens the popup for download .php file. How can I fix this problem? – Pars Oct 12 '13 at 06:53
  • Sorry guys, I didn't have time these last months to update my project, and to answer your questions ; I'll try to do it as soon as possible, 'cause I would like to make something more generic that could help people to start an application (more like a very light framework) – Jérémy Dutheil Oct 31 '13 at 15:10
  • 4
    As suggestion, I think incorporating the answer to this question here http://stackoverflow.com/questions/5818312/mysql-with-node-js is a superior method. avoiding any ajax call and making the code more inline with the use of node. Now, PHP can simply select the information from the database. – blackmambo Nov 05 '13 at 04:13
  • sorry for bringing this up.. but i'm still stuck on setting up the Node.js server at port 8080 on localhost, as apache is already running on it .. can you explain how can i resolve this ? – Qarib Haider Nov 07 '13 at 07:32
  • @SyedQarib, just point your node.js server to another port instead of 8080 – Joseandro Luiz Dec 05 '13 at 03:39
  • 1
    Is it possible to connect to the node app using io.connect if it's on a different machine than your main app rather than having the node app on the same server but using a different port? – maembe Jul 20 '14 at 17:58
  • 1
    require hmac signing as message authentication. this insures that only php can broadcast messages to the socket. the socket will inspect the signed token, and if it passes, ti will then broadcast the message. this is good for preventing spam and ensure data integrity. so never post directly to the node socket from the client. instead post to php app with ajax, then relay that to the socket server. it is fairly non trivial to open a socket connection to a websocket server with fopen+fwrite or stream select from php. – r3wt Mar 07 '15 at 04:29
  • thanks @Jérémy Dutheil for the code,but I have problem,when I put localhost:8080 on the browser it shows cannot Get / have I made a mistake thanks for help – miratum Jun 04 '15 at 00:57
  • If you already have an open connection, why don't you send data through that connection instead of sending through an ajax call? – Bangash Oct 30 '15 at 06:27
  • Omg i found this working great!!! superb after a long search and test finally something worth i found! @JérémyDutheil tnx alot for your answer! – SOuřaan Gřg Jan 09 '16 at 06:22
  • 1
    Agreed with @Bangash, You can use Node.js to store the data into the mysql db instead of PHP, that would make it a Lot faster – Parthapratim Neog Mar 16 '16 at 14:00
  • 1
    When we only need a socket server why we have added express and http server? – Ravinder Payal Mar 27 '17 at 10:06
  • I'm getting error `GET http://127.0.0.1:8080/socket.io/1/?t=1501069240046 404 (Not Found)` can you help? –  Jul 26 '17 at 11:44
  • @Vay `so why even use nodejs` For the benefit of real-time communication with websockets, of course. It's more efficient than constantly hammer server with ajax polling. – Vaviloff Sep 01 '17 at 04:19
2

I have another solution that works quite well for me, but I would like someone to comment about how effective it is, as I have not (yet) had the opportunity/time to test it on the real server.

Here goes the node-js code. I put this code in a file called nodeserver.js:

var http = require('http');

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});

    var knall = new Object();
    knall.totten = "4 tomtar";
    knall.theArr = new Array();
    knall.theArr.push("hoppla")
    knall.theArr.push("hej")
    var strKnall = JSON.stringify(knall);

    res.end(strKnall);
}).listen(process.env.PORT);  

And here is the simple piece of code in php, calling the node-js server with the help of file_get_contents():

$json = file_get_contents('http://localhost:3002/knall.json');
$obj = json_decode($json);

Works great, when I load the php-page, it in turn calls the nodeserver.js page, which jsonify the knall-object.

I have two localhost-installations running on iis on windows 10, one standard php-server, and the nodejs-server works with the neat iisnode package.

The 'real' server is run on ubuntu.

I think this is a neat and easy solution for communication between two servers, but maybe someone has any comments about it?

Lorenz Meyer
  • 19,166
  • 22
  • 75
  • 121
Tornseglare
  • 963
  • 1
  • 11
  • 24
  • This makes no sense to me, because you are launching the node server from within the php script. I cannot immagine any use case for this. What we need is a way to communicate between a running node.js instance and php. – Lorenz Meyer Mar 02 '17 at 04:43
  • No @Lorenz, that is the node.js script, running on it's own server. I am calling the node.js-page directly from php with file_get_contents(), from another php-server. It is now in everyday use with 500+ users a day. Maybe you are confused because the "localhost:3002" piece? That is because this example runs on my local windows-computer, with two standalone servers in iis. – Tornseglare Mar 05 '17 at 21:23
  • I'm really confused. This means that `nodejs.js` is actually **not** a source file, but it is an URL you named so, because it contains json? The first would not make any sense, but the latter seems very confusing to me. – Lorenz Meyer Mar 06 '17 at 06:20
  • @Lorenz, I tried to clarify the example by changing the filename of the nodejs js file, and edit the text a bit. To answer your question, the file now renamed to nodeserver.js is run on it's own server. The http.createServer() call creates a server, which listen()s for incoming connections at port 80. – Tornseglare Mar 08 '17 at 12:05
  • Note that you can call the node.js server directly from a browser, by just enter the url "http://localhost:3002/nodeserver.js", and you would get a json-response. The file_get_contents() in the php file fetches the content from another server, in this case the node.js server. – Tornseglare Mar 08 '17 at 12:09
  • I don't want to be picky, but the fact that the URL is the same as the node source is really confusing. It should be `file_get_contents('http://localhost:3002/knall.json');`, because `nodeserver.js` is the name of the webserver executable, but your node server just returns the same thing for any URL. Your example is equivalent to a hello world page for Apache at the URL http://example.com/apache.exe instead of /index.html, which would be as misleading. – Lorenz Meyer Mar 08 '17 at 21:47
  • No, I am grateful for you taking your time checking my quick n dirty solutions and make them readable. :) Yes, in my simple example there are only one file at the node.js server, acting as server. The name could be anything. – Tornseglare Mar 14 '17 at 08:31
  • Liked the smart simplicity of your solution! It's a bit hacky, but is quite nice for a small project. – Vaviloff Sep 01 '17 at 04:15
  • Make me some light, please...all the chat messages will be stored in mysql db? If yes, will use php: sql insert and select queryes, or node js can do that itself? And how a qwery is executed each time an message is send? – Botea Florin Dec 13 '17 at 20:47
  • Botea, you can use MySQL inside node.js, no problems. This link is maybe not exactly right, but will give you a start: https://expressjs.com/en/guide/database-integration.html#mysql – Tornseglare Dec 14 '17 at 23:11
0

Try similar or you can check my blog for complete sample code on nodejs


On your page side:

  • Load Socket JS

https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js

  • Make object of the socket

var socket = io();

  • Use the emit function to send data to nodeserver.

socket.emit('new_notification', {
message: 'message',
title: 'title',
icon: 'icon',
});

So now your code will be look like

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>

var socket = io(); 

$(document).ready(function($) {
  $('.rules-table').on('click', '.runRule', function(event) {
    event.preventDefault();
    /* Act on the event */
    var ruleID = $(this).parents('tr').attr('id');

    // send notification before going to post 
    socket.emit('new_notification', {
        message: 'Messge is ready to sent',
        title: title,
        icon: icon,
    });
    $.ajax({
      url: '/ajax/run-rule.php',
      type: 'POST',
      dataType: 'json',
      data: {
        ruleID: ruleID
      },
    })
    .done(function(data) {
      console.log(data);

      // send notification when post success 
      socket.emit('new_notification', {
        message: 'Messge was sent',
        title: title,
        icon: icon,
      });

    })
    .fail(function() {
      console.log("error");

      // send notification when post failed 
      socket.emit('new_notification', {
        message: 'Messge was failed',
        title: title,
        icon: icon,
      });
    })
    .always(function() {
      console.log("complete");
    });

  });
});

Now on Node server side make handler for your request to get your request and send a message to all connected devices/browsers(server.js)

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

app.get('/', function(req, res) {
   res.sendfile('index.html');
});


io.on('connection', function (socket) {
  socket.on( 'new_notification', function( data ) {
    console.log(data.title,data.message);

    // Now Emit this message to all connected devices
    io.sockets.emit( 'show_notification', { 
      title: data.title, 
      message: data.message, 
      icon: data.icon, 
    });
  });
});

http.listen(3000, function() {
   console.log('listening on localhost:3000');
});

Now the client/browser/client side make a receiver to receive socket message from node server

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>   

var socket = io();

/**
 * Set Default Socket For Show Notification
 * @param {type} data
 * @returns {undefined}
 */
socket.on('show_notification', function (data) {
    showDesktopNotification(data.title, data.message, data.icon);
});
/**
 * Set Notification Request
 * @type type
 */
function setNotification() {
    showDesktopNotification('Lokesh', 'Desktop Notification..!', '/index.jpeg');
    sendNodeNotification('Lokesh', 'Browser Notification..!', '/index.jpeg');
}
/**
 * Check Browser Notification Permission
 * @type window.Notification|Window.Notification|window.webkitNotification|Window.webkitNotification|Window.mozNotification|window.mozNotification
 */
var Notification = window.Notification || window.mozNotification || window.webkitNotification;
Notification.requestPermission(function (permission) {
});
/**
 * Request Browser Notification Permission 
 * @type Arguments
 */
function requestNotificationPermissions() {
    if (Notification.permission !== 'denied') {
        Notification.requestPermission(function (permission) {
        });
    }
}
/**
 * Show Desktop Notification If Notification Allow
 * @param {type} title
 * @param {type} message
 * @param {type} icon
 * @returns {undefined}
 */
function showDesktopNotification(message, body, icon, sound, timeout) {
    if (!timeout) {
        timeout = 4000;
    }
    requestNotificationPermissions();
    var instance = new Notification(
            message, {
                body: body,
                icon: icon,
                sound: sound
            }
    );
    instance.onclick = function () {
        // Something to do
    };
    instance.onerror = function () {
        // Something to do
    };
    instance.onshow = function () {
        // Something to do
    };
    instance.onclose = function () {
        // Something to do
    };
    if (sound)
    {
        instance.sound;
    }
    setTimeout(instance.close.bind(instance), timeout);
    return false;
}
vikujangid
  • 728
  • 3
  • 8
  • 19