public static function decode(&$buffer)
{
if (strlen($buffer) < 2) {
return null;
}
$frame = new self();
// Read the first two bytes, then chop them off
$firstByte = substr($buffer, 0, 1);
$secondByte = substr($buffer, 1, 1);
$raw = substr($buffer, 2);
$firstByte = ord($firstByte);
$secondByte = ord($secondByte);
$frame->FIN = self::IsBitSet($firstByte, 7);
$frame->RSV1 = self::IsBitSet($firstByte, 6);
$frame->RSV2 = self::IsBitSet($firstByte, 5);
$frame->RSV3 = self::IsBitSet($firstByte, 4);
$frame->mask = self::IsBitSet($secondByte, 7);
$frame->opcode = $firstByte & 0xf;
$len = $secondByte & ~128;
if ($len <= 125) {
$frame->payloadLength = $len;
} elseif ($len == 126 && strlen($raw) >= 2) {
$arr = unpack("nfirst", $raw);
$frame->payloadLength = array_pop($arr);
$raw = substr($raw, 2);
} elseif ($len == 127 && strlen($raw) >= 8) {
list(, $h, $l) = unpack('N2', $raw);
$frame->payloadLength = $l + $h * 0x100000000;
$raw = substr($raw, 8);
} else {
return null;
}
// If the frame is masked, try to eat the key from the buffer. If the buffer is insufficient, return null and
// try again next time
if ($frame->mask) {
if (strlen($raw) < 4) {
return null;
}
$frame->maskingKey = substr($raw, 0, 4);
$raw = substr($raw, 4);
}
// Don't continue until we have a full frame
if (strlen($raw) < $frame->payloadLength) {
return null;
}
$packetPayload = substr($raw, 0, $frame->payloadLength);
// Advance buffer
$buffer = substr($raw, $frame->payloadLength);
if ($frame->mask) {
$frame->payloadData = self::rotMask($packetPayload, $frame->maskingKey, 0);
} else {
$frame->payloadData = $packetPayload;
}
return $frame;
}