Чат на сайте — это не просто модная фишка, а реальный инструмент для удержания пользователей. Но как сделать его быстрым и отзывчивым? Ответ прост: использовать вебсокеты. В этой статье мы разберём, как построить чат на Yii2 с вебсокетами, шаг за шагом, с примерами кода и практическими советами.
Почему вебсокеты, а не AJAX?
Классический AJAX-чат работает так: браузер каждые пару секунд спрашивает сервер: «Есть новые сообщения?». Сервер отвечает: «Нет» или «Да, вот». Это как дёргать продавца в магазине каждые 5 секунд: «А есть хлеб? А сейчас? А сейчас?». Продавец злится, вы тратите время.
Вебсокеты — это постоянный канал связи. Как телефонный звонок: один раз соединились и общаетесь, пока не надоест. Сервер сам присылает сообщение, как только оно появилось. Никаких лишних запросов, мгновенная доставка.
В Yii2 нет встроенной поддержки вебсокетов, но это не проблема. Мы можем использовать популярную библиотеку Ratchet для PHP. Она отлично дружит с Yii2.
Установка и настройка Ratchet
Для начала установим Ratchet через Composer. Откройте терминал в корне вашего Yii2-проекта и выполните:
composer require cboden/ratchet
Теперь создадим консольную команду, которая запустит WebSocket-сервер. В Yii2 для этого удобно использовать контроллеры в папке commands.
Создайте файл commands/ChatController.php:
<?php
namespace app\commands;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use yii\console\Controller;
use app\components\ChatServer;
class ChatController extends Controller
{
public function actionStart()
{
$server = IoServer::factory(
new HttpServer(
new WsServer(
new ChatServer()
)
),
8080
);
$server->run();
}
}
Здесь мы создаём сервер на порту 8080. Класс ChatServer мы напишем чуть позже — он будет обрабатывать подключения и сообщения.
Пишем логику чата: класс ChatServer
Создайте файл components/ChatServer.php. Этот класс реализует интерфейсы MessageComponentInterface и ConnectionInterface из Ratchet. Вот его основа:
<?php
namespace app\components;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Yii;
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)
{
$data = json_decode($msg, true);
// Сохраняем сообщение в базу данных
$message = new \app\models\Message();
$message->user_id = $data['user_id'];
$message->text = $data['text'];
$message->created_at = time();
$message->save();
// Рассылаем всем клиентам
foreach ($this->clients as $client) {
$client->send(json_encode([
'user_id' => $data['user_id'],
'text' => $data['text'],
'created_at' => date('H:i:s'),
]));
}
}
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();
}
}
Этот код принимает сообщения в формате JSON, сохраняет их в базу (модель Message нужно создать) и рассылает всем подключённым клиентам.
Клиентская часть: JavaScript и WebSocket
Теперь напишем клиентский скрипт, который будет подключаться к нашему серверу и отправлять сообщения. Добавьте на страницу чата следующий код:
// Подключаемся к WebSocket-серверу
const socket = new WebSocket('ws://localhost:8080');
// Отправка сообщения
function sendMessage() {
const input = document.getElementById('messageInput');
const text = input.value.trim();
if (text === '') return;
const data = {
user_id: 1, // Здесь должен быть ID текущего пользователя
text: text
};
socket.send(JSON.stringify(data));
input.value = '';
}
// Получение сообщений
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
const messagesDiv = document.getElementById('messages');
const messageElement = document.createElement('div');
messageElement.innerHTML = `<strong>Пользователь ${data.user_id}</strong> (${data.created_at}): ${data.text}`;
messagesDiv.appendChild(messageElement);
};
// Обработка закрытия соединения
socket.onclose = function() {
console.log('Соединение закрыто. Попробуйте перезагрузить страницу.');
};
Не забудьте добавить HTML-разметку для поля ввода и области сообщений:
<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="Введите сообщение...">
<button onclick="sendMessage()">Отправить</button>
Это минимальный рабочий пример. В реальном проекте стоит добавить аутентификацию, индикатор набора текста и историю сообщений.
Сравнение подходов: AJAX vs WebSocket
Чтобы вы окончательно поняли, почему вебсокеты лучше, вот таблица сравнения:
| Характеристика | AJAX | WebSocket |
|---|---|---|
| Задержка | Высокая (зависит от интервала опроса) | Низкая (мгновенно) |
| Нагрузка на сервер | Высокая (много лишних запросов) | Низкая (одно соединение) |
| Сложность реализации | Простая | Средняя |
| Поддержка браузерами | Везде | Современные браузеры |
Как видите, вебсокеты выигрывают по производительности, но требуют немного больше усилий при настройке.
Запуск и отладка
Чтобы запустить сервер, выполните в терминале:
php yii chat/start
Сервер начнёт слушать порт 8080. Откройте браузер, перейдите на страницу с чатом — и попробуйте отправить сообщение. Если что-то не работает, проверьте консоль браузера (F12) и вывод терминала.
Частая проблема: порт 8080 занят. Поменяйте его на другой, например 8081.
Ещё один момент: в продакшене нельзя просто запустить скрипт в терминале. Нужно использовать супервизор (supervisor) или systemd, чтобы сервер автоматически перезапускался при падении.
Что в итоге?
Мы построили простой чат на Yii2 с вебсокетами. Да, это только основа, но вы уже можете отправлять и получать сообщения в реальном времени. Дальше можно добавить приватные комнаты, уведомления, историю сообщений и многое другое.
Главное — не бойтесь экспериментировать. Вебсокеты открывают двери в мир реального времени, и Yii2 с Ratchet — отличный тандем для этого.
Студия WNDER

