Я написал сервер WebSocket на PHP, который хорошо подключается к Firefox, но не к Safari. Я думаю, что с рукопожатием что-то не так. Safari нужна старая версия hybi00 ... но я не могу найти ошибку: /
Соединение закрывается в Safari сразу после попытки подключения.
Заранее спасибо за помощь!
<code><?php
error_reporting(E_ALL);
set_time_limit(0);
date_default_timezone_set("Europe/Berlin");
ob_implicit_flush(true);
function debug($text)
{
$file = "log.html";
file_put_contents($file,
"<pre>".$text."
"."
Ende der Information ", 8);
}
// Socket initialisieren
$ master = socket_create (AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option ($ master, SOL_SOCKET, SO_REUSEADDR, 1);
// Diesen Computer binden
socket_bind ($ master, "localhost", 10000) или die ();
// Maximale Verbindungsanforderungen: 5
socket_listen ($ master, 5);
делать
{
$ client = socket_accept ($ master);
echo "Neuer Client! \ n";
новый клиент ($ клиент);
} while (true);
выход();
// Clientklasse
Класс Клиента
{
частное $ соединение;
private $ header = array ();
частный $ crypt; // BOOL, hybi00 не нуждается в расшифровке, но hybi06 +
функция __construct (& $ socket)
{
$ this-> connection = $ socket;
$ This-> SetWebSecKey ();
в то время как (истина)
{
$ q = socket_read ($ this-> connection, 1024);
если (Исеть ($ д))
{
echo $ this-> unmask ($ q);
}
$ welcome = "\ x81 \ x8c \ xff \ xb8 \ xbd \ xbd \ xb7 \ xdd \ xd1 \ xd1 \ x90 \ x98 \ xea \ xd2 \ x8d \ xd4 \ xd9 \ x9c";
}
}
/ **
* Снятие маски с полученного полезного груза.
* @param $ payload
*
* http://srchea.com/blog/2011/12/build-a-real-time-application-using-html5-websockets/
* /
частная функция unmask ($ payload) {
$ length = ord ($ payload [1]) & 127;
if ($ length == 126) {
$ masks = substr ($ payload, 4, 4);
$ data = substr ($ payload, 8);
}
elseif ($ length == 127) {
$ masks = substr ($ payload, 10, 4);
$ data = substr ($ payload, 14);
}
еще {
$ masks = substr ($ payload, 2, 4);
$ data = substr ($ payload, 6);
}
$ text = '';
для ($ i = 0; $ i 125 && $ length <65536)
$ header = pack ('CCS', $ b1, 126, $ length);
elseif ($ length> = 65536)
$ header = pack ('CCN', $ b1, 127, $ length);
вернуть заголовок $. $ текст;
}
приватная функция SetWebSecKey ()
{
// Заголовок запроса в массиве тейлен
$ request = socket_read ($ this-> connection, 1024);
$ request = explode ("\ n", $ request);
foreach ($ request as $ key => $ head)
{
$ header = explode (":", $ head, 2);
$ header [0] = trim ($ header [0]); // Параметр
$ header [1] = trim ($ header [1]); // Верт
$ this-> header [$ header [0]] = $ header [1];
}
$ handshake = new Handshake ($ this-> header);
$ Handshake-> Отправить (соединение $ this->);
}
приватная функция SendPlain ($ text)
{
socket_write ($ this-> connection, $ text, strlen ($ text));
}
}
класс Рукопожатие
{
закрытый заголовок $;
личное $ hybi00;
private $ secKey;
публичная функция __construct ($ headerArray)
{
echo "\ nHandshake wird ausgeführt:";
// Einfacher или двойник SecWebKey?
// Einfach: Hybi06 +
// Doppelt: Hybi00 +
$ this-> header = $ headerArray;
если (Исеть ($ this-> заголовок [ "Sec-WebSocket-Key"]))
{
эхо "Hybi06 + \ n";
// Moderner Hybi06 +
$ this-> secKey = $ this-> InitHybi06 ();
} elseif (isset ($ this-> header ["Sec-WebSocket-Key1"])) {
// Эльтерьер Hybi00 +
эхо "Hybi00 + \ n";
$ this-> secKey = $ this-> InitHybi00 ();
} еще {echo "Fehler - Unbekanntes WebSocket-Protokoll \ n";
вернуть;
}
}
приватная функция InitHybi06 ()
{
$ this-> hybi00 = false;
$ key = $ this-> header ["Sec-WebSocket-Key"];
$ GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
$ key. = $ GUID;
вернуть base64_encode (sha1 ($ key, true));
}
частная функция InitHybi00 ()
{
$ this-> hybi00 = true;
$ key1 = $ this-> header ["Sec-WebSocket-Key1"];
$ key2 = $ this-> header ["Sec-WebSocket-Key2"];
$ key1 = $ this-> Hybi00NumSpace ($ key1);
$ key2 = $ this-> Hybi00NumSpace ($ key2);
$ data = array_keys ($ this-> header);
$ data = $ data [count ($ this-> header) -1];
$ ctx = hash_init ('md5');
hash_update ($ ctx, pack ("N", $ key1));
hash_update ($ ctx, pack ("N", $ key2));
hash_update ($ ctx, $ data);
$ hash_data = hash_final ($ ctx, true);
вернуть $ hash_data;
}
приватная функция Hybi00NumSpace ($ key)
{
$ numbrs = preg_replace ('/ [^ \ d] * /', '', $ key);
$ space = strlen (preg_replace ('/ [^ \ s] [^ \ s] * /', '', $ key));
вернуть $ numbrs / $ пробелы;
}
открытая функция Send ($ socket, $ origin = "http://localhost", $ location =" ws: // localhost ", $ return = false)
{
if (! isset ($ this-> header) ||! isset ($ this-> hybi00) ||! isset ($ this-> secKey))
{
echo "Fehler: Handshake nicht vollständig! \ n"; вернуть;
}
$ header = $ this-> CreateHeader ($ origin, $ location);
отладки ($ заголовка);
$ header = Explode ("\ n", $ header);
если ($ возврата)
вернуть заголовок $;
foreach ($ header как $ line)
{
$ line. = "\ n";
socket_write ($ socket, $ line, strlen ($ line));
}
}
приватная функция CreateHeader ($ origin, $ location)
{
$ header = "HTTP / 1.1 101 WebSocket Protocol Handshake \ r \ n".
Msgstr "Обновить: WebSocket \ r \ n".
Msgstr "Подключение: обновить \ r \ n".
"Sec-WebSocket-Origin: $ origin \ r \ n";
если ($ this-> hybi00)
{
$ header. = "Sec-WebSocket-Location: $ location \ r \ n";
$ header. = "\ r \ n". $ this-> secKey.chr (0);
} еще {
$ header. = "Sec-WebSocket-Accept:". $ this-> secKey. "\ r \ n \ r \ n";
}
вернуть заголовок $;
}
}