Chris@0: $st */ Chris@17: $st = fstat($fp); Chris@17: if (($st['mode'] & 0170000) !== 020000) { Chris@17: fclose($fp); Chris@17: $fp = false; Chris@17: } Chris@0: } Chris@0: } Chris@0: Chris@16: if (is_resource($fp)) { Chris@0: /** Chris@0: * stream_set_read_buffer() does not exist in HHVM Chris@0: * Chris@0: * If we don't set the stream's read buffer to 0, PHP will Chris@0: * internally buffer 8192 bytes, which can waste entropy Chris@0: * Chris@0: * stream_set_read_buffer returns 0 on success Chris@0: */ Chris@0: if (is_callable('stream_set_read_buffer')) { Chris@0: stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER); Chris@0: } Chris@0: if (is_callable('stream_set_chunk_size')) { Chris@0: stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: try { Chris@16: /** @var int $bytes */ Chris@0: $bytes = RandomCompat_intval($bytes); Chris@0: } catch (TypeError $ex) { Chris@0: throw new TypeError( Chris@0: 'random_bytes(): $bytes must be an integer' Chris@0: ); Chris@0: } Chris@0: Chris@0: if ($bytes < 1) { Chris@0: throw new Error( Chris@0: 'Length must be greater than 0' Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * This if() block only runs if we managed to open a file handle Chris@0: * Chris@0: * It does not belong in an else {} block, because the above Chris@0: * if (empty($fp)) line is logic that should only be run once per Chris@0: * page load. Chris@0: */ Chris@16: if (is_resource($fp)) { Chris@0: /** Chris@0: * @var int Chris@0: */ Chris@0: $remaining = $bytes; Chris@0: Chris@0: /** Chris@0: * @var string|bool Chris@0: */ Chris@0: $buf = ''; Chris@0: Chris@0: /** Chris@0: * We use fread() in a loop to protect against partial reads Chris@0: */ Chris@0: do { Chris@0: /** Chris@0: * @var string|bool Chris@0: */ Chris@0: $read = fread($fp, $remaining); Chris@0: if (!is_string($read)) { Chris@17: /** Chris@17: * We cannot safely read from the file. Exit the Chris@17: * do-while loop and trigger the exception condition Chris@17: * Chris@17: * @var string|bool Chris@17: */ Chris@17: $buf = false; Chris@17: break; Chris@0: } Chris@0: /** Chris@0: * Decrease the number of bytes returned from remaining Chris@0: */ Chris@0: $remaining -= RandomCompat_strlen($read); Chris@0: /** Chris@17: * @var string $buf Chris@0: */ Chris@17: $buf .= $read; Chris@0: } while ($remaining > 0); Chris@0: Chris@0: /** Chris@0: * Is our result valid? Chris@17: * @var string|bool $buf Chris@0: */ Chris@0: if (is_string($buf)) { Chris@0: if (RandomCompat_strlen($buf) === $bytes) { Chris@0: /** Chris@0: * Return our random entropy buffer here: Chris@0: */ Chris@0: return $buf; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * If we reach here, PHP has failed us. Chris@0: */ Chris@0: throw new Exception( Chris@0: 'Error reading from source device' Chris@0: ); Chris@0: } Chris@0: }