Belajar PHP Mencoba RatchetPHP untuk menangani Websocket

RatchetPHP library dapat membantu kita untuk membuat websocket, realtime aplikasi. Websocket sendiri kadang diperlukan di beberapa kasus aplikasi yang menginginkan data dan flow proses dilakukan secara realtime. Contoh sederhana adalah kita sedang chatting, ada proses yang dilakukan secara realtime.

Kasus ini sebenarnya sudah dikenalkan di salah satu fitur keren dari NodeJS. Dengan NodeJS kita dapat mudah melakukan hal tersebut dengan bahasa Javascript. Namun, mungkin ada beberapa kasus dimana kita tidak bisa menggunakan JS untuk menghandle proses websocket ini dan harus menggunakan PHP karena mungkin semua aplikasi dibagun di atas PHP.

Saya mencoba mengikuti dokumentasi dari RatchetPHP dan mengikuti beberapa tutorial yang ada di internet. Berikut saya coba tulis di blog agar nanti bisa mudah di implementasikan kembali tanpa harus browsing-browsing lagi.

Tahapan-nya:
1. PHP versi 7
Versi PHP yang bisa menjalankan Ratchetphp ini >=5.4.2. Untuk temen-temen yang masih dibawah itu belum bisa menggunakan RatchetPHP ini. Saya sarankan menggunakan PHP Versi 7+
2. Install ZeroMQ. Distributed system message.
Ini seperti RabbitMQ yang gunanya menghantarkan data/message. Karena RatchetPHP ini menggunakan ZeroMQ, saya mengikuti untuk memasang ZeroMQ di ubuntu saya. Panduan Installasi bisa mengikut di link ini: https://gist.github.com/katopz/8b766a5cb0ca96c816658e9407e83d00

#!/usr/bin/bash

# Download zeromq
# Ref http://zeromq.org/intro:get-the-software
wget https://github.com/zeromq/libzmq/releases/download/v4.2.2/zeromq-4.2.2.tar.gz

# Unpack tarball package
tar xvzf zeromq-4.2.2.tar.gz

# Install dependency
sudo apt-get update && \
sudo apt-get install -y libtool pkg-config build-essential autoconf automake uuid-dev

# Create make file
cd zeromq-4.2.2
./configure

# Build and install(root permission only)
sudo make install

# Install zeromq driver on linux
sudo ldconfig

# Check installed
ldconfig -p | grep zmq

# Expected
############################################################
# libzmq.so.5 (libc6,x86-64) => /usr/local/lib/libzmq.so.5
# libzmq.so (libc6,x86-64) => /usr/local/lib/libzmq.so
############################################################


3. Install ext-zmq. extension untuk ZeroMQ.
Extension ini untuk menghubungkan antara PHP dengan ZeroMQ. Temen-temen bisa lihat di link ini https://eole-io.github.io/sandstone-doc/install-zmq-php-linux

Setelah semua di install buat folder berisi composer json seperti berikut ini:

{
    "name": "adiputra/rachetphp-test",
    "description": "rachetphp testing",
    "require": {
        "cboden/ratchet": "^0.4.1",
        "react/zmq": "0.2.*|0.3.*"
    },
    "autoload": {
        "psr-4": {
            "Adiputra\\Rachetphp\\": "src"
        }
    },
    "authors": [
        {
            "name": "Adiputra",
            "email": "tuts.adiputra@gmail.com"
        }
    ]
}

Setelah itu jalankan composer install untuk menginstall beberapa library dari Ratchetphp ini.

Setelah itu kita buat folder src lalu di dalam folder src kita buat folder bin dan file server.php. Isi file server.php seperti berikut ini:

<?php
require dirname(__DIR__) . '../../vendor/autoload.php';

use React\EventLoop\Factory;
use React\ZMQ\Context;

$loop = React\EventLoop\Factory::create();
$broadcast = new Adiputra\Rachetphp\Broadcast;

// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', array($broadcast, 'onNewObject'));

// Set up our WebSocket server for clients wanting real-time updates
$webSock = new React\Socket\Server('0.0.0.0:8080', $loop); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            $broadcast
        )
    ),
    $webSock
);

$loop->run();

File server.php gunanya untuk membuat server serta melisten atau menerima apakah ada data yang dikirimkan oleh client atau tidak.

Setelah itu kita buat file client yaitu index.html seperti kode dibawah ini:

<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<div id="messages"></div>

<div>
    <form>
        <input type="text" id="msgText">
        <input type="button" id="msgSend" value=">">
    </form>
</div>
<script>
    var conn = new WebSocket('ws://localhost:8080');
    var userId = 51;
    
    conn.onopen = function (e) {
        console.log("Connection established!");
        console.log(e.data);
    };

    conn.onmessage = function (e) {
        console.log(e.data);

        var response = JSON.parse(e.data);
        if(response['user_id'] == userId) {
            var chat = document.createElement("div");
            var cwind = document.getElementById("messages");
            cwind.appendChild(chat);
            cwind.lastElementChild.innerHTML = response["message"];
        }
    };

    var button = document.getElementById("msgSend");

    button.onclick = function () {
        var val = document.getElementById("msgText").value;
        conn.send(JSON.stringify({'user_id': userId, 'message': val}));
    };

</script>
</body>

File index.html ini adalah file client yang nanti akan menerima data dari server ke client atau sebaliknya dari client ke server.

Setelah itu saya buat file Broadcast.php seperti kode dibawah ini:

<?php
namespace Adiputra\Rachetphp;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Broadcast implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients->attach($conn);

        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $numRecv = count($this->clients) - 1;
        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
            , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');

        foreach ($this->clients as $client) {
            if ($from !== $client) {
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn) {
        // The connection is closed, remove it, as we can no longer send it messages
        $this->clients->detach($conn);

        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }

    public function onNewObject($msg)
    {
        echo "on new object fire \n";
        foreach ($this->clients as $client) {
            $client->send($msg);
        }
    }
}

Isi file tersebut adalah membaca beberapa event yang terjadi. Temen-temen yang pernah menggunakan Socket IO pasti memahami beberapa event disini ya. Secara garis besar terdapat event ketika telah terbuka / masuk (on open). Ketika sedang tertutup (on close) dan ketika terjadi pengiriman data (on message). Beberapa method seperti on error untuk menghandle ketika terjadi error pada class Ratchetphp ini. Ke-empat method itu adalah bawaan utama atau default yang saya baca pada documentasi RatchetPHP

Terdapat method tambahan yaitu method onNewObject. Kegunaan method itu untuk mengirimkan kembali ke client data setelah menerima data.

Sampai disini kawan-kawan bisa menjalankan dengan cara:
1. Jalankan server.php
Menjalankan server.php dengan cara mengetikan php src/bin/server.php. Pastikan ketika menjalankan ini tidak memunculkan error.
2. Jalankan index.html di beberapa browser
Untuk menerima dan mengirimkan data dari client ke client lain. Kawan-kawan bisa membuka file index.html di beberapa browser seperti browser firefox dan chromium.

Sampai disini seharusnya sudah jalan dengan baik ya 🙂

Saya coba membuat file baru dengan nama SendMessage.php:

<?php
$userId = 51;

$entryData = array(
    'user_id' => $userId,
    'message' => "Send message for user id: " . $userId
);

$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'adiputra');
$socket->connect("tcp://localhost:5555");
$socket->send(json_encode($entryData));

File ini gunanya untuk mengakses langsung file PHP lalu mengirimkan data ke socket agar client bisa membaca data yang dikirimkan dengan PHP.

Temen temen bisa mencoba dengan mengetikkan perintah php src/SendMessage.php untuk mencobanya.

PHPUnit : Cara Mengambil Value Dari Hasil Test Fungsi Lain

PHPUnit salah satu tool yang menarik untuk dipelajari terutama untuk kita yang ingin project atau aplikasi kita bebas dari bug. Mungkin ada beberapa kita pernah dengar istilah TDD, Test Driven Development? Atau mungkin pernah mendengar Continuous Integration? Nah dari sini mulai belajar bagaimana code yang kita buat itu sebelumnya harus menjalankan unit testing sehingga kedepan aplikasi kita lancar walaupun ada panambahan fitur baru. Continue reading PHPUnit : Cara Mengambil Value Dari Hasil Test Fungsi Lain

Barcode Generator PHP dengan Codeigniter

Membuat barcode tidak sesulit yang disangka. Banyak library dan orang-orang baik hati ternyata yang rajin bagi-bagi kodenya :).

Untuk membuat barcode pada php dengan codeigniter, saya menggunakan barcode generator di link ini (http://www.barcodephp.com/en/download). Continue reading Barcode Generator PHP dengan Codeigniter

Tutorial PHP dan MongoDB pada Ubuntu – Part 3

Pada tutorial lalu sudah dijelaskan cara menambahkan data pada MongoDB dengan PHP. Sekarang saya coba bahas cara sederhana mengubah / edit data pada MongoDB dengan PHP. Hal yang penting saat masuk ke update data adalah “apa pembeda dari data yang mau kita update”. Tutorial ObjectId pada MongoDB lalu saya sempat buat agar sedikit nyambung apa itu “_id” dan penerapan kasus pada update data artikel ini. Jadi, silahkan baca terlebih dahulu ya tentang ObjectId pada MongoDB. Continue reading Tutorial PHP dan MongoDB pada Ubuntu – Part 3

Tutorial PHP dan MongoDB pada Ubuntu – Part 1

Setelah berhasil menginstall driver php untuk mongodb. Sekarang mari kita coba buat aplikasi sangat sederhana CRUD-nya. Pada artikel ini saya akan coba membuat sampel database pada mongodb lalu memanggil data dari database yang telah dibuat dengan PHP. Continue reading Tutorial PHP dan MongoDB pada Ubuntu – Part 1

Ambil Data Diri Google Plus Dengan PHP dan Google API

Belum lama ini saya coba-coba API nya si Google dengan mengambil data diri Google Plus. Jadi, saat dia login di aplikasi kita nanti, data-data yang dia input di Google Plus bisa diambil. Jadi, mungkin dapat jadi satu pilihan kembali apabila user ingin registrasi tak perlu membuat form input untuk menyimpan data user, cukup satu tombol untuk aksi ke API nya Google, kita bisa dapatkan data-data si user tersebut. Continue reading Ambil Data Diri Google Plus Dengan PHP dan Google API

Cara Mengambil Nilai Dolar dari Website Bank BCA dan Mandiri dengan PHP

Cara mengambil nilai dolar dari website bank BCA dan Mandiri dengan PHP dapat dilakukan dengan teknik cUrl dan DOM nya milik PHP. Biasanya teknik ini digunakan untuk keperluan e-commerce saat si toko menginginkan harga produk nya ter-list juga dengan harga dolar yang sesuai dengan perubahan dolar. Continue reading Cara Mengambil Nilai Dolar dari Website Bank BCA dan Mandiri dengan PHP

OOP Pada PHP – Pengenalan Inheritance

Inheritance atau turunan merupakan salah satu fitur dari pemrograman OOP dimana satu Class menuruni satu atau banyak class lainnya. Suatu Class yang dituruni biasa disebut Class Anak (child) sedangkan Class yang menuruni biasa disebut Class Induk (parent). Continue reading OOP Pada PHP – Pengenalan Inheritance

OOP Pada PHP : Class, Property, Method dan Objek

Pemrograman Berorientasi Objek (OOP) merupakan suatu hal yang mesti dipegang oleh programmer, baik dia programmer Java, C, PHP, Delphi dan lainnya. Mengapa ? Saya sudah sempat posting kenapa harus OOP dengan bahasa yang sederhana. Lalu bagaimana OOP pada PHP ? Continue reading OOP Pada PHP : Class, Property, Method dan Objek