Sending messages from PHP to Node.js

后端 未结 6 1995
终归单人心
终归单人心 2020-12-04 20:25

How to send messages from php to node.js? I have a linux server running php and node.js.

When a user completes a transaction (via php), I\'d like send a message f

相关标签:
6条回答
  • 2020-12-04 20:30

    I found such problem can be solved simply by using the Express framework. Let's suppose php sends a json message to the node server and the server replies with ok.

    In app.js

    var app = require('express')();
    var http = require('http').Server(app);
    var io = require('socket.io')(http);
    var bodyParser = require('body-parser')
    app.use(bodyParser.json());
    
    app.post('/phpcallback', function(req, res) {
        var content = req.body;
        console.log('message received from php: ' + content.msg);
        //to-do: forward the message to the connected nodes.
        res.end('ok');
    });
    
    http.listen(8080, function(){
      var addr = http.address();
      console.log('app listening on ' + addr.address + ':' + addr.port);
    });
    

    In test.php

    <?php
    
    $data = array("name" => "Robot", "msg" => "Hi guys, I'm a PHP bot !");                                                                    
    $data_string = json_encode($data);
    
    $ch = curl_init('http://localhost:8080/phpcallback');                                                                      
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                                                  
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                      
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          
        'Content-Type: application/json',                                                                                
        'Content-Length: ' . strlen($data_string))                                                                       
    );                                                                                                                   
    
    echo curl_exec($ch)."\n";
    curl_close($ch);
    
    ?>
    

    Here we have also a more detailed example where a php script could drop a message to the users of a specific chat room.

    https://github.com/lteu/chat


    My personal impression about Redis approach: Cumbersome. You need to run Apache, nodeJS and Redis, three servers together in the same. And PubSub mechanism is quite different from the emit of socket.io, so you need to see if it is compatible with your existing code.

    0 讨论(0)
  • 2020-12-04 20:33

    I was looking for a really simple way to get PHP to send a socket.io message to clients.

    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!

    0 讨论(0)
  • 2020-12-04 20:41

    We do it by using message queue. There are a lot of solutions like radis (https://github.com/mranney/node_redis) or 0mq (http://zeromq.org/). It allows to send a message to subscribers (for example from php to nodejs).

    0 讨论(0)
  • 2020-12-04 20:44

    Step 1. Get the PHP Emitter: https://github.com/rase-/socket.io-php-emitter

    $redis = new \Redis(); // Using the Redis extension provided client
    $redis->connect('127.0.0.1', '6379');
    $emitter = new SocketIO\Emitter($redis);
    $emitter->emit('new question', '<b>h<br/>tml</b>');
    

    add this to your index.js:

    var redis = require('socket.io-redis');
    io.adapter(redis({ host: 'localhost', port: 6379 }));
    io.on('connection', function(socket){
        socket.on('new question', function(msg) {
            io.emit('new question', msg);
        });
    });
    

    add something like this to your index.html

    socket.on('new question', function(msg) {
        $('body').append( msg );
    });
    
    0 讨论(0)
  • 2020-12-04 20:47

    The suggestion seems to be to talk to node through the HTTP interface, just as any other client does. You can talk to node via HTTP using cURL in php

    See: http://groups.google.com/group/socket_io/browse_thread/thread/74a76896d2b72ccc/216933a076ac2595?pli=1

    In particular, see this post from Matt Pardee

    I faced a similar problem with wanting to keep users informed of a new note added on to a bug, and similar notifications that could really only be effectively sent from PHP to my Node server. What I did follows (apologies if this gets all garbled and unformatted in sending, if it does, I'd be happy to paste the code somewhere else): First, you'll need to use cURL from PHP. I wrote a function for my class like this:

    function notifyNode($type, $project_id, $from_user, $data) {
        $ch = curl_init();
    
        curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1');
    
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
        curl_setopt($ch, CURLOPT_PORT, 8001);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
    
        curl_setopt($ch, CURLOPT_POST, true);
    
        $pf = array('f' => $type, 'pid' => $project_id, 'user_from' => $from_user, 
                 'data' => array());
    
        foreach($data as $k => $v) {
            $pf['data'][$k] = $v;
        }
    
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($pf));
    
        curl_exec($ch);
        curl_close($ch);
    }
    

    You'll notice that I send the cURL request on the same server since both PHP and NodeJS are running there, your mileage may vary. The port I set this code to connect to is 8001 (this is the port my Node server is running on, and the port the socket.io server connects to). This sends a HTTP POST request with the post field encoded. This is all pretty standard cURL stuff.

    In your Node app you probably have something like:

    var server = http.createServer(function(req, res) {});
    server.listen(8001);
    var io = io.listen(server, { transports: ['websocket', 'flashsocket', 'xhr-polling'] });
    
    ...
    

    well what we'll do here is expand on the http.createServer part, to listen for connections coming from our local host ("127.0.0.1"). The createServer code then becomes:

    var server = http.createServer(function(req, res) {
        // Check for notices from PHP
        if(res.socket.remoteAddress == '127.0.0.1') {
            if(req.method == 'POST') {
                // The server is trying to send us an activity message
    
                var form = new formidable.IncomingForm();
                form.parse(req, function(err, fields, files) {
    
                    res.writeHead(200, [[ "Content-Type", "text/plain"]
                            , ["Content-Length", 0]
                            ]);
                    res.write('');
                    res.end();
    
                    //sys.puts(sys.inspect({fields: fields}, true, 4));
    
                    handleServerNotice(fields);                
                });
            }
        }
    });
    

    From there you can implement your handleServerNotice function..

    function handleServerNotice(data) {
            ...
    }
    

    etc etc. I haven't tested this in a while, and in fact that code block was commented out on my node server, so I hope what I've pasted here works - in general this concept is proven and I think it'll work for you. Anyway just wanted to be sure you knew it's been a few months so I'm not sure exactly why I commented out. The code I wrote took a little research -- like setting the 'Expect:' header in cURL -- and I was pretty excited when it finally worked. Let me know if you need any additional help.

    Best,

    Matt Pardee

    0 讨论(0)
  • 2020-12-04 20:47

    A bit late, but you could communicate with your node client using the Redis Pub/Sub mechanism in a very simple and effective way. All you need to do is install redis on your server.

    On the php side, initialize Redis then publish a message

    $purchase_info = json_encode(array('user_id' =>$user_id,
             'purchase_information'=>array('item'=>'book','price'=>'2$'));
    
    $this->redis->publish('transaction_completed', $purchase_info);
    

    On the node.js side

    var redis = require('redis');
    var purchase_listener = redis.createClient();
    purchase_listener.subscribe('transaction_completed');
    purchase_listener.on('message', function(channel, message){
        var purchase_data = JSON.parse(message);
        user_id = purchase_data.user_id;
        purchase_info = purchase_data.purchase_information;
        // Process the data
        // And send confirmation to your client via a socket connection
    })
    

    Is this scalable ? (In response to @mohan-singh)

    When talking about scalability you need to think about your infrastructure's architecture and your particular needs but here's a quick answer : I've been using a variant of this mechanism on a high traffic real-time application without problems but here's what you should be careful about:

    1. Redis PUB/SUB is not a queuing system, that means if your node process goes down all the messages that were sent WHILE it is down will be lost.

    2. If you have more than 1 subscriber to the publisher they will all receive the same message and handle it, be careful about that if you have more than a node process listening to the same redis db handling your real-time logic (There are easy ways to go around this though)

    The nice thing about this system is that you don't need to add anything to your existing infrastructure and can get started immediately, it's very fast and it behaves exactly like an HTTP server.

    Here are your alternatives for more scalable options:

    1. Using a self-hosted fast messaging queue server (ActiveMQ, RabbitMQ, beanstalkd ... ) server to handle your messaging logic between php and node, these tend to be fast but as the load increases you lose a bit of performance, and have to maintain/scale your messaging servers, and take care of duplication across regions which is not an easy and enjoyable thing (depending on what you enjoy doing).
    2. Using a hosted messaging queue server (IronMQ, SQS...) Some of these(IronMQ) are pretty fast and will be great for your use case but introduce some (minor) complexity to your codebase.
    3. Building a messaging queue with Redis with clustered node servers : https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
    4. Using HTTP inside a VPN to communicate with node servers. Once you see your traffic spiking you will only need to load-balance your node servers and add as much stateless servers as you need and send POST messages to that load balancer.

    The point of this lengthy edit is that there is no such thing as a magic scalable solution, you need to weigh your options and see which one works the best for your use case. In my opinion, if you're starting to build your first iteration now, choose any option that you're comfortable with, write very clean code and when you start scaling it will be very easy to change, this is what I've done :)

    0 讨论(0)
提交回复
热议问题