comparison vendor/zendframework/zend-diactoros/src/Response/SapiStreamEmitter.php @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children 5311817fb629
comparison
equal deleted inserted replaced
-1:000000000000 0:c75dbcec494b
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @see http://github.com/zendframework/zend-diactoros for the canonical source repository
6 * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
8 */
9
10 namespace Zend\Diactoros\Response;
11
12 use Psr\Http\Message\ResponseInterface;
13 use RuntimeException;
14 use Zend\Diactoros\RelativeStream;
15
16 class SapiStreamEmitter implements EmitterInterface
17 {
18 use SapiEmitterTrait;
19
20 /**
21 * Emits a response for a PHP SAPI environment.
22 *
23 * Emits the status line and headers via the header() function, and the
24 * body content via the output buffer.
25 *
26 * @param ResponseInterface $response
27 * @param int $maxBufferLength Maximum output buffering size for each iteration
28 */
29 public function emit(ResponseInterface $response, $maxBufferLength = 8192)
30 {
31 if (headers_sent()) {
32 throw new RuntimeException('Unable to emit response; headers already sent');
33 }
34
35 $response = $this->injectContentLength($response);
36
37 $this->emitStatusLine($response);
38 $this->emitHeaders($response);
39 $this->flush();
40
41 $range = $this->parseContentRange($response->getHeaderLine('Content-Range'));
42
43 if (is_array($range) && $range[0] === 'bytes') {
44 $this->emitBodyRange($range, $response, $maxBufferLength);
45 return;
46 }
47
48 $this->emitBody($response, $maxBufferLength);
49 }
50
51 /**
52 * Emit the message body.
53 *
54 * @param ResponseInterface $response
55 * @param int $maxBufferLength
56 */
57 private function emitBody(ResponseInterface $response, $maxBufferLength)
58 {
59 $body = $response->getBody();
60
61 if ($body->isSeekable()) {
62 $body->rewind();
63 }
64
65 if (! $body->isReadable()) {
66 echo $body;
67 return;
68 }
69
70 while (! $body->eof()) {
71 echo $body->read($maxBufferLength);
72 }
73 }
74
75 /**
76 * Emit a range of the message body.
77 *
78 * @param array $range
79 * @param ResponseInterface $response
80 * @param int $maxBufferLength
81 */
82 private function emitBodyRange(array $range, ResponseInterface $response, $maxBufferLength)
83 {
84 list($unit, $first, $last, $length) = $range;
85
86 $body = $response->getBody();
87
88 $length = $last - $first + 1;
89
90 if ($body->isSeekable()) {
91 $body->seek($first);
92
93 $first = 0;
94 }
95
96 if (! $body->isReadable()) {
97 echo substr($body->getContents(), $first, $length);
98 return;
99 }
100
101 $remaining = $length;
102
103 while ($remaining >= $maxBufferLength && ! $body->eof()) {
104 $contents = $body->read($maxBufferLength);
105 $remaining -= strlen($contents);
106
107 echo $contents;
108 }
109
110 if ($remaining > 0 && ! $body->eof()) {
111 echo $body->read($remaining);
112 }
113 }
114
115 /**
116 * Parse content-range header
117 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
118 *
119 * @param string $header
120 * @return false|array [unit, first, last, length]; returns false if no
121 * content range or an invalid content range is provided
122 */
123 private function parseContentRange($header)
124 {
125 if (preg_match('/(?P<unit>[\w]+)\s+(?P<first>\d+)-(?P<last>\d+)\/(?P<length>\d+|\*)/', $header, $matches)) {
126 return [
127 $matches['unit'],
128 (int) $matches['first'],
129 (int) $matches['last'],
130 $matches['length'] === '*' ? '*' : (int) $matches['length'],
131 ];
132 }
133 return false;
134 }
135 }