DEV Community

MD ARIFUL HAQUE
MD ARIFUL HAQUE

Posted on

Building Real-Time Applications with PHP Using WebSockets

Building real-time applications using WebSockets in PHP allows for continuous, two-way communication between the client and server. WebSockets are particularly useful in scenarios such as live chat applications, notifications, multiplayer games, and other interactive services where real-time communication is crucial.

Here's an outline of how to build a WebSocket server in PHP and how to integrate it into a real-time application:

Steps to Build a Real-Time Application with WebSockets in PHP

1. What is WebSocket?

WebSocket is a protocol that provides full-duplex communication between a server and clients over a single, long-lived TCP connection. It allows messages to be sent to and from a server without the overhead of traditional HTTP requests.

2. Why Use WebSockets?

  • Real-time updates: Ideal for applications that require immediate feedback.
  • Efficient communication: Maintains an open connection, eliminating the need for repeated HTTP requests.
  • Low latency: Better performance in terms of speed and resource usage compared to traditional polling or long-polling methods.

3. WebSocket Communication Flow

  • Client opens connection: Client sends a WebSocket handshake to the server.
  • Server acknowledges: Server responds to the handshake, and a WebSocket connection is established.
  • Messages exchanged: Both client and server can send messages at any time.
  • Connection closed: Either client or server can close the connection when done.

4. Setting Up a WebSocket Server in PHP

PHP doesn’t natively support WebSockets, but you can use a PHP script or libraries like Ratchet or Swoole to create a WebSocket server.

Here’s how to create a basic WebSocket server using PHP without additional libraries:

4.1. Basic WebSocket Server in PHP

<?php
// WebSocket Server in PHP

// Set up the IP and port
$host = '127.0.0.1'; // Use localhost for testing
$port = 8080;        // Port number

// Create the WebSocket server socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

// Bind to the port and start listening for connections
socket_bind($socket, $host, $port);
socket_listen($socket);

// Array to hold connected clients
$clients = array($socket);

while (true) {
    // Prepare an array of sockets to check for activity
    $read = $clients;
    socket_select($read, $write = NULL, $except = NULL, 0, 10);

    // If the master socket is readable, accept a new connection
    if (in_array($socket, $read)) {
        $newClient = socket_accept($socket);
        $clients[] = $newClient;

        // Perform WebSocket handshake
        $request = socket_read($newClient, 5000);
        perform_handshake($request, $newClient, $host, $port);

        echo "New client connected.\n";
        unset($read[array_search($socket, $read)]);
    }

    // Check each client for incoming data
    foreach ($read as $client) {
        $data = @socket_read($client, 1024, PHP_NORMAL_READ);
        if ($data === false) {
            unset($clients[array_search($client, $clients)]);
            socket_close($client);
            echo "Client disconnected.\n";
            continue;
        }

        // Process the received data
        $decodedData = decode($data);
        echo "Received message: " . $decodedData . "\n";

        // Send the response to all connected clients
        $response = encode("Server received: " . $decodedData);
        foreach ($clients as $sendClient) {
            if ($sendClient != $socket && $sendClient != $client) {
                socket_write($sendClient, $response);
            }
        }
    }
}

// Function to perform WebSocket handshake
function perform_handshake($request, $client, $host, $port) {
    $headers = array();
    $lines = preg_split("/\r\n/", $request);

    foreach ($lines as $line) {
        $line = chop($line);
        if (preg_match('/\A(\S+): (.*)\z/', $line, $matches)) {
            $headers[$matches[1]] = $matches[2];
        }
    }

    $secWebSocketKey = $headers['Sec-WebSocket-Key'];
    $secWebSocketAccept = base64_encode(pack('H*', sha1($secWebSocketKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));

    $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
                "Upgrade: websocket\r\n" .
                "Connection: Upgrade\r\n" .
                "WebSocket-Origin: $host\r\n" .
                "WebSocket-Location: ws://$host:$port/websocket\r\n" .
                "Sec-WebSocket-Accept:$secWebSocketAccept\r\n\r\n";
    socket_write($client, $upgrade);
}

// Function to decode WebSocket data
function decode($data) {
    $bytes = unpack('C*', $data);
    $mask = array_slice($bytes, 3, 4);
    $text = "";

    for ($i = 7; $i < count($bytes); $i++) {
        $j = $i - 7;
        $text .= chr($bytes[$i] ^ $mask[$j % 4]);
    }
    return $text;
}

// Function to encode data to send via WebSocket
function encode($text) {
    $b1 = 0x81; // FIN and text frame opcode
    $length = strlen($text);
    $header = pack('C*', $b1, $length);
    return $header . $text;
}
?>
Enter fullscreen mode Exit fullscreen mode

5. How the WebSocket Server Works:

  1. Socket Creation: We create a server socket with socket_create(), binding it to an IP and port using socket_bind().
  2. Listening: The server listens for incoming connections with socket_listen().
  3. Client Handling: When a new client connects, we accept the connection using socket_accept().
  4. WebSocket Handshake: After accepting the connection, we perform the WebSocket handshake to establish a connection using the Sec-WebSocket-Key.
  5. Communication: Once the handshake is successful, the server reads incoming data from the client and decodes the WebSocket frame. It then processes the message and sends the response to all connected clients.
  6. Disconnect Handling: If a client disconnects, the server closes the socket for that client.

6. Client Side:

You can use JavaScript in the browser to establish the WebSocket connection to your PHP WebSocket server.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket Example</title>
</head>
<body>
    <h1>WebSocket Client</h1>
    <textarea id="messages" cols="30" rows="10" readonly></textarea><br>
    <input type="text" id="messageInput">
    <button onclick="sendMessage()">Send</button>

    <script>
        var ws = new WebSocket("ws://127.0.0.1:8080");

        ws.onopen = function() {
            console.log("Connection established");
        };

        ws.onmessage = function(event) {
            var messages = document.getElementById('messages');
            messages.value += event.data + '\n';
        };

        function sendMessage() {
            var message = document.getElementById('messageInput').value;
            ws.send(message);
        }
    </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

7. Run the WebSocket Server:

  1. Run the PHP WebSocket server from the command line:
   php websocket_server.php
Enter fullscreen mode Exit fullscreen mode
  1. Open the HTML client in a browser, and the WebSocket connection will be established. You can send messages between the client and the server in real-time.

8. Enhancements with Libraries:

While the above code provides a basic WebSocket server, it's recommended to use libraries like Ratchet or Swoole for production-level applications, which offer better scalability, security, and WebSocket management.

  • Ratchet: A popular PHP library for WebSockets that handles routing, WebSocket frames, and multiple connections efficiently.
  • Swoole: A high-performance coroutine-based PHP extension that supports WebSocket servers with event-driven I/O. It significantly improves performance and concurrency.

Conclusion:

Building real-time applications with WebSockets in PHP allows for interactive and engaging user experiences. Whether you're creating a chat application or real-time notifications, WebSockets offer a powerful, low-latency communication channel between the server and clients.

Top comments (0)