PHPBuilder - Creating Real Time Applications with PHP and WebSockets



RSS Twitter
Articles Application Architecture

Creating Real Time Applications with PHP and WebSockets

by: Octavia Anghel
|
July 3, 2014

Introduction

This article will explore the main PHP libraries used to create real time, bi-directional applications between clients and servers over WebSockets.

 

WebSocket is full-duplex client/server communication over TCP. It is also a new feature available in browsers as a part of the HTML5 specs that allows JavaScript clients to open bi-directional socket connections to a server. The WebSocket protocol is currently supported in several browsers, including Chrome, Internet Explorer, Firefox, Safari and Opera.

 

The main characteristic of WebSockets is the ability to perform bi-directional communication without breaking the connection. This is why WebSockets makes it possible to have more interaction between a browser and a web site, facilitating live content and the creation of real-time games.

 

WebSocket connections are basically TCP socket connections that following the WebSocket rules to communicate. The WebSocket Protocol is an independent TCP-based protocol.

 

WebSocket URL

A WebSocket URL looks like this:

ws://host:port/path (ex. ws://localhost:8000/echo) 

The main parts of the URL are the host and port. The connection is made to the host on the given port number.

 

Using WebSockets

To use WebSockets, you need to have a browser and a serverthat both support the WebSocket protocol. You will also need a traditional web server such as Apache or IIS to serve your website's static content. Once you have downloaded the WebSocket server (this is not the same as Apache), you need to start it and make sure its running in the background. You'll need to make sure not to close the command prompt window!

 

Once the server is running, your client can connect to it to push messages. The client establishes a WebSocket connection through a process known as the WebSocket handshake. This process starts with the client sending a regular HTTP request to the server. An Upgrade header is included in this request that informs the server that the client wishes to establish a WebSocket connection.

 

PHPWebSockets

PHPWebSockets is a WebSockets server written in PHP (https://github.com/ghedipunk/PHP-WebSockets).

 

The WebSocket server itself is a class that can be extended to write the rest of the application. The WebSockets.php is the base class and we need to extend that class to write our own simple WebSocket server application. The WebSockets.php base class does the socket management and WebSocket handshake. In the next figure you can see the PHPWebSocket file structure:

 

 

Below is a simple chat sample application that uses the WebSockets.php class:

 

Listing testwebsock.php

#!/usr/bin/env php
<?php

require_once('./WebSockets.php');

class echoServer extends WebSocketServer {
    
  protected function process ($user, $message) {
    $this->send($user,$message);
  }
  
  protected function connected ($user) {
    // Do nothing: This is just an echo server, there's no need to track the user.
    // However, if we did care about the users, we would probably have a cookie to
    // parse at this step, would be looking them up in permanent storage, etc.
  }
  
  protected function closed ($user) {
    // Do nothing: This is where cleanup would go, in case the user had any sort of
    // open files or other objects associated with them.  This runs after the socket 
    // has been closed, so there is no need to clean up the socket itself here.
  }
}

$echo = new echoServer("0.0.0.0","9000");

try {
  $echo->run();
}
catch (Exception $e) {
  $echo->stdout($e->getMessage());
}

 

 

Starting the server using the php –q testwebsock.php

 

Listing client.html

...
<script type="text/javascript">
var socket;

function init() {
	var host = "ws://127.0.0.1:9000/echobot"; // SET THIS TO YOUR SERVER
	try {
		socket = new WebSocket(host);
		log('WebSocket - status '+socket.readyState);
		socket.onopen    = function(msg) { 
							   log("Welcome - status "+this.readyState); 
						   };
		socket.onmessage = function(msg) { 
							   log("Received: "+msg.data); 
						   };
		socket.onclose   = function(msg) { 
							   log("Disconnected - status "+this.readyState); 
						   };
	}
	catch(ex){ 
		log(ex); 
	}
	$("msg").focus();
}

function send(){
	var txt,msg;
	txt = $("msg");
	msg = txt.value;
	if(!msg) { 
		alert("Message can not be empty"); 
		return; 
	}
	txt.value="";
	txt.focus();
	try { 
		socket.send(msg); 
		log('Sent: '+msg); 
	} catch(ex) { 
		log(ex); 
	}
}
function quit(){
	if (socket != null) {
		log("Goodbye!");
		socket.close();
		socket=null;
	}
}

function reconnect() {
	quit();
	init();
}

// Utilities
function $(id){ return document.getElementById(id); }
function log(msg){ $("log").innerHTML+="<br>"+msg; }
function onkey(event){ if(event.keyCode==13){ send(); } }
</script>
... 

 

 

Run the client.html in the browser and communicate with the server.

 

A simple and functional chat application using the PHPWebSockets can be downloaded from here.

 

Ratchet

Ratchet (http://socketo.me/) is one of the main PHP libraries used to create real time, bi-directional applications between clients and servers over WebSockets and also provides you many components to easily add functionality in your application, such as I/O (socket transport), HTTP Protocol Handler, WebSocket Protocol Handler, Session Provider and WAMP Protocol Handler. To install Ratchet you need to add the code below in your composer.json file and run the: >php ~/composer.phar install in command prompt.

 

{
    "require": {
        "cboden/ratchet": "0.3.*"
    }
}

 

An simple chat example that uses Ratchet implements the MessageComponentInterface, which implements the decorator pattern to build an application stack, and that inherits from the ComponentInterface and from the MessageInterface the following methods, described next:

 

This basic application will listen for 4 events:

onOpen - Called when a new client has Connected

onMessage - Called when a message is received by a Connection

onClose - Called when a Connection is closed

onError - Called when an error occurs on a Connection

 

Next class is the chat "application."

 

Listing chat.php

<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

    // Make sure composer dependencies have been installed
    require __DIR__ . '/vendor/autoload.php';

class Chat implements MessageComponentInterface {
    protected $clients;

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

    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        foreach ($this->clients as $client) {
            if ($from != $client) {
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        $conn->close();
    }
}

 

Run this script using the >php chat.php in command prompt.

// Run the server application through the WebSocket protocol on port 8080
    $app = new Ratchet\App('localhost', 8080);
    $app->route('/chat', new Chat);
    $app->route('/echo', new Ratchet\Server\EchoServer, array('*'));
    $app->run();

 

And then open a page with the following JavaScript:

var conn = new WebSocket('ws://localhost:8080/echo');
    conn.onmessage = function(e) { console.log(e.data); };
    conn.send('Hello!'); 

 

You can find some complex working Ratchet examples here and you can also learn about the composer dependencies that Ratchet example use, such as AutobahnJS (the JavaScript library to be used in conjunction with the WAMPServerComponent. It provides an Pub/Sub and RPC sub-protocol on top of WebSockets.) When (JavaScript library required by AutobahnJS for deferred calls.), Guzzle (a PHP library meant for abstracting cURL calls and working with RESTful APIs. Ratchet requires Guzzle to act as its HTTP server).

 

Elephant.io

Elephant.io is a library that provides a socket.io client fully written in PHP and its goal is to ease communications between your PHP application and a socket.io server. This library has some dependencies in order to function correctly, such as Socket.IO 0.8+, PHP 5.3+ and NodeJS 0.6.5+ and you also need openssl in your PHP config.

 

Socket.IO is a JavaScript library that enables realtime applications through bi-directional communication between web clients and server. It has two parts: a client-side library that runs in the browser, and a server-side library for node.js. To be installed, you need first to install Node.js (http://nodejs.org/M) - software platform for scalable server-side and networking applications. Node.js applications are written in JavaScript. After you install Node.js, open it and type npm install socket.io installation command.

 

Below are listed the PHP server side and the Socket.io side code of an example using the Elephant.io library.

 

The PHP server side allows you to connect to your socket.io instance and then gives something to it. At the end of the script it will be disconnected. You may notice in the code below the init and send available methods, described here:

 

init($keepalive = false) - Init will initialize the connection to socket.io
send($type, $id = null, $endpoint = null, $message = null) - Send allow you to send message to socket.io. 

 

use ElephantIO\Client as Elephant;

$elephant = new Elephant('http://localhost:8000', 'socket.io', 1, false, true, true);

$elephant->init();
$elephant->send(
    ElephantIOClient::TYPE_EVENT,
    null,
    null,
    json_encode(array('name' => 'foo', 'args' => 'bar'))
);
$elephant->close();

echo 'tryin to send `bar` to the event `foo`'; 

 

Socket.io server side looks like this:

 

var io = require('socket.io').listen(8000);

io.sockets.on('connection', function (socket) {
  console.log('user connected!');

  socket.on('foo', function (data) {
    console.log('here we are in action event and data is: ' + data);
  });
});

 

In the zip archive you will find an example of using the Elephant.IO library:

 

 

Wrench

Wrench, previously known as php-WebSocket, is a simple WebSocket server and client package for PHP 5.3/5.4 that uses streams. You can download this library from here. To install Wrench add the code below in your composer.json file and run the: >php ~/composer.phar install in command prompt.

 

{
    ...
    "require": {
        "wrench/wrench": "dev-master"
    }
}

 

or bootstrap like this:

 

require_once 'SplClassLoader.php';

$classLoader = new \SplClassLoader('Wrench', __DIR__ . '/../path/to/wrench/lib');
$classLoader->register();

 

The complete API documentation is found here.

 

Below is also a simple chat example that you will find in the zip archive:

 

A simple server is listed next:

 

Listing server.php

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);

require('lib/SplClassLoader.php');

$classLoader = new SplClassLoader('Wrench','/lib');
$classLoader->register();

$server = new \Wrench\Server('ws://localhost:8000'); 
$server->registerApplication('echo', new \Wrench\Application\EchoApplication()); 
$server->run();

 

Listing index.html

. . .
    <script src="js/jquery.min.js"></script>
    <script src="js/json2.js"></script>
    <script src="lib/coffeescript/jsmaker.php?f=client.coffee"></script>

    <meta charset=utf-8/>

    <title>Shiny WSS Demo Application</title>
</head>
. . . 

 

The output of this simple application should look like this:

 

 

Simple chat example using Wrench library.

 

Conclusion

Throughout this article we have reviewed the main PHP libraries that aid in the creation of real time applications with PHP and WebSockets.

 

Comment and Contribute

Your comment has been submitted and is pending approval.

Author:
Octavia Anghel

Comment:



Comment:

(Maximum characters: 1200). You have characters left.