@vityakarpov33

Как отправить данные через websoket из php?

Здравствуйте, кто-нибудь знает как вызвать и отправить данные через сокет из php?
Вот так вызываю в js
var conn = new WebSocket('wss://site.com:8443?token=token');

var data = {
userId: user_id
};

conn.send(JSON.stringify(data));
  • Вопрос задан
  • 93 просмотра
Пригласить эксперта
Ответы на вопрос 3
402d
@402d
начинал с бейсика на УКНЦ в 1988
сходи на packagist и выбери себе либу.
В свое время я взял hoa/websocket, но сейчас проект заброшен.
В любом случае можешь из этих примеров найти вдохновение
Ответ написан
Комментировать
@vityakarpov33 Автор вопроса
Олег я так понимаю, что это все не просто и не быстро? У меня на реализацию чата как у вк ушло почти 1.5 месяца, чтобы это гарантированно работало и со стороны сервера и фронтенд, теперь думал внедрить вызов из php для системных массовых уведомлений, но снова cтолько времени тратить пока не готов.. Видимо проще просто добавлять сообщения в бд без уведомления в браузер
Ответ написан
Комментировать
@aspirantes
Примерно так. Одно время копал в сторону веб-сокетов. Есть готовые наработки для дэймона и для чата. На просторах интернета готовый код не нашёл, только библиотеки, поэтому подгонял по RFC сам.

Общий принцип - правильно кодировать и декодировать. Ну и само собой у серверов, куда подключаешься, тоже свои заморочки имеются.

$context = stream_context_create(
  [
      'ssl' => [
        'disable_compression' => true
      ],
  ]
);
$fp = stream_socket_client("ssl://example.com:9443", $errstr, $errno, 30, STREAM_CLIENT_CONNECT, $context);
    if (!$fp) {
        echo "$errstr ($errno)<br />\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'])->data->p)) $fp3 = json_decode($fp2['message'])->data->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 >> (16 - 1))  & 0b1);        /* Финальный фрейм. Если сообщение нефрагмантированное, то всегда 1, если фрагмантированно, то у последнего 1 у остальных 0 */
        $data['rsv1']           = (bool) (($header >> (16 - 2))  & 0b1);        /* Флаги RSV1, RSV2, RSV3 служат для расширений протокола, почти всегда в false */
        $data['rsv2']           = (bool) (($header >> (16 - 3))  & 0b1);
        $data['rsv3']           = (bool) (($header >> (16 - 4))  & 0b1);
        $data['opcode']         = (int)  (($header >> (16 - 8))  & 0b1111);     /* Тип фрейма */
        $data['is_mask']        = (bool) (($header >> (16 - 9))  & 0b1);        /* Замаскированы ли фреймы */
        $data['length_prev']    = (int)  (($header >> (16 - 16)) & 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'] < 126)
        {
            $data['length'] = $data['length_prev'];
        }
        elseif ($data['length_prev'] === 126)
        {
            $data['length'] = unpack("x2/n", $str)[1];
        }
        elseif ($data['length_prev'] > 126)
        {
//          $data['length'] = unpack("x2/J", $str)[1];
            $data['length'] = unpack("x2/x4/N", $str)[1];
        }

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

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

        }
        elseif ($data['length_prev'] === 126)
        {
            $message_start += 2;
        }
        elseif ($data['length_prev'] > 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 < $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" => 0b1,
            "rsv1" => 0b0,
            "rsv2" => 0b0,
            "rsv3" => 0b0,
            "opcode" => 0x1,
            "is_mask" => $is_mask === true ? 0b1 : 0b0,
            "length" => strlen($str)
        ];

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

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

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

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

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

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

        $bin .= $str;
        print_r($bin)."\n";
        return $bin;
    }
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы