Веб-приложения давно перестали быть просто страницами с формами. Пользователи хотят мгновенных обновлений: чаты, уведомления, совместное редактирование. Обычные HTTP-запросы тут не справляются. На помощь приходят вебсокеты. В этой статье разберём, как подружить Yii2 с вебсокетами, чтобы ваше приложение работало в реальном времени.

Digital-студия WNDER

Что такое вебсокеты и зачем они нужны в Yii2

Вебсокет — это постоянное двустороннее соединение между браузером и сервером. Представьте телефонный разговор: вы говорите, собеседник отвечает сразу, без задержек. В отличие от HTTP, где клиент каждый раз спрашивает «есть что-нибудь новое?», вебсокет держит канал открытым, и сервер сам присылает данные, когда нужно.

В Yii2 нет встроенного вебсокет-сервера, но это не проблема. Фреймворк отлично расширяется. Мы можем использовать сторонние библиотеки, например, Ratchet или Swoole, и интегрировать их с Yii2-компонентами.

Зачем это в Yii2? Допустим, у вас интернет-магазин. Пользователь оформил заказ — и сразу видит, как статус меняется с «Обрабатывается» на «Отправлен». Или чат поддержки: оператор отвечает, а сообщение появляется без перезагрузки страницы. Всё это — реальное время.

Выбираем инструмент: Ratchet или Swoole

Для PHP есть два популярных решения для вебсокетов: Ratchet и Swoole. Ratchet — это чистый PHP, работает поверх ReactPHP. Swoole — это расширение PHP, написанное на C, даёт высокую производительность, но требует установки.

Сравним их в таблице.

Характеристика Ratchet Swoole
Установка Через Composer Расширение PHP (pecl)
Производительность Средняя Высокая
Сложность освоения Низкая Средняя
Поддержка Yii2 Легко интегрировать Требует адаптации

Для большинства проектов на Yii2 достаточно Ratchet. Он прост в настройке и не требует экзотики. Swoole выбирайте, если нужна максимальная нагрузка.

Правило: Начинайте с Ratchet. Если упрётесь в производительность — переходите на Swoole. Не усложняйте заранее.

Устанавливаем и настраиваем Ratchet в Yii2

Первым делом установим Ratchet через Composer. В корне проекта выполните:

composer require cboden/ratchet

Теперь создадим консольную команду для запуска вебсокет-сервера. В Yii2 это делается через контроллер в папке commands. Создайте файл WebSocketController.php.

<?php
namespace app\commands;

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use yii\console\Controller;
use app\components\ChatHandler;

class WebSocketController extends Controller
{
    public function actionStart()
    {
        $server = IoServer::factory(
            new HttpServer(
                new WsServer(
                    new ChatHandler()
                )
            ),
            8080
        );
        $this->stdout("Сервер запущен на порту 8080\n");
        $server->run();
    }
}

Здесь мы создаём сервер на порту 8080 и передаём ему обработчик ChatHandler. Этот класс мы сейчас напишем. Он будет управлять подключениями и сообщениями.

<?php
namespace app\components;

use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;

class ChatHandler 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();
    }
}

Это простейший чат-сервер: все сообщения от одного клиента рассылаются остальным. Теперь запустим сервер из консоли:

php yii websocket/start

Сервер слушает порт 8080. Осталось подключиться к нему из браузера.

Клиентская часть: JavaScript и WebSocket API

На стороне клиента всё просто. Браузерный WebSocket API входит в стандарт. Подключимся к нашему серверу и отправим сообщение.

const socket = new WebSocket('ws://localhost:8080');

socket.onopen = function() {
  console.log('Соединение установлено');
  socket.send('Привет, сервер!');
};

socket.onmessage = function(event) {
  console.log('Получено: ' + event.data);
};

socket.onclose = function() {
  console.log('Соединение закрыто');
};

Этот код можно вставить в <script> на любой странице Yii2. Но чтобы было красиво, добавим простую форму чата.

<div id="chat">
  <div id="messages" style="height: 300px; overflow-y: scroll; border: 1px solid #ccc; padding: 10px; margin-bottom: 10px;"></div>
  <input type="text" id="messageInput" placeholder="Введите сообщение..." style="width: 80%;">
  <button id="sendButton">Отправить</button>
</div>

<script>
  const socket = new WebSocket('ws://localhost:8080');
  const messages = document.getElementById('messages');
  const input = document.getElementById('messageInput');
  const button = document.getElementById('sendButton');

  socket.onmessage = function(event) {
    const div = document.createElement('div');
    div.textContent = event.data;
    messages.appendChild(div);
    messages.scrollTop = messages.scrollHeight;
  };

  button.onclick = function() {
    const text = input.value.trim();
    if (text) {
      socket.send(text);
      input.value = '';
    }
  };
</script>

Теперь у вас есть рабочий чат. Откройте две вкладки — и увидите, как сообщения летают между ними.

Практические советы и подводные камни

Вот несколько рекомендаций, которые сэкономят вам нервы.

  • Не запускайте вебсокет-сервер на том же порту, что и веб-сервер. Используйте отдельный порт, например 8080, и проксируйте через Nginx.
  • Обрабатывайте переподключения. Соединение может разорваться. В JavaScript добавьте socket.onclose с таймером для повторного подключения.
  • Используйте WSS для HTTPS. Если сайт работает по HTTPS, вебсокет должен быть WSS (защищённый). Настройте SSL-сертификат.
  • Храните состояние в Redis или базе. Если сервер упадёт, история сообщений не потеряется.
Лайфхак: Для отладки используйте вкладку Network в DevTools. Там видно все кадры WebSocket. А ещё можно поставить расширение «WebSocket King» для ручного тестирования.

Ещё один момент: Ratchet не дружит с Yii2-сессиями из коробки. Если нужно авторизовать пользователя, передавайте токен в URL или первом сообщении, а затем проверяйте его на сервере через компонент Yii.

Что в итоге

Вебсокеты в Yii2 — это не страшно. С помощью Ratchet вы можете добавить реальное время в любое приложение: чаты, уведомления, обновления статусов. Главное — правильно настроить сервер и не забыть про обработку ошибок.

Помните: начинайте с простого, тестируйте каждый шаг. И тогда ваше приложение станет по-настоящему интерактивным.

Студия WNDER