<?php
/**
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository
* @copyright Copyright (c) 2015-2018 Zend Technologies USA Inc. (http://www.zend.com)
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
*/
namespace Zend\Diactoros\Response;
use Psr\Http\Message\ResponseInterface;
use function is_array;
use function preg_match;
use function strlen;
use function substr;
/**
* @deprecated since 1.8.0. The package zendframework/zend-httphandlerrunner
* now provides this functionality.
*/
class SapiStreamEmitter implements EmitterInterface
{
use SapiEmitterTrait;
/**
* Emits a response for a PHP SAPI environment.
*
* Emits the status line and headers via the header() function, and the
* body content via the output buffer.
*
* @param ResponseInterface $response
* @param int $maxBufferLength Maximum output buffering size for each iteration
*/
public function emit(ResponseInterface $response, $maxBufferLength = 8192)
{
$this->assertNoPreviousOutput();
$this->emitHeaders($response);
$this->emitStatusLine($response);
$range = $this->parseContentRange($response->getHeaderLine('Content-Range'));
if (is_array($range) && $range[0] === 'bytes') {
$this->emitBodyRange($range, $response, $maxBufferLength);
return;
}
$this->emitBody($response, $maxBufferLength);
}
/**
* Emit the message body.
*
* @param ResponseInterface $response
* @param int $maxBufferLength
*/
private function emitBody(ResponseInterface $response, $maxBufferLength)
{
$body = $response->getBody();
if ($body->isSeekable()) {
$body->rewind();
}
if (! $body->isReadable()) {
echo $body;
return;
}
while (! $body->eof()) {
echo $body->read($maxBufferLength);
}
}
/**
* Emit a range of the message body.
*
* @param array $range
* @param ResponseInterface $response
* @param int $maxBufferLength
*/
private function emitBodyRange(array $range, ResponseInterface $response, $maxBufferLength)
{
list($unit, $first, $last, $length) = $range;
$body = $response->getBody();
$length = $last - $first + 1;
if ($body->isSeekable()) {
$body->seek($first);
$first = 0;
}
if (! $body->isReadable()) {
echo substr($body->getContents(), $first, $length);
return;
}
$remaining = $length;
while ($remaining >= $maxBufferLength && ! $body->eof()) {
$contents = $body->read($maxBufferLength);
$remaining -= strlen($contents);
echo $contents;
}
if ($remaining > 0 && ! $body->eof()) {
echo $body->read($remaining);
}
}
/**
* Parse content-range header
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
*
* @param string $header
* @return false|array [unit, first, last, length]; returns false if no
* content range or an invalid content range is provided
*/
private function parseContentRange($header)
{
if (preg_match('/(?P<unit>[\w]+)\s+(?P<first>\d+)-(?P<last>\d+)\/(?P<length>\d+|\*)/', $header, $matches)) {
return [
$matches['unit'],
(int) $matches['first'],
(int) $matches['last'],
$matches['length'] === '*' ? '*' : (int) $matches['length'],
];
}
return false;
}
}