protected function _decode($connectionId)
{
$data = $this->_read[$connectionId];
if (strlen($data) < 2) {
return false;
}
$unmaskedPayload = '';
$decodedData = array();
// estimate frame type:
$firstByteBinary = sprintf('%08b', ord($data[0]));
$secondByteBinary = sprintf('%08b', ord($data[1]));
$opcode = bindec(substr($firstByteBinary, 4, 4));
$isMasked = $secondByteBinary[0] == '1';
$payloadLength = ord($data[1]) & 127;
switch ($opcode) {
// text frame:
case 1:
$decodedData['type'] = 'text';
break;
case 2:
$decodedData['type'] = 'binary';
break;
// connection close frame:
// connection close frame:
case 8:
$decodedData['type'] = 'close';
break;
// ping frame:
// ping frame:
case 9:
$decodedData['type'] = 'ping';
break;
// pong frame:
// pong frame:
case 10:
$decodedData['type'] = 'pong';
break;
default:
$decodedData['type'] = '';
}
if ($payloadLength === 126) {
if (strlen($data) < 4) {
return false;
}
$payloadOffset = 8;
$dataLength = bindec(sprintf('%08b', ord($data[2])) . sprintf('%08b', ord($data[3]))) + $payloadOffset;
} elseif ($payloadLength === 127) {
if (strlen($data) < 10) {
return false;
}
$payloadOffset = 14;
for ($tmp = '', $i = 0; $i < 8; $i++) {
$tmp .= sprintf('%08b', ord($data[$i + 2]));
}
$dataLength = bindec($tmp) + $payloadOffset;
} else {
$payloadOffset = 6;
$dataLength = $payloadLength + $payloadOffset;
}
if (strlen($data) < $dataLength) {
return false;
} else {
$this->_read[$connectionId] = substr($data, $dataLength);
}
if ($isMasked) {
if ($payloadLength === 126) {
$mask = substr($data, 4, 4);
} elseif ($payloadLength === 127) {
$mask = substr($data, 10, 4);
} else {
$mask = substr($data, 2, 4);
}
for ($i = $payloadOffset; $i < $dataLength; $i++) {
$j = $i - $payloadOffset;
if (isset($data[$i])) {
$unmaskedPayload .= $data[$i] ^ $mask[$j % 4];
}
}
$decodedData['payload'] = $unmaskedPayload;
} else {
$payloadOffset = $payloadOffset - 4;
$decodedData['payload'] = substr($data, $payloadOffset, $dataLength - $payloadOffset);
}
return $decodedData;
}