Эта статья предназначена для тех кто уже знает или начинает учить PHP, Но также человек далёкий от программирования может написать свой мессенджер если просто будет следовать инструкциям.

Для начала давайте объясню что такое WebSocket, простыми словами это тоже самое что и AJAX (http) только тут Клиент (Фронтенду) подключается к Серверу (Бэкенду) и не разрывает соединение а соединение остаётся активным, и мы можем отправлять запросы сколько угодно и сервер тоже. То-есть сервер может на наш запрос не отвечать а мы просто отправлять и наоборот можем вез порядочно отправлять друг другу запросы. Иллюстрация принципа работы WebSocket.

1. Установка PHP

И так мы поняли что такое WebSocket, теперь давайте установим PHP (Язык программирования).

Для Windows пользователей:

Шаг 1: Заходим на официальный сайт ospanel.io.

Шаг 2: Нажимаем скачать и на открывшейся странице два раза нажимаем на кнопку "Нет, спасибо, хочу просто скачать" и начнётся скачивание Open Server (пока скачивайте можете попить чайку ????)

Шаг 3: Двойной клик по файлу. Откроется окошко с предложением выбрать место, куда распаковать файлы из архива. Я выбрал диск D.

Жмем кнопку ОК. Начнется процесс разархивации.

Шаг 4: Заходим в папку, которую выбрали на 3-ем шаге. Видим что появилась папка OpenServer. Входим в неё.

Видим два ярлыка запуска программы (ярлык может быть всего один, это зависит от разрядности Windows).

Два раза щелкаем по ярлычку Open Server x64.

Так как это первый запуск Опенсервера, то начнется процесс установки компонентов (MicrosoftVC++) для правильной работы программы.

После окончания установки программа подскажет, что нужно перезагрузить компьютер. Перезагружаем.

Шаг 5: Заново проходим четвертый шаг – то есть заходим в папку Опенсервера и запускаем программу.

В трее (область в нижнем правом углу там, где часы) видим новый значок – красный флажок.

Щелкаем мышкой по нему, и откроется меню программы.

Шаг 6: Нажимаем My favorites и Git-Bash

Шаг 7(Последний): Пишем на появившейся окошке php -v и видим

Для Linux Пользователей:

Шаг 1: Открываем терминал и пишем команду

Для Arch Linux -> sudo pacman -S php

Для Debiam Linux -> sudo apt -y install php8.2

Для Fedora/RHEL -> sudo dnf install dnf-plugins-core
sudo dnf install http://rpms.remirepo.net/fedora/remi-release-37.rpm
sudo dnf module reset php
sudo dnf config-manager --set-enabled remi
sudo dnf module enable php:remi-8.2
sudo dnf module install php:remi-8.2

Шаг 2 (Последний): Перезагружаем систему и вводим в терминале php -v
Должны увидеть

2. Установка Composer (Пакетный менеджер PHP)

Мы установили PHP, теперь давайте установим Composer чтобы использовать фреймворк Ratchet для написания WebSocket приложений на PHP.

Шаг 1: Зайдите на сайт - https://getcomposer.org/download/ потом спуститесь ниже и нажмите на ссылку Latest Stable у вас должно скачаться файл composer.phar.

Шаг 2: Создайте папку где нибудь в системе для проекта и перемещаем туда скачанный файл composer.phar.

Шаг 3: Открываем терминал и переходим на директорию проекта пишем cd [директория вашего проекта]

Шаг 4: Пишем в терминале php composer.phar require cboden/ratchet для установки фреймворка Ratchet

Теперь у нас всё готово для написания кода.

3. Пишем код

И так давайте в папке проекта создадим файлы client.html и server.php

Вот как должен выглядеть папка нашего проекта после всех выше манипуляций.
Вот как должен выглядеть папка нашего проекта после всех выше манипуляций.

Открываем server.php на любом вам удобном текстовом редакторе (не имеется введу Word или его аналог а именно текстовый редактор по типу блокнота в Windows или редактора кода к примеру Notepad++).

и пишем туда код

<?php

require __DIR__ . '/vendor/autoload.php';

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\WebSocket\WsServer;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;

// Создаем класс обработчика сообщений WebSocket
class WebSocketHandler implements MessageComponentInterface {
  protected $clients;

  public function __construct() {
    $this->clients = new \SplObjectStorage;
  }

  // Обработчик нового подключения клиента
  public function onOpen(ConnectionInterface $conn) {
    $this->clients->attach($conn);
    echo "New client connected: {$conn->resourceId}\n";
  }

  // Обработчик получения сообщения от клиента
  public function onMessage(ConnectionInterface $from, $msg) {
	foreach ($this->clients as $client) {
		  $client->send($msg);
	}
  }


  // Обработчик закрытия соединения клиента
  public function onClose(ConnectionInterface $conn) {
    $this->clients->detach($conn);
    echo "Client disconnected: {$conn->resourceId}\n";
  }

  // Обработчик ошибок соединения
  public function onError(ConnectionInterface $conn, \Exception $e) {
    echo "An error has occurred: {$e->getMessage()}\n";
    $conn->close();
  }
}

// Создаем новый WebSocket-сервер на порту 8080
$server = IoServer::factory(
  new HttpServer(
    new WsServer(
      new WebSocketHandler()
    )
  ),
  8080
);

// Запускаем сервер
echo "WebSocket server started\n";
$server->run();

Код require __DIR__ . '/vendor/autoload.php'; запускает автозагрузку библиотек в папке проекта.

Код ниже импортирует фреймворк Ratchet и его элементы.

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\WebSocket\WsServer;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;

а тут
class WebSocketHandler implements MessageComponentInterface {
создаём класс и реализуем интерфейс фреймворка Ratchet MessageComponentInterface к нашему классу WebSocketHandler

protected $clients;
создаём протектированную переменную $clients, эта переменная хранит все подключённые клиенты.

Ниже мы присваиваем к нашей переменной $clients объект SplObjectStorage чтобы мы могли удобно проводить манипуляцию со списком клиентов.

$this->clients = new \SplObjectStorage;

В функции ниже которая запускается при каждом подключений клиента к серверу, добавляется ID клиента к списку $clients и выводится на терминал его ID.

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

Функция ниже запускается при каждой отправке сообщения, функция получает данные отправителя и его сообщение и перечисляет всех подключённых клиентов из списка и отправляет всем сообщение включая самого отправителя чтобы он сам мог видеть свои отправленные сообщения.

  public function onMessage(ConnectionInterface $from, $msg) {
	foreach ($this->clients as $client) {
		  $client->send($msg);
	}
  }

Функция ниже вызывается при разрывании соединения с сервера с клиентом, при этом удаляя его ID из списка $clients.

public function onClose(ConnectionInterface $conn) {
    $this->clients->detach($conn);
    echo "Client disconnected: {$conn->resourceId}\n";
}

Функция ниже вызывается при ошибке с WebSocket, сервер выводит ошибку в терминал и отключает весь сервер.

public function onError(ConnectionInterface $conn, \Exception $e) {
    echo "An error has occurred: {$e->getMessage()}\n";
    $conn->close();
}

В коде ниже создаём хост с портом 8080 если оно не доступно можете изменить на 8081.


// Создаем новый WebSocket-сервер на порту 8080
$server = IoServer::factory(
  new HttpServer(
    new WsServer(
      new WebSocketHandler()
    )
  ),
  8080
);

тут $server->run(); запускаем сервер.

И запускаем код на терминале написав php server.php.

Открываем client.html и пишем туда код

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Chat</title>
</head>
<body>
    <div id="messages"></div>
    <form>
        <input type="text" id="message" autocomplete="off">
        <button>Send</button>
    </form>

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

        socket.addEventListener('open', function(event) {
            console.log('Connected to server.');
        });

        socket.addEventListener('message', function(event) {
            const messages = document.getElementById('messages');
            const message = document.createElement('div');
            message.innerHTML = event.data;
            messages.appendChild(message);
        });

        const form = document.querySelector('form');
        const input = document.querySelector('input');

        form.addEventListener('submit', function(event) {
            event.preventDefault();

            const message = input.value;
            socket.send(message);

            input.value = '';
        });
		
    </script>
</body>
</html>

Тут const socket = new WebSocket('ws://localhost:8080'); Создаётся WebSocket соединение с адресом ws://localhsot:8080 с портом 8080 как говорил выше если оно занято можете изменить на 8081.

Функция ниже выполняется при подключений с сервером и выводит текст Connected to server.

socket.addEventListener('open', function(event) {
  console.log('Connected to server.');
});

Функция ниже запускается при каждом получений сообщения которая добавляет в тег с id messages текст сообщения.

socket.addEventListener('message', function(event) {
  const messages = document.getElementById('messages');
  const message = document.createElement('div');
  message.innerHTML = event.data;
  messages.appendChild(message);
});

Функция ниже вызывается при отправке сообщения, которая отправляет сообщение серверу.

 form.addEventListener('submit', function(event) {
  event.preventDefault();

  const message = input.value;
  socket.send(message);

  input.value = '';
});

4. Пользование

Наш мессенджер готов теперь мы можем протестировать его чтобы протестировать открываем на двух вкладках браузера файл client.html и пишем любое сообщение потом нажимаем Enter или кнопку Send.

В продолжений этой статьи мы установим наш мессенджер на хостинг чтобы все могли им пользоваться.

Спасибо за просмотр!

Это моя первая статья и был бы благодарен, если отметите мои ошибки.
С уважением Туленов Темур.
При поддержке сообщества ThinkUP

Комментарии (11)


  1. NICO_01
    00.00.0000 00:00
    -4

    Здравствуйте какой хостинг вы предпочитаете использовать?


    1. temurumaru Автор
      00.00.0000 00:00

      Давайте поговорим об этом в личке


      1. Alexmaru
        00.00.0000 00:00
        +2

        Да тут у нас мастера ссылок в комментариях! Все в бункер.


      1. FanatPHP
        00.00.0000 00:00
        +2

        Здравствуйте, а давайте вы отредактируете свой последний комментарий и не будете так явно рекламировать хостинг. А напишете что-то вроде "напишу в личку, чтобы не сочли за рекламу".


        Заминусуют.
        Статья и так слабая, а вы сюда еще и рекламу тащите.
        Я бы написал в личку, но "пользователь запретил личные сообщения" уж не знаю — сам или уже какое-то ограничение навесилось.


        1. temurumaru Автор
          00.00.0000 00:00

          Конечно ок, спасибо)


        1. temurumaru Автор
          00.00.0000 00:00

          По моему само, потому что я щас как автор нахожусь в песочнице из за того что я тут новенький.


        1. temurumaru Автор
          00.00.0000 00:00

          Если есть советы как его улучшить пж напишите в личку, буду благодарен)


        1. temurumaru Автор
          00.00.0000 00:00

          Просто при созданий статья я целился ещё на развивающихся в IT людей, как туториал, или тут нельзя прям?


          1. FanatPHP
            00.00.0000 00:00
            +8

            Туториал можно, но он должен быть осмысленным.
            Тем, кто уже изучает РНР, не нужно рассказывать как его установить.
            Тем, кто только хочет изучить, не нужно рассказывать про вебсокет — им бы сначала основы синтаксиса объяснить. Они же из приведенного примера кода не поймут вообще ни одного слова. Причем я уверен, что вы и сами максимум через слово в этом коде понимаете.


            А в этом-то и заключается смысл туториалов — чтобы человек понял, как работает описываемая система, и мог либо дополнить её, либо пофиксить, если она вдруг сломается. А здесь просто "делай раз, делай два, готово!" — что это, зачем, что с этим дальше делать — непонятно.


            Если хотите написать про вебсокет, то и пишите про него, а не про то как установить пхп. Но пишите подробнее, объясняйте. А объяснять у вас как раз получается плохо.


            • объяснение "что такое WebSocket" мало того что пестрит опечатками, но главное, совершенно невразумительное. "Это как аякс". А вы уверены что ваш "развивающийся в IT человек" знает, что такое аякс? "То-есть сервер может на наш запрос не отвечать а мы просто отправлять, наоборот и можем вез порядочно отправлять друг другу запросы." — это предложение вообще с трудом можно понять.
            • Код require __DIR__ . '/vendor/autoload.php'; ничего не импортирует
            • и use Ratchet\MessageComponentInterface; тоже
            • вот "тут" class WebSocketHandler implements MessageComponentInterface мы ничего не подключаем. Интерфейс вообще ничего не подключает, это не трейт. Тут должно быть что-то вроде "Мы создаем обработчик сообщений по схеме, описанной в интерфейсе MessageComponentInterface".

            То есть мы опять упираемся в то, что вы и сами не очень понимаете этот код. И это не секрет, потому что оправдание "я пишу [плохо, потому что] для новичков" пишут как раз только новички :)


  1. funnybanana
    00.00.0000 00:00
    +1

    теперь давайте установим PHP (Язык программирования).

    Это вы хорошо уточнили...

    И вы начинаете с установки PHP (языка программирования), но для windows пользователей зачем то отправляете качать open server вместо https://www.php.net/downloads.php

    Для чего именно open server, а не скажем VertrigoServ могли бы объяснить..

    В общем то я узнаю в авторе поста одного из тех кто повёлся на онлайн курсы по программированию, при чём не очень высокого качества, аля скачай это, нажми это, скопируй это - ты программист.

    Как по мне эта статья не имеет ценности для хабра... Таких статей, с таким же кодом тут с десяток.


  1. CHIM86
    00.00.0000 00:00
    +1

    Вот скажу за себя. Я хоть и не новичок в PHP, но полез в эту статью, чтобы почитать про вебсокеты, а в итоге наткнулся на какой то псевдо-мануал по установке openserver и подключении готовых наработок. Как человек пишущий код с нуля, для меня эта статья не интересна от слова совсем, так как из неё непонятно ничего что происходит под капотом всех этих подключённых чужих фалов.