Mercurial > hg > isophonics-drupal-site
comparison vendor/guzzlehttp/psr7/src/CachingStream.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 namespace GuzzleHttp\Psr7; | |
3 | |
4 use Psr\Http\Message\StreamInterface; | |
5 | |
6 /** | |
7 * Stream decorator that can cache previously read bytes from a sequentially | |
8 * read stream. | |
9 */ | |
10 class CachingStream implements StreamInterface | |
11 { | |
12 use StreamDecoratorTrait; | |
13 | |
14 /** @var StreamInterface Stream being wrapped */ | |
15 private $remoteStream; | |
16 | |
17 /** @var int Number of bytes to skip reading due to a write on the buffer */ | |
18 private $skipReadBytes = 0; | |
19 | |
20 /** | |
21 * We will treat the buffer object as the body of the stream | |
22 * | |
23 * @param StreamInterface $stream Stream to cache | |
24 * @param StreamInterface $target Optionally specify where data is cached | |
25 */ | |
26 public function __construct( | |
27 StreamInterface $stream, | |
28 StreamInterface $target = null | |
29 ) { | |
30 $this->remoteStream = $stream; | |
31 $this->stream = $target ?: new Stream(fopen('php://temp', 'r+')); | |
32 } | |
33 | |
34 public function getSize() | |
35 { | |
36 return max($this->stream->getSize(), $this->remoteStream->getSize()); | |
37 } | |
38 | |
39 public function rewind() | |
40 { | |
41 $this->seek(0); | |
42 } | |
43 | |
44 public function seek($offset, $whence = SEEK_SET) | |
45 { | |
46 if ($whence == SEEK_SET) { | |
47 $byte = $offset; | |
48 } elseif ($whence == SEEK_CUR) { | |
49 $byte = $offset + $this->tell(); | |
50 } elseif ($whence == SEEK_END) { | |
51 $size = $this->remoteStream->getSize(); | |
52 if ($size === null) { | |
53 $size = $this->cacheEntireStream(); | |
54 } | |
55 $byte = $size + $offset; | |
56 } else { | |
57 throw new \InvalidArgumentException('Invalid whence'); | |
58 } | |
59 | |
60 $diff = $byte - $this->stream->getSize(); | |
61 | |
62 if ($diff > 0) { | |
63 // Read the remoteStream until we have read in at least the amount | |
64 // of bytes requested, or we reach the end of the file. | |
65 while ($diff > 0 && !$this->remoteStream->eof()) { | |
66 $this->read($diff); | |
67 $diff = $byte - $this->stream->getSize(); | |
68 } | |
69 } else { | |
70 // We can just do a normal seek since we've already seen this byte. | |
71 $this->stream->seek($byte); | |
72 } | |
73 } | |
74 | |
75 public function read($length) | |
76 { | |
77 // Perform a regular read on any previously read data from the buffer | |
78 $data = $this->stream->read($length); | |
79 $remaining = $length - strlen($data); | |
80 | |
81 // More data was requested so read from the remote stream | |
82 if ($remaining) { | |
83 // If data was written to the buffer in a position that would have | |
84 // been filled from the remote stream, then we must skip bytes on | |
85 // the remote stream to emulate overwriting bytes from that | |
86 // position. This mimics the behavior of other PHP stream wrappers. | |
87 $remoteData = $this->remoteStream->read( | |
88 $remaining + $this->skipReadBytes | |
89 ); | |
90 | |
91 if ($this->skipReadBytes) { | |
92 $len = strlen($remoteData); | |
93 $remoteData = substr($remoteData, $this->skipReadBytes); | |
94 $this->skipReadBytes = max(0, $this->skipReadBytes - $len); | |
95 } | |
96 | |
97 $data .= $remoteData; | |
98 $this->stream->write($remoteData); | |
99 } | |
100 | |
101 return $data; | |
102 } | |
103 | |
104 public function write($string) | |
105 { | |
106 // When appending to the end of the currently read stream, you'll want | |
107 // to skip bytes from being read from the remote stream to emulate | |
108 // other stream wrappers. Basically replacing bytes of data of a fixed | |
109 // length. | |
110 $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell(); | |
111 if ($overflow > 0) { | |
112 $this->skipReadBytes += $overflow; | |
113 } | |
114 | |
115 return $this->stream->write($string); | |
116 } | |
117 | |
118 public function eof() | |
119 { | |
120 return $this->stream->eof() && $this->remoteStream->eof(); | |
121 } | |
122 | |
123 /** | |
124 * Close both the remote stream and buffer stream | |
125 */ | |
126 public function close() | |
127 { | |
128 $this->remoteStream->close() && $this->stream->close(); | |
129 } | |
130 | |
131 private function cacheEntireStream() | |
132 { | |
133 $target = new FnStream(['write' => 'strlen']); | |
134 copy_to_stream($this, $target); | |
135 | |
136 return $this->tell(); | |
137 } | |
138 } |