Bagaimana cara mengintegrasikan nodeJS + Socket.IO dan PHP?

98

Saya baru-baru ini melihat-lihat, untuk menemukan cara yang baik untuk berkomunikasi antara nodeJS dan PHP. Inilah idenya: nodeJS masih cukup baru, dan mungkin agak sulit untuk mengembangkan aplikasi lengkap hanya dengan itu. Selain itu, Anda mungkin memerlukannya hanya untuk satu modul proyek Anda, seperti pemberitahuan waktu nyata, obrolan, ... Dan Anda ingin mengelola semua hal lain dengan PHP, karena itu mungkin lebih mudah bagi Anda (dan Anda dapat memanfaatkan kerangka kerja yang ada, seperti CodeIgniter atau Symfony).

Saya ingin mendapatkan solusi yang mudah; Saya tidak ingin menggunakan cURL, atau server ketiga untuk berkomunikasi antara server Apache dan Node. Yang saya inginkan adalah dapat menangkap kejadian dari node dalam Javascript sederhana, sisi klien.

Saya tidak menemukan jawaban yang lengkap, sebagian besar waktu sisi klien dijalankan oleh server node dan karenanya tidak berlaku dalam kasus saya. Jadi saya merangkak semua topik yang mungkin, dan akhirnya menemukan jawaban saya; Saya akan mencoba membagikan ini, dan untuk mendapatkan poin di mana semuanya jelas.

Semoga ini bisa membantu beberapa orang! ;)

Jérémy Dutheil
sumber

Jawaban:

131

Jadi, sebagai permulaan, saya meletakkan proyek saya di github, jika Anda ingin mengakses kode lengkap: https://github.com/jdutheil/nodePHP

Ini adalah proyek contoh yang sangat sederhana: obrolan web. Anda hanya memiliki seorang penulis dan pesan, dan ketika Anda menekan kirim itu disimpan dalam database mysql. Idenya adalah mengirim pembaruan waktu nyata, dan melakukan percakapan nyata. ;) Kami akan menggunakan nodeJS untuk itu.

Saya tidak akan berbicara tentang kode PHP, ini sangat sederhana dan tidak menarik di sini; apa yang ingin saya tunjukkan adalah bagaimana mengintegrasikan kode nodeJS Anda.

Saya menggunakan express dan Socket.IO, jadi pastikan untuk menginstal modul tersebut dengan npm. Kemudian, kami membuat server nodeJS sederhana:

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 );

Kami mendaftarkan acara callback kami ketika pengguna baru terhubung; setiap kali kami menerima pesan (mewakili pesan obrolan), kami menyiarkannya ke setiap pengguna yang terhubung. Sekarang, bagian yang sulit: sisi klien! Itu bagian yang menyita sebagian besar waktu saya, karena saya tidak tahu skrip mana yang termasuk untuk dapat menjalankan kode Socket.IO tanpa nodeServer (karena halaman klien akan dilayani oleh Apache).

Tapi semuanya sudah selesai; ketika Anda menginstal modul Socket.IO dengan npm, skrip tersedia di /node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js; bahwa skrip yang akan kami sertakan di halaman PHP kami, dalam kasus saya:

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

Dan untuk menyelesaikan, nodeClient.js saya, di mana kita cukup terhubung ke server node dan menunggu acara untuk memperbarui halaman kita. ;)

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 );
});

Saya akan mencoba memperbarui dan meningkatkan kode saya secepat mungkin, tetapi saya pikir itu sudah terbuka untuk semua hal keren! Saya sangat terbuka untuk saran dan ulasan tentang hal ini, apakah ini cara yang baik untuk melakukannya, ..?

Semoga ini bisa membantu beberapa orang!

Jérémy Dutheil
sumber
18
Nah, ketika Anda menulis pertanyaan ada opsi "jawab pertanyaan Anda sendiri, bagikan pengetahuan gaya Tanya Jawab", jadi saya pikir kita bisa berbagi seperti ini, maaf jika saya salah :)
Jérémy Dutheil
4
Sebagai saran, saya pikir menggabungkan jawaban untuk pertanyaan ini di sini stackoverflow.com/questions/5818312/mysql-with-node-js adalah metode yang lebih unggul. menghindari panggilan ajax dan membuat kode lebih sejalan dengan penggunaan node. Sekarang, PHP dapat dengan mudah memilih informasi dari database.
blackmambo
1
Apakah mungkin untuk terhubung ke aplikasi node menggunakan io.connect jika berada di mesin yang berbeda dari aplikasi utama Anda daripada memiliki aplikasi node di server yang sama tetapi menggunakan port yang berbeda?
maembe
1
memerlukan penandatanganan hmac sebagai autentikasi pesan. ini memastikan bahwa hanya php yang dapat menyiarkan pesan ke soket. soket akan memeriksa token yang ditandatangani, dan jika lolos, ti akan menyiarkan pesan. ini bagus untuk mencegah spam dan memastikan integritas data. jadi jangan pernah memposting langsung ke soket node dari klien. alih-alih posting ke aplikasi php dengan ajax, lalu kirimkan ke server soket. tidaklah sepele untuk membuka koneksi socket ke server websocket dengan fopen + fwrite atau stream select dari php.
r3wt
1
Setuju dengan @Bangash, Anda dapat menggunakan Node.js untuk menyimpan data ke db mysql alih-alih PHP, yang akan membuatnya jauh lebih cepat
Parthapratim Neog
2

Saya memiliki solusi lain yang bekerja cukup baik untuk saya, tetapi saya ingin seseorang berkomentar tentang seberapa efektifnya, karena saya belum (belum) memiliki kesempatan / waktu untuk mengujinya di server sebenarnya.

Ini dia kode node-js. Saya meletakkan kode ini dalam file bernama nodeerver.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);  

Dan berikut adalah potongan kode sederhana di php, memanggil server node-js dengan bantuan file_get_contents ():

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

Berfungsi dengan baik, ketika saya memuat halaman php, itu pada gilirannya memanggil halaman nodeerver.js, yang jsonify knall-object.

Saya memiliki dua instalasi localhost yang berjalan di iis di windows 10, satu php-server standar, dan nodejs-server bekerja dengan paket iisnode yang rapi .

Server 'nyata' dijalankan di ubuntu.

Saya pikir ini adalah solusi yang rapi dan mudah untuk komunikasi antara dua server, tetapi mungkin seseorang memiliki komentar tentang itu?

Snorvarg
sumber
Ini tidak masuk akal bagi saya, karena Anda meluncurkan server node dari dalam skrip php. Saya tidak bisa membayangkan kasus penggunaan apa pun untuk ini. Yang kita butuhkan adalah cara untuk berkomunikasi antara instance node.js yang sedang berjalan dan php.
Lorenz Meyer
Tidak ada @Lorenz, itu adalah skrip node.js, berjalan di servernya sendiri. Saya memanggil node.js-page langsung dari php dengan file_get_contents (), dari php-server lain. Sekarang digunakan sehari-hari dengan 500+ pengguna sehari. Mungkin anda bingung karena bidak "localhost: 3002"? Itu karena contoh ini berjalan di komputer windows lokal saya, dengan dua server mandiri di iis.
Snorvarg
Saya sangat bingung. Artinya itu nodejs.jssebenarnya bukan file sumber, tetapi ini adalah URL yang Anda beri nama, karena berisi json? Yang pertama tidak masuk akal, tetapi yang terakhir tampaknya sangat membingungkan saya.
Lorenz Meyer
@Lorenz, saya mencoba untuk memperjelas contoh dengan mengubah nama file dari file nodejs js, dan mengedit teks sedikit. Untuk menjawab pertanyaan Anda, file yang sekarang diubah namanya menjadi nodeerver.js dijalankan di servernya sendiri. Panggilan http.createServer () membuat server, yang mendengarkan () untuk koneksi masuk di port 80.
Snorvarg
Perhatikan bahwa Anda dapat memanggil server node.js langsung dari browser, cukup dengan memasukkan url " localhost: 3002 / nodeerver.js ", dan Anda akan mendapatkan respons json. File_get_contents () di file php mengambil konten dari server lain, dalam hal ini server node.js.
Snorvarg
0

Coba serupa atau Anda dapat memeriksa blog saya untuk kode contoh lengkap di nodejs


Di sisi halaman Anda:

  • Soket Beban JS

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

  • Buat objek soket

var socket = io ();

  • Gunakan emitfungsi untuk mengirim data ke nodeerver.

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

Jadi sekarang kode Anda akan terlihat seperti

<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");
    });

  });
});

Sekarang di sisi server Node buat penangan untuk permintaan Anda untuk mendapatkan permintaan Anda dan mengirim pesan ke semua perangkat / browser yang terhubung (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');
});

Sekarang sisi klien / browser / klien membuat penerima untuk menerima pesan soket dari server node

<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.dll
sumber