public function read()
{
if (!is_resource($this->stream)) {
return;
}
/*
* The first byte contains the FIN bit, the reserved bits, and the
* opcode... We're not interested in them. Yet.
* the second byte contains the mask bit and the payload's length
*/
$data = fread($this->stream, 2);
$bytes = unpack('C*', $data);
$mask = ($bytes[2] & 0b10000000) >> 7;
$length = $bytes[2] & 0b1111111;
/*
* Here is where it is getting tricky :
*
* - If the length <= 125, then we do not need to do anything ;
* - if the length is 126, it means that it is coded over the next 2 bytes ;
* - if the length is 127, it means that it is coded over the next 8 bytes.
*
* But,here's the trick : we cannot interpret a length over 127 if the
* system does not support 64bits integers (such as Windows, or 32bits
* processors architectures).
*/
switch ($length) {
case 0x7d:
// 125
break;
case 0x7e:
// 126
$data .= $bytes = fread($this->stream, 2);
$bytes = unpack('n', $bytes);
if (empty($bytes[1])) {
throw new RuntimeException('Invalid extended packet len');
}
$length = $bytes[1];
break;
case 0x7f:
// 127
// are (at least) 64 bits not supported by the architecture ?
if (8 > PHP_INT_SIZE) {
throw new DomainException('64 bits unsigned integer are not supported on this architecture');
}
/*
* As (un)pack does not support unpacking 64bits unsigned
* integer, we need to split the data
*
* {@link http://stackoverflow.com/questions/14405751/pack-and-unpack-64-bit-integer}
*/
$data .= $bytes = fread($this->stream, 8);
list($left, $right) = array_values(unpack('N2', $bytes));
$length = $left << 32 | $right;
break;
}
// incorporate the mask key if the mask bit is 1
if (true === $mask) {
$data .= fread($this->stream, 4);
}
// Split the packet in case of the length > 16kb
while ($length > 0 && ($buffer = fread($this->stream, $length))) {
$data .= $buffer;
$length -= strlen($buffer);
}
// decode the payload
return (string) new Decoder($data);
}