WebSocket in PHP: Creating Advanced-Level Real-Time Applications

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

WebSocket in PHP: From Theory to Industrial Real-Time Applications



The WebSocket protocol revolutionized web development by enabling full-duplex communication channels between client and server. Unlike classic AJAX (long polling, Server-Sent Events), WebSocket provides a persistent connection with minimal overhead. For a PHP developer, transitioning from basic "echo server" examples to an industrial real-time application is a serious challenge involving state management, scaling, and asynchronous processing.



In this article, we will explore advanced techniques for working with WebSocket in PHP: multi-user chat architecture, integration with Redis for horizontal scaling, background task processing, and performance optimization.



1. Architecture of an Advanced WebSocket Server with Ratchet



The Ratchet library (based on ReactPHP) remains the gold standard for WebSocket in PHP. However, for production solutions, a simple onMessage is not enough. Let's consider a component-based architecture with separation of concerns:



<?phpuse Ratchet\\MessageComponentInterface;use Ratchet\\ConnectionInterface;use React\\EventLoop\\LoopInterface;

class RealTimeHub implements MessageComponentInterface { private $clients; private $loop; private $redis; private $userRegistry;

public function __construct(LoopInterface $loop, \\Redis $redis) { $this->clients = new \\SplObjectStorage; $this->loop = $loop; $this->redis = $redis; $this->userRegistry = []; }

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

public function onMessage(ConnectionInterface $from, $msg) { $data = json_decode($msg, true);

switch ($data['type'] ?? '') { case 'auth': $this->handleAuth($from, $data); break; case 'message': $this->handleMessage($from, $data); break; case 'subscribe': $this->handleSubscribe($from, $data); break; default: $from->send(json_encode(['error' => 'Unknown command'])); } }

public function onClose(ConnectionInterface $conn) { $this->clients->detach($conn); // Clean up user registration if (isset($conn->userId)) { unset($this->userRegistry[$conn->userId]); } }

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

private function handleAuth(ConnectionInterface $conn, array $data) { $token = $data['token'] ?? ''; // JWT token validation $userId = $this->validateToken($token); if ($userId) { $conn->userId = $userId; $this->userRegistry[$userId] = $conn; $conn->send(json_encode(['type' => 'auth_ok'])); } else { $conn->send(json_encode(['type' => 'auth_fail'])); } }

private function handleMessage(ConnectionInterface $from, array $data) { $targetUserId = $data['to'] ?? null; if ($targetUserId && isset($this->userRegistry[$targetUserId])) { $this->userRegistry[$targetUserId]->send(json_encode([ 'type' => 'message', 'from' => $from->userId ?? 'anonymous', 'text' => $data['text'] ])); } }

private function validateToken(string $token): ?int { // Simulating JWT validation $payload = json_decode(base64_decode(explode('.', $token)[1] ?? ''), true); return $payl

Blogs

Book Recommendations