Introduction to ReactPHP and Websockets

TYPO3 Developer Days 2022

Frank Berger

A bit about me

  • Frank Berger
  • Head of Engineering at code711.de, a label of B-Factor GmbH, Sudhaus7 and 12bis3.de
  • Started as an Unix Systemadministrator who also develops in 1996
  • Does TYPO3 since 2005

Websockets

Protocol ws:// and wss://

Standardized in 2011 as RFC 6455

Located in layer 7 of the OSI model (on top of layer 4 TCP)

Upgrade protocol on top of HTTP

Allows full-duplex communication

Support for all major browsers

Support in all major languages

ReactPHP (& Ratchet)

The solution in PHP

ReactPHP

ReactPHP is an event driven, non-blocking I/O framework for webservice in PHP

(think NodeJS on the server, but with PHP)

Runs on a separate port on the server, needs to be proxied through the webserver

Handles thousands of connections and events in a single PHP process

Does not need any special extensions in PHP, but leverages new features in PHP 8.1 like fibers

Ratchet

A websocket implementation with ReactPHP

Basic Implementation (server side)


						composer require cboden/ratchet
					


						use Ratchet\MessageComponentInterface;
						use Ratchet\ConnectionInterface;

						require_once __DIR__ . "/vendor/autoload.php";

						$app = new Ratchet\App('0.0.0.0', 8080);
						$app->route('/echo', new Ratchet\Server\EchoServer, array('*'));
						$app->run();
					

Client Side


							

							var conn = new WebSocket('ws://0.0.0.0:8080/echo');
							conn.onopen = function(ev) {
								conn.send('hello');
							}
							conn.onmessage = function(ev) {
								let li=document.createElement('li');
								li.innerText = ev.data;
								document.getElementById('log').append(li);
							}
						

CLient Side available events

conn.onopen
conn.onmessage
conn.onclose
conn.onerror
conn.readyState === 1

manage the open state

use custom JS events

Nothing happening much yet, how about we try this in two browsers?

Distributing the message

Chat server side


class MyChat 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) {
			$client->send($msg);
		}
	}
	public function onClose(ConnectionInterface $conn) {
		$this->clients->detach($conn);
	}
	public function onError(ConnectionInterface $conn, \Exception $e) {
		$conn->close();
	}
}
					

$app = new Ratchet\App('0.0.0.0', 8080);
$app->route('/chat', new MyChat, array('*'));
$app->run();
					

lets try it

Lets implement a simple chat

Further ideas

Using redis for backlog

Adding user profiles

Direct messages

.. and so on

Summary

Working with websockets is not so hard

Thank you, questions and resources

Twitter: @FoppelFB

https://code711.de/

fberger@code711.de

fberger@sudhaus7.de