Как можно отправить данные с помощью WebSocket из PHP?

Как в PHP можно использовать сокеты для вызова и отправки данных? Вот реализация в JavaScript:

```js
var conn = new WebSocket('wss://site.com:8443?token=token');

var data = {
  userId: user_id
};

conn.send(JSON.stringify(data));
```
  • 28 июня 2024 г. 5:41
Ответы на вопрос 4
Для отправки данных с помощью WebSocket из PHP вам нужно использовать библиотеку, поддерживающую взаимодействие с WebSocket. Например, можно использовать библиотеку Ratchet (http://socketo.me/).

Пример использования Ratchet для отправки данных из PHP:

1. Установите Ratchet с помощью Composer:

```bash
composer require cboden/ratchet
```

2. Пример отправки данных:

```php
use Ratchet\Client\WebSocket;
use Ratchet\Client\Connector;
use React\EventLoop\Factory;

$loop = Factory::create();
$connector = new Connector($loop);

$connector('wss://site.com:8443?token=token')->then(function (WebSocket $conn) {
    $data = json_encode(['userId' => $user_id]);
    $conn->send($data)->then(function () use ($conn) {
        $conn->close();
    });
});

$loop->run();
```

Этот код устанавливает соединение с WebSocket-сервером по указанному URL, отправляет данные в формате JSON и закрывает соединение. Важно подставить реальный `$user_id` вместо переменной.

Таким образом, вы можете использовать сокеты в PHP для отправки данных с помощью WebSocket.
сходи на packagist и выбери себе либу. <br/> В свое время я взял hoa/websocket, но сейчас проект заброшен. <br/> В любом случае можешь из этих примеров найти вдохновение
<a href="https://qna.habr.com/user/402d" rel="nofollow">Олег</a> я так понимаю, что это все не просто и не быстро? У меня на реализацию чата как у вк ушло почти 1.5 месяца, чтобы это гарантированно работало и со стороны сервера и фронтенд, теперь думал внедрить вызов из php для системных массовых уведомлений, но снова cтолько времени тратить пока не готов.. Видимо проще просто добавлять сообщения в бд без уведомления в браузер
Примерно так. Одно время копал в сторону веб-сокетов. Есть готовые наработки для дэймона и для чата. На просторах интернета готовый код не нашёл, только библиотеки,  поэтому подгонял по <a href="https://datatracker.ietf.org/doc/html/rfc6455" rel="nofollow">RFC </a> сам. <br/> <br/> Общий принцип - правильно кодировать и декодировать. Ну и само собой у серверов, куда подключаешься, тоже свои заморочки имеются. <br/> <br/> <pre><code class="php">$context = stream_context_create(
  [
      'ssl' =&gt; [
        'disable_compression' =&gt; true
      ],
  ]
);
$fp = stream_socket_client("ssl://example.com:9443", $errstr, $errno, 30, STREAM_CLIENT_CONNECT, $context);
    if (!$fp) {
        echo "$errstr ($errno)&lt;br /&gt;\n";
    } else {
        echo "true\n";
        fwrite($fp, "POST /ws/stream HTTP/1.1\r\n" .
            "Host: example.com\r\n" .
            "Accept: */*\r\n" .
            "Cache-Control: no-cache\r\n" .
            "Sec-WebSocket-Key: qwerty123\r\n" .
            "X-Mbx-Apikey: $akey\r\n" .
            "Connection: Upgrade\r\n" .
            "Upgrade: websocket\r\n\r\n");
            $old  = time() + 180000000;
        fwrite($fp, $data);
        while (!feof($fp)) {
            $stat = fstat($fp);
            $fp2 = fread($fp, 8192);
            $new = time();
            $fp2 = decode($fp2);
            if ($fp2['opcode'] == 9) {
                fwrite($fp, encode($new, 'ping'));
                echo "\nPING\n\n";
            };
            if (isset(json_decode($fp2['message'])-&gt;data-&gt;p)) $fp3 = json_decode($fp2['message'])-&gt;data-&gt;p;
            if (isset($fp3)) echo $fp3."\n";
            print_r($fp2)."\n";
        }
}
fclose($fp);
echo('close');

function decode($str, $message_only = false)
    {
        /* Разбираем заголовок */
        if (empty($str)) return "\n\n Пустое значение \n\n";
        $header = unpack("n", $str)[1];         /* Рапаковываем первые 16 бит, порядок байт «big endian», т.к. сетевой протокол */
        $data = [];
        $data['fin']            = (bool) (($header &gt;&gt; (16 - 1))  &amp; 0b1);        /* Финальный фрейм. Если сообщение нефрагмантированное, то всегда 1, если фрагмантированно, то у последнего 1 у остальных 0 */
        $data['rsv1']           = (bool) (($header &gt;&gt; (16 - 2))  &amp; 0b1);        /* Флаги RSV1, RSV2, RSV3 служат для расширений протокола, почти всегда в false */
        $data['rsv2']           = (bool) (($header &gt;&gt; (16 - 3))  &amp; 0b1);
        $data['rsv3']           = (bool) (($header &gt;&gt; (16 - 4))  &amp; 0b1);
        $data['opcode']         = (int)  (($header &gt;&gt; (16 - 8))  &amp; 0b1111);     /* Тип фрейма */
        $data['is_mask']        = (bool) (($header &gt;&gt; (16 - 9))  &amp; 0b1);        /* Замаскированы ли фреймы */
        $data['length_prev']    = (int)  (($header &gt;&gt; (16 - 16)) &amp; 0b1111111);  /* Предварительная длина фрейма */

        /* Определяем тип фрейма */
        switch ($data['opcode']) {
            case '1':
                $data['type'] = '1'; //text
                break;
            case '2':
                $data['type'] = '2'; //binary
                break;
            case '8':
                $data['type'] = '8'; //close
                break;
            case '9':
                $data['type'] = '9'; //ping
                break;
            case '10':
                $data['type'] = '10'; //pong
                break;
            default:
                break;
        }

        /* Определяем длину фрейма */
        if ($data['length_prev'] &lt; 126)
        {
            $data['length'] = $data['length_prev'];
        }
        elseif ($data['length_prev'] === 126)
        {
            $data['length'] = unpack("x2/n", $str)[1];
        }
        elseif ($data['length_prev'] &gt; 126)
        {
//          $data['length'] = unpack("x2/J", $str)[1];
            $data['length'] = unpack("x2/x4/N", $str)[1];
        }

        /* Маска */
        if ($data['is_mask'])
        {
            if ($data['length_prev'] &lt; 126)
            {
                $mask = substr($str, 2, 4);
            }
            elseif ($data['length_prev'] === 126)
            {
                $mask = substr($str, 2 + 2, 4);
            }
            elseif ($data['length_prev'] &gt; 126)
            {
                $mask = substr($str, 2 + 8, 4);
            }
        }

        /* Тело запроса */
        $message_start = 2;
        if ($data['length_prev'] &lt; 126)
        {

        }
        elseif ($data['length_prev'] === 126)
        {
            $message_start += 2;
        }
        elseif ($data['length_prev'] &gt; 126)
        {
            $message_start += 8;
        }

        if ($data['is_mask'])
        {
            $message_start += 4;
        }
        $data['message_start'] = $message_start;

        $message = substr($str, $message_start, $data['length']);

        /* Размаскируем сообщение */
        if ($data['is_mask'])
        {
            $length = strlen($message);

            for ($i = 0; $i &lt; $length; $i++) 
            {
                $message[$i] = $message[$i] ^ $mask[$i % 4];
            }
        }

        $data['message'] = $message;

        /* Возвращаем сообщение */
        if ($message_only === false)
        {
            return $data;
        }
        else
        {
            return $data['message'];
        }
    }

    /**
     * Закодировать строку
     * 
     * @param string $str
     * @param boolean $is_mask
     * @return string
     */
    function encode($str, $ping = false, $is_mask = false)
    {
        $bin = "";

        /* Основные флаги */
        $data = 
        [
            "fin" =&gt; 0b1,
            "rsv1" =&gt; 0b0,
            "rsv2" =&gt; 0b0,
            "rsv3" =&gt; 0b0,
            "opcode" =&gt; 0x1,
            "is_mask" =&gt; $is_mask === true ? 0b1 : 0b0,
            "length" =&gt; strlen($str)
        ];

        if ($ping = 'ping') $data['opcode'] = 0xA;

        /* Предварительная длина */
        if ($data['length'] &lt; 126)
        {
            $data['length_prev'] = $data['length'];
        }
        elseif ($data['length'] &lt; 65536)
        {
            $data['length_prev'] = 126;
        }
        else
        {
            $data['length_prev'] = 127;
        }

        /* Заголовок */
        $header = $data['fin'];
        $header = $header &lt;&lt; 1 | $data['rsv1'];
        $header = $header &lt;&lt; 1 | $data['rsv2'];
        $header = $header &lt;&lt; 1 | $data['rsv3'];
        $header = $header &lt;&lt; 4 | $data['opcode'];
        $header = $header &lt;&lt; 1 | $data['is_mask'];
        $header = $header &lt;&lt; 7 | $data['length_prev'];
        $bin .= pack("n", $header);

        /* Расширенная длина тела */
        if ($data['length_prev'] === 126)
        {
            $bin .= pack("n", $data['length']);
        }
        elseif ($data['length_prev'] &gt; 126)
        {
            $bin .= pack("x4N", $data['length']);
        }

        /* Маскировать сообщение */
        if ($is_mask)
        {
            $mask = substr(md5(microtime()), 0, 4);
            $bin .= $mask;

            $length = strlen($str);
            for ($i = 0; $i &lt; $length; $i++) 
            {
                $str[$i] = $str[$i] ^ $mask[$i % 4];
            }
        }

        $bin .= $str;
        print_r($bin)."\n";
        return $bin;
    }</code></pre>
Похожие вопросы