Введение в WebSocket на PHP: от теории к практике
Современные веб-приложения всё чаще требуют мгновенной передачи данных между клиентом и сервером. Традиционный HTTP-запрос-ответный цикл, основанный на long polling или периодических AJAX-запросах, уже не справляется с задачами реального времени. Здесь на помощь приходит протокол WebSocket — технология, позволяющая установить постоянное двустороннее соединение между браузером и сервером.
В этой статье мы разберём, как создать real-time приложения на PHP с использованием WebSocket. Вы узнаете, как установить серверную библиотеку Ratchet, написать простой чат и систему уведомлений, а также какие подводные камни вас ждут. Материал ориентирован на разработчиков, знакомых с основами PHP и JavaScript.
Что такое WebSocket и почему это важно для PHP?
WebSocket — это протокол, работающий поверх TCP. Он инициируется как HTTP-запрос (handshake), после чего соединение «апгрейдится» до полноценного двустороннего канала. В отличие от HTTP:
- Сервер может отправлять данные клиенту без предварительного запроса.
- Соединение остаётся открытым, экономя ресурсы на повторные handshake.
- Задержка передачи данных минимальна — миллисекунды против секунд при long polling.
PHP традиционно считался языком, не подходящим для real-time задач из-за своей модели «один запрос — один процесс». Однако современные библиотеки, такие как Ratchet и ReactPHP, позволяют запускать долгоживущие PHP-процессы, работающие как независимые WebSocket-серверы. Это открывает возможности для:
- Онлайн-чатов и мессенджеров.
- Систем уведомлений (новые письма, заказы, алерты).
- Совместного редактирования документов.
- Игр и трейдинговых платформ.
Установка и настройка WebSocket сервера на PHP с Ratchet
Для работы с WebSocket в PHP мы будем использовать библиотеку Ratchet (на базе ReactPHP). Установка выполняется через Composer.
Шаг 1. Создаём проект и устанавливаем зависимости
mkdir websocket-php
cd websocket-php
composer require cboden/ratchet
После установки в папке vendor появятся Ratchet и ReactPHP.
Шаг 2. Создаём класс WebSocket-сервера
Создайте файл server.php:
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class ChatServer implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "Новое подключение: {$conn->resourceId}\n";
}
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);
echo "Отключение: {$conn->resourceId}\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Ошибка: {$e->getMessage()}\n";
$conn->close();
}
}
Шаг 3. Запускаем сервер
Добавьте в server.php код запуска:
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require __DIR__ . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new ChatServer()
)
),
8080
);
echo "WebSocket сервер запущен на порту 8080\n";
$server->run();
Запустите сервер из командной строки:
php server.php
Сервер будет работать, пока вы не остановите процесс (Ctrl+C).
Создание клиентской части: JavaScript WebSocket
Теперь напишем клиентскую часть на JavaScript. Создайте файл index.html:
<!DOCTYPE html>
<html>
<head>
<title>Real-time чат на PHP WebSocket</title>
</head>
<body>
<h3>WebSocket чат</h3>
<div id="messages"></div>
<input type="text" id="messageInput" placeholder="Введите сообщение...">
<button onclick="sendMessage()">Отправить</button>
<script>
const socket = new WebSocket('ws://localhost:8080');
socket.onopen = function() {
console.log('Соединение установлено');
};
socket.onmessage = function(event) {
const messages = document.getElementById('messages');
const msg = document.createElement('p');
msg.textContent = event.data;
messages.appendChild(msg);
};
socket.onclose = function() {
console.log('Соединение закрыто');
};
function sendMessage() {
const input = document.getElementById('messageInput');
socket.send(input.value);
input.value = '';
}
</script>
</body>
</html>
Откройте index.html в браузере. При отправке сообщения оно будет получено всеми подключёнными клиентами — это основа real-time чата.
Расширенный пример: система real-time уведомлений
Добавим функционал, когда сервер сам генерирует уведомления (например, при поступлении нового заказа). Для этого модифицируем серверную часть.
Сервер с периодической рассылкой
<?php
// ... (предыдущий код ChatServer)
// Внешняя функция для отправки уведомлений всем клиентам
function notifyAll($server, $message) {
foreach ($server->clients as $client) {
$client->send(json_encode([
'type' => 'notification',
'message' => $message
]));
}
}
// Пример: каждые 10 секунд отправляем тестовое уведомление
$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(10, function() use ($server