PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.0.5
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.0.5
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / vendor / zbateson / stream-decorators / src / Base64Stream.php

Base64Stream.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 11.0.5, at vendor/zbateson/stream-decorators/src/Base64Stream.php

224 lines 5.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This file is part of the ZBateson\StreamDecorators project.
4 *
5 * @license http://opensource.org/licenses/bsd-license.php BSD
6 */
7
8 namespace ZBateson\StreamDecorators;
9
10 use GuzzleHttp\Psr7\BufferStream;
11 use GuzzleHttp\Psr7\StreamDecoratorTrait;
12 use Psr\Http\Message\StreamInterface;
13 use RuntimeException;
14
15 /**
16 * GuzzleHttp\Psr7 stream decoder extension for base64 streams.
17 *
18 * Note that it's expected the underlying stream will only contain valid base64
19 * characters (normally the stream should be wrapped in a
20 * PregReplaceFilterStream to filter out non-base64 characters for reading).
21 *
22 * ```
23 * $f = fopen(...);
24 * $stream = new Base64Stream(new PregReplaceFilterStream(
25 * Psr7\Utils::streamFor($f), '/[^a-zA-Z0-9\/\+=]/', ''
26 * ));
27 * //...
28 * ```
29 *
30 * For writing, a ChunkSplitStream could come in handy so the output is split
31 * into lines:
32 *
33 * ```
34 * $f = fopen(...);
35 * $stream = new Base64Stream(new ChunkSplitStream(new PregReplaceFilterStream(
36 * Psr7\Utils::streamFor($f), '/[^a-zA-Z0-9\/\+=]/', ''
37 * )));
38 * //...
39 * ```
40 *
41 * @author Zaahid Bateson
42 */
43 class Base64Stream implements StreamInterface
44 {
45 use StreamDecoratorTrait;
46
47 /**
48 * @var BufferStream buffered bytes
49 */
50 private $buffer;
51
52 /**
53 * @var string remainder of write operation if the bytes didn't align to 3
54 * bytes
55 */
56 private $remainder = '';
57
58 /**
59 * @var int current number of read/written bytes (for tell())
60 */
61 private $position = 0;
62
63 /**
64 * @var StreamInterface $stream
65 */
66 private $stream;
67
68 public function __construct(StreamInterface $stream)
69 {
70 $this->stream = $stream;
71 $this->buffer = new BufferStream();
72 }
73
74 /**
75 * Returns the current position of the file read/write pointer
76 */
77 public function tell() : int
78 {
79 return $this->position;
80 }
81
82 /**
83 * Returns null, getSize isn't supported
84 *
85 * @return null
86 */
87 public function getSize() : ?int
88 {
89 return null;
90 }
91
92 /**
93 * Not implemented (yet).
94 *
95 * Seek position can be calculated.
96 *
97 * @param int $offset
98 * @param int $whence
99 * @throws RuntimeException
100 */
101 public function seek($offset, $whence = SEEK_SET) : void
102 {
103 throw new RuntimeException('Cannot seek a Base64Stream');
104 }
105
106 /**
107 * Overridden to return false
108 */
109 public function isSeekable() : bool
110 {
111 return false;
112 }
113
114 /**
115 * Returns true if the end of stream has been reached.
116 */
117 public function eof() : bool
118 {
119 return ($this->buffer->eof() && $this->stream->eof());
120 }
121
122 /**
123 * Fills the internal byte buffer after reading and decoding data from the
124 * underlying stream.
125 *
126 * Note that it's expected the underlying stream will only contain valid
127 * base64 characters (normally the stream should be wrapped in a
128 * PregReplaceFilterStream to filter out non-base64 characters).
129 */
130 private function fillBuffer(int $length) : void
131 {
132 $fill = 8192;
133 while ($this->buffer->getSize() < $length) {
134 $read = $this->stream->read($fill);
135 if ($read === '') {
136 break;
137 }
138 $this->buffer->write(\base64_decode($read));
139 }
140 }
141
142 /**
143 * Attempts to read $length bytes after decoding them, and returns them.
144 *
145 * Note that reading and writing to the same stream may result in wrongly
146 * encoded data and is not supported.
147 *
148 * @param int $length
149 * @return string
150 */
151 public function read($length) : string
152 {
153 // let Guzzle decide what to do.
154 if ($length <= 0 || $this->eof()) {
155 return $this->stream->read($length);
156 }
157 $this->fillBuffer($length);
158 $ret = $this->buffer->read($length);
159 $this->position += \strlen($ret);
160 return $ret;
161 }
162
163 /**
164 * Writes the passed string to the underlying stream after encoding it to
165 * base64.
166 *
167 * Base64Stream::close or detach must be called. Failing to do so may
168 * result in 1-2 bytes missing from the end of the stream if there's a
169 * remainder. Note that the default Stream destructor calls close as well.
170 *
171 * Note that reading and writing to the same stream may result in wrongly
172 * encoded data and is not supported.
173 *
174 * @param string $string
175 * @return int the number of bytes written
176 */
177 public function write($string) : int
178 {
179 $bytes = $this->remainder . $string;
180 $len = \strlen($bytes);
181 if (($len % 3) !== 0) {
182 $this->remainder = \substr($bytes, -($len % 3));
183 $bytes = \substr($bytes, 0, $len - ($len % 3));
184 } else {
185 $this->remainder = '';
186 }
187 $this->stream->write(\base64_encode($bytes));
188 $written = \strlen($string);
189 $this->position += $len;
190 return $written;
191 }
192
193 /**
194 * Writes out any remaining bytes at the end of the stream and closes.
195 */
196 private function beforeClose() : void
197 {
198 if ($this->isWritable() && $this->remainder !== '') {
199 $this->stream->write(\base64_encode($this->remainder));
200 $this->remainder = '';
201 }
202 }
203
204 /**
205 * @inheritDoc
206 */
207 public function close() : void
208 {
209 $this->beforeClose();
210 $this->stream->close();
211 }
212
213 /**
214 * @inheritDoc
215 */
216 public function detach()
217 {
218 $this->beforeClose();
219 $this->stream->detach();
220
221 return null;
222 }
223 }
224