Get started with 33% off your first certification using code: 33OFFNEW

How to use websockets in PHP using Ratchet

5 min read
Published on 14th March 2023
How to use websockets in PHP using Ratchet

Websockets are a communication protocol that allow two-way communication between a client and a server. They are commonly used in real-time applications such as chat applications, online games, and stock trading platforms.

In this tutorial, we'll look at how to use websockets in PHP. We'll start by creating a simple PHP script that listens for incoming websocket connections, and then we'll build on that by adding support for sending and receiving messages.

Prerequisites

Before we begin, you'll need to have the following installed on your system:

  • PHP (version 5.4 or later)
  • Composer (a package manager for PHP)
  • You'll also need to have a basic understanding of how websockets work.

Step 1: Setting Up the Project

Create a new directory for your project and navigate to it in a terminal window. Then, run the following command to create a new composer project:

composer init

Follow the prompts to set up your project. When prompted for a package name, you can use any name you like (e.g. "my-websocket-project"). For the other prompts, you can accept the default values by pressing enter.

Once the project is set up, run the following command to install the Ratchet library, which we'll be using to implement websockets:

composer require cboden/ratchet

Step 2: Implementing the WebSocket Server

Create a new file called "server.php" in your project directory, and add the following code to it:

<?php
require __DIR__ . '/vendor/autoload.php';

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\WebSocket\MessageComponentInterface as WebSocketMessageComponentInterface;
use Ratchet\WebSocket\WsServer;

class MyWebSocketServer implements WebSocketMessageComponentInterface
{
    public function onOpen(ConnectionInterface $conn)
    {
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg)
    {
        echo "Received message: {$msg}\n";
    }

    public function onClose(ConnectionInterface $conn)
    {
        echo "Connection closed! ({$conn->resourceId})\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        echo "Error: {$e->getMessage()}\n";
        $conn->close();
    }
}

$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new MyWebSocketServer()
        )
    ),
    8080
);

$server->run();

This code creates a new WebSocket server that listens on port 8080. When a client connects to the server, the onOpen() method is called. When the server receives a message from a client, the onMessage() method is called. When a client disconnects from the server, the onClose() method is called. If an error occurs, the onError() method is called.

Step 3: Testing the WebSocket Server

Start the server by running the following command in your terminal:

php server.php

This will start the server and begin listening for incoming websocket connections.

Next, open a new terminal window and run the following command to connect to the server:

wscat -c ws://localhost:8080

You may need to install wscat via npm globally if you don't have it already:

npm install -g wscat

This will connect to the websocket server and allow you to send and receive messages.

Try sending a message by typing the following command:

> hello world

You should see the message "Received message: hello world" printed in the terminal window where you started the server.

Step 4: Sending Messages

In order to send messages from the server to the client, we need to keep track of all connected clients. We can do this by storing their connections in an array.

Modify the MyWebSocketServer class to add a new property and modify the onOpen() and onClose() methods as follows:

class MyWebSocketServer implements WebSocketMessageComponentInterface
{
    protected $clients;

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

    public function onOpen(ConnectionInterface $conn)
    {
        echo "New connection! ({$conn->resourceId})\n";
        $this->clients->attach($conn);
    }

    public function onClose(ConnectionInterface $conn)
    {
        echo "Connection closed! ({$conn->resourceId})\n";
        $this->clients->detach($conn);
    }
}

The $clients property is an instance of SplObjectStorage, which is a built-in PHP class that allows us to store objects and associate data with them.

Next, modify the onMessage() method to broadcast the received message to all connected clients:

public function onMessage(ConnectionInterface $from, $msg)
{
    echo "Received message: {$msg}\n";
    foreach ($this->clients as $client) {
        if ($from !== $client) {
            $client->send($msg);
        }
    }
}

This code loops over all connected clients, and sends the message to each client except for the one that sent the original message.

Step 5: Adding Authentication

In a real-world application, you'll likely want to add authentication to your websocket server to prevent unauthorized access. Here's an example of how you might do that.

First, modify the MyWebSocketServer class to require a username and password when a client connects:

class MyWebSocketServer implements WebSocketMessageComponentInterface
{
    protected $clients;

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

    public function onOpen(ConnectionInterface $conn)
    {
        $queryParams = $conn->httpRequest->getUri()->getQuery();
        parse_str($queryParams, $queryParamsArray);

        $username = $queryParamsArray['username'] ?? null;
        $password = $queryParamsArray['password'] ?? null;

        if ($username !== 'myusername' || $password !== 'mypassword') {
            $conn->close();
            return;
        }

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

    public function onClose(ConnectionInterface $conn)
    {
        echo "Connection closed! ({$conn->resourceId})\n";
        $this->clients->detach($conn);
    }

    // ...
}

This code retrieves the username and password parameters from the query string of the websocket connection URL. If the username and password are not valid, the connection is immediately closed.

Next, modify the server.php file to add an event loop and keep the server running indefinitely:

use React\EventLoop\Factory as EventLoopFactory;
use React\Socket\Server as Reactor;
use React\Socket\ConnectionInterface as ReactConnection;

$loop = EventLoopFactory::create();
$socket = new Reactor('0.0.0.0:8080', $loop);
$server = new IoServer(
    new HttpServer(
        new WsServer(
            new MyWebSocketServer()
        )
    ),
    $socket,
    $loop
);
$server->run();

This code uses the ReactPHP event loop to keep the server running indefinitely, rather than relying on the default PHP web server.

Conclusion

In this tutorial, we've looked at how to use websockets in PHP using the Ratchet library. We started by creating a simple websocket server that listens for incoming connections, and then we built on that by adding support for sending and receiving messages, and adding authentication.

Websockets are a powerful tool for building real-time web applications, and PHP is a great language to use for server-side development. With the help of the Ratchet library, it's easy to get started with websockets in PHP.

If you want to learn more about websockets and real-time web development, there are many great resources available online. Happy coding!