/** * @param StreamInterface $stream * @param null|string $mimeType * @param ServerRequestInterface|null $request not used yet. */ public static function returnStream(StreamInterface $stream, $mimeType = null, ServerRequestInterface $request = null) { header('Accept-Ranges: bytes'); if (!is_null($mimeType)) { header('Content-Type: ' . $mimeType); } try { $ranges = StreamRange::createFromRequest($stream, $request); $contentLength = 0; if (!empty($ranges)) { header('HTTP/1.1 206 Partial Content'); foreach ($ranges as $range) { $contentLength += $range->getLastPos() - $range->getFirstPos() + 1; } //@todo Content-Range for multiple ranges? header('Content-Range: bytes ' . $ranges[0]->getFirstPos() . '-' . $ranges[0]->getLastPos() . '/' . $stream->getSize()); } else { $contentLength = $stream->getSize(); header('HTTP/1.1 200 OK'); } header("Content-Length: " . $contentLength); if (empty($ranges)) { while (!$stream->eof()) { echo $stream->read(self::BYTES_BY_CYCLE); } } else { foreach ($ranges as $range) { $pos = $range->getFirstPos(); $stream->seek($pos); while ($pos <= $range->getLastPos()) { $length = min($range->getLastPos() - $pos + 1, self::BYTES_BY_CYCLE); echo $stream->read($length); $pos += $length; } } } } catch (StreamRangeException $e) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); } }
/** * @dataProvider rangesProvider */ public function testConstruct($stream, $rangeValue, $first, $last) { $range = new StreamRange($stream, $rangeValue); $this->assertEquals($first, $range->getFirstPos()); $this->assertEquals($last, $range->getLastPos()); }