1 | <?php |
||
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||
2 | /** |
||
3 | * This file is part of the ZBateson\StreamDecorators project. |
||
4 | * |
||
5 | * @license http://opensource.org/licenses/bsd-license.php BSD |
||
0 ignored issues
–
show
|
|||
6 | */ |
||
0 ignored issues
–
show
|
|||
7 | namespace ZBateson\StreamDecorators; |
||
8 | |||
9 | use Psr\Http\Message\StreamInterface; |
||
10 | use GuzzleHttp\Psr7\StreamDecoratorTrait; |
||
11 | use GuzzleHttp\Psr7\BufferStream; |
||
12 | use RuntimeException; |
||
13 | |||
14 | /** |
||
15 | * GuzzleHttp\Psr7 stream decoder extension for UU-Encoded streams. |
||
16 | * |
||
17 | * The size of the underlying stream and the position of bytes can't be |
||
18 | * determined because the number of encoded bytes is indeterminate without |
||
19 | * reading the entire stream. |
||
20 | * |
||
21 | * @author Zaahid Bateson |
||
0 ignored issues
–
show
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
|
|||
22 | */ |
||
0 ignored issues
–
show
|
|||
23 | class UUStream implements StreamInterface |
||
24 | { |
||
0 ignored issues
–
show
|
|||
25 | use StreamDecoratorTrait; |
||
26 | |||
27 | /** |
||
0 ignored issues
–
show
|
|||
28 | * @var string name of the UUEncoded file |
||
29 | */ |
||
30 | protected $filename = null; |
||
0 ignored issues
–
show
|
|||
31 | |||
32 | /** |
||
0 ignored issues
–
show
|
|||
33 | * @var BufferStream of read and decoded bytes |
||
34 | */ |
||
35 | private $buffer; |
||
0 ignored issues
–
show
|
|||
36 | |||
37 | /** |
||
0 ignored issues
–
show
|
|||
38 | * @var string remainder of write operation if the bytes didn't align to 3 |
||
39 | * bytes |
||
40 | */ |
||
41 | private $remainder = ''; |
||
0 ignored issues
–
show
|
|||
42 | |||
43 | /** |
||
0 ignored issues
–
show
|
|||
44 | * @var int read/write position |
||
45 | */ |
||
46 | private $position = 0; |
||
0 ignored issues
–
show
|
|||
47 | |||
48 | /** |
||
0 ignored issues
–
show
|
|||
49 | * @var boolean set to true when 'write' is called |
||
50 | */ |
||
51 | private $isWriting = false; |
||
0 ignored issues
–
show
|
|||
52 | |||
53 | /** |
||
0 ignored issues
–
show
|
|||
54 | * @param StreamInterface $stream Stream to decorate |
||
0 ignored issues
–
show
|
|||
55 | * @param string $filename optional file name |
||
0 ignored issues
–
show
|
|||
56 | */ |
||
57 | 12 | public function __construct(StreamInterface $stream, $filename = null) |
|
0 ignored issues
–
show
|
|||
58 | { |
||
0 ignored issues
–
show
|
|||
59 | 12 | $this->stream = $stream; |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line. To visualize $a = "a";
$ab = "ab";
$abc = "abc";
will produce issues in the first and second line, while this second example $a = "a";
$ab = "ab";
$abc = "abc";
will produce no issues.
Loading history...
|
|||
60 | 12 | $this->filename = $filename; |
|
61 | 12 | $this->buffer = new BufferStream(); |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line. To visualize $a = "a";
$ab = "ab";
$abc = "abc";
will produce issues in the first and second line, while this second example $a = "a";
$ab = "ab";
$abc = "abc";
will produce no issues.
Loading history...
|
|||
62 | 12 | } |
|
0 ignored issues
–
show
|
|||
63 | |||
64 | /** |
||
65 | * Overridden to return the position in the target encoding. |
||
66 | * |
||
67 | * @return int |
||
0 ignored issues
–
show
|
|||
68 | */ |
||
69 | 3 | public function tell() |
|
70 | { |
||
0 ignored issues
–
show
|
|||
71 | 3 | return $this->position; |
|
72 | } |
||
0 ignored issues
–
show
|
|||
73 | |||
74 | /** |
||
75 | * Returns null, getSize isn't supported |
||
76 | * |
||
77 | * @return null |
||
78 | */ |
||
79 | 1 | public function getSize() |
|
80 | { |
||
0 ignored issues
–
show
|
|||
81 | 1 | return null; |
|
0 ignored issues
–
show
|
|||
82 | } |
||
0 ignored issues
–
show
|
|||
83 | |||
84 | /** |
||
85 | * Not supported. |
||
86 | * |
||
87 | * @param int $offset |
||
0 ignored issues
–
show
|
|||
88 | * @param int $whence |
||
0 ignored issues
–
show
|
|||
89 | * @throws RuntimeException |
||
0 ignored issues
–
show
|
|||
90 | */ |
||
0 ignored issues
–
show
|
|||
91 | 1 | public function seek($offset, $whence = SEEK_SET) |
|
0 ignored issues
–
show
|
|||
92 | { |
||
0 ignored issues
–
show
|
|||
93 | 1 | throw new RuntimeException('Cannot seek a UUStream'); |
|
94 | } |
||
0 ignored issues
–
show
|
|||
95 | |||
96 | /** |
||
97 | * Overridden to return false |
||
98 | * |
||
99 | * @return boolean |
||
100 | */ |
||
101 | 1 | public function isSeekable() |
|
102 | { |
||
0 ignored issues
–
show
|
|||
103 | 1 | return false; |
|
0 ignored issues
–
show
|
|||
104 | } |
||
0 ignored issues
–
show
|
|||
105 | |||
106 | /** |
||
0 ignored issues
–
show
|
|||
107 | * Finds the next end-of-line character to ensure a line isn't broken up |
||
108 | * while buffering. |
||
109 | * |
||
110 | * @return string |
||
111 | */ |
||
112 | 10 | private function readToEndOfLine($length) |
|
0 ignored issues
–
show
|
|||
113 | { |
||
0 ignored issues
–
show
|
|||
114 | 10 | $str = $this->stream->read($length); |
|
115 | 10 | if ($str === false || $str === '') { |
|
0 ignored issues
–
show
|
|||
116 | 9 | return $str; |
|
117 | } |
||
118 | 10 | while (substr($str, -1) !== "\n") { |
|
119 | 1 | $chr = $this->stream->read(1); |
|
120 | 1 | if ($chr === false || $chr === '') { |
|
0 ignored issues
–
show
|
|||
121 | 1 | break; |
|
122 | } |
||
123 | $str .= $chr; |
||
124 | } |
||
125 | 10 | return $str; |
|
126 | } |
||
0 ignored issues
–
show
|
|||
127 | |||
128 | /** |
||
129 | * Removes invalid characters from a uuencoded string, and 'BEGIN' and 'END' |
||
130 | * line headers and footers from the passed string before returning it. |
||
131 | * |
||
132 | * @param string $str |
||
0 ignored issues
–
show
|
|||
133 | * @return string |
||
0 ignored issues
–
show
|
|||
134 | */ |
||
135 | 10 | private function filterAndDecode($str) |
|
0 ignored issues
–
show
|
|||
136 | { |
||
0 ignored issues
–
show
|
|||
137 | 10 | $ret = str_replace("\r", '', $str); |
|
138 | 10 | $ret = preg_replace('/[^\x21-\xf5`\n]/', '`', $ret); |
|
139 | 10 | if ($this->position === 0) { |
|
140 | 10 | $matches = []; |
|
0 ignored issues
–
show
|
|||
141 | 10 | if (preg_match('/^\s*begin\s+[^\s+]\s+([^\r\n]+)\s*$/im', $ret, $matches)) { |
|
142 | $this->filename = $matches[1]; |
||
143 | } |
||
144 | 10 | $ret = preg_replace('/^\s*begin[^\r\n]+\s*$/im', '', $ret); |
|
145 | } else { |
||
146 | $ret = preg_replace('/^\s*end\s*$/im', '', $ret); |
||
147 | } |
||
148 | 10 | return convert_uudecode(trim($ret)); |
|
149 | } |
||
0 ignored issues
–
show
|
|||
150 | |||
151 | /** |
||
0 ignored issues
–
show
|
|||
152 | * Buffers bytes into $this->buffer, removing uuencoding headers and footers |
||
153 | * and decoding them. |
||
154 | */ |
||
0 ignored issues
–
show
|
|||
155 | 10 | private function fillBuffer($length) |
|
0 ignored issues
–
show
|
|||
156 | { |
||
0 ignored issues
–
show
|
|||
157 | // 5040 = 63 * 80, seems to be good balance for buffering in benchmarks |
||
158 | // testing with a simple 'if ($length < x)' and calculating a better |
||
159 | // size reduces speeds by up to 4x |
||
160 | 10 | while ($this->buffer->getSize() < $length) { |
|
161 | 10 | $read = $this->readToEndOfLine(5040); |
|
162 | 10 | if ($read === false || $read === '') { |
|
0 ignored issues
–
show
|
|||
163 | 9 | break; |
|
164 | } |
||
165 | 10 | $this->buffer->write($this->filterAndDecode($read)); |
|
166 | } |
||
167 | 10 | } |
|
0 ignored issues
–
show
|
|||
168 | |||
169 | /** |
||
170 | * Returns true if the end of stream has been reached. |
||
171 | * |
||
172 | * @return boolean |
||
173 | */ |
||
174 | 10 | public function eof() |
|
175 | { |
||
0 ignored issues
–
show
|
|||
176 | 10 | return ($this->buffer->eof() && $this->stream->eof()); |
|
0 ignored issues
–
show
|
|||
177 | } |
||
0 ignored issues
–
show
|
|||
178 | |||
179 | /** |
||
180 | * Attempts to read $length bytes after decoding them, and returns them. |
||
181 | * |
||
182 | * @param int $length |
||
0 ignored issues
–
show
|
|||
183 | * @return string |
||
0 ignored issues
–
show
|
|||
184 | */ |
||
185 | 10 | public function read($length) |
|
0 ignored issues
–
show
|
|||
186 | { |
||
0 ignored issues
–
show
|
|||
187 | // let Guzzle decide what to do. |
||
0 ignored issues
–
show
|
|||
188 | 10 | if ($length <= 0 || $this->eof()) { |
|
189 | return $this->stream->read($length); |
||
190 | } |
||
191 | 10 | $this->fillBuffer($length); |
|
192 | 10 | $read = $this->buffer->read($length); |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 12 spaces but found 1 space
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line. To visualize $a = "a";
$ab = "ab";
$abc = "abc";
will produce issues in the first and second line, while this second example $a = "a";
$ab = "ab";
$abc = "abc";
will produce no issues.
Loading history...
|
|||
193 | 10 | $this->position += strlen($read); |
|
194 | 10 | return $read; |
|
195 | } |
||
0 ignored issues
–
show
|
|||
196 | |||
197 | /** |
||
198 | * Writes the 'begin' UU header line. |
||
199 | */ |
||
0 ignored issues
–
show
|
|||
200 | 2 | private function writeUUHeader() |
|
0 ignored issues
–
show
This method is not in camel caps format.
This check looks for method names that are not written in camelCase. In camelCase names are written without any punctuation, the start of each new
word being marked by a capital letter. Thus the name
database connection seeker becomes
Loading history...
|
|||
201 | { |
||
0 ignored issues
–
show
|
|||
202 | 2 | $filename = (empty($this->filename)) ? 'null' : $this->filename; |
|
0 ignored issues
–
show
|
|||
203 | 2 | $this->stream->write("begin 666 $filename"); |
|
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $filename instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
|
|||
204 | 2 | } |
|
0 ignored issues
–
show
|
|||
205 | |||
206 | /** |
||
207 | * Writes the '`' and 'end' UU footer lines. |
||
208 | */ |
||
0 ignored issues
–
show
|
|||
209 | 2 | private function writeUUFooter() |
|
0 ignored issues
–
show
This method is not in camel caps format.
This check looks for method names that are not written in camelCase. In camelCase names are written without any punctuation, the start of each new
word being marked by a capital letter. Thus the name
database connection seeker becomes
Loading history...
|
|||
210 | { |
||
0 ignored issues
–
show
|
|||
211 | 2 | $this->stream->write("\r\n`\r\nend\r\n"); |
|
212 | 2 | } |
|
0 ignored issues
–
show
|
|||
213 | |||
214 | /** |
||
215 | * Writes the passed bytes to the underlying stream after encoding them. |
||
216 | * |
||
217 | * @param string $bytes |
||
0 ignored issues
–
show
|
|||
218 | */ |
||
0 ignored issues
–
show
|
|||
219 | 2 | private function writeEncoded($bytes) |
|
0 ignored issues
–
show
|
|||
220 | { |
||
0 ignored issues
–
show
|
|||
221 | 2 | $encoded = preg_replace('/\r\n|\r|\n/', "\r\n", rtrim(convert_uuencode($bytes))); |
|
222 | // removes ending '`' line |
||
0 ignored issues
–
show
|
|||
223 | 2 | $this->stream->write("\r\n" . rtrim(substr($encoded, 0, -1))); |
|
0 ignored issues
–
show
|
|||
224 | 2 | } |
|
0 ignored issues
–
show
|
|||
225 | |||
226 | /** |
||
227 | * Prepends any existing remainder to the passed string, then checks if the |
||
228 | * string fits into a uuencoded line, and removes and keeps any remainder |
||
229 | * from the string to write. Full lines ready for writing are returned. |
||
230 | * |
||
231 | * @param string $string |
||
0 ignored issues
–
show
|
|||
232 | * @return string |
||
0 ignored issues
–
show
|
|||
233 | */ |
||
234 | 2 | private function handleRemainder($string) |
|
0 ignored issues
–
show
|
|||
235 | { |
||
0 ignored issues
–
show
|
|||
236 | 2 | $write = $this->remainder . $string; |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line. To visualize $a = "a";
$ab = "ab";
$abc = "abc";
will produce issues in the first and second line, while this second example $a = "a";
$ab = "ab";
$abc = "abc";
will produce no issues.
Loading history...
|
|||
237 | 2 | $nRem = strlen($write) % 45; |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 12 spaces but found 1 space
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line. To visualize $a = "a";
$ab = "ab";
$abc = "abc";
will produce issues in the first and second line, while this second example $a = "a";
$ab = "ab";
$abc = "abc";
will produce no issues.
Loading history...
|
|||
238 | 2 | $this->remainder = ''; |
|
239 | 2 | if ($nRem !== 0) { |
|
240 | 2 | $this->remainder = substr($write, -$nRem); |
|
241 | 2 | $write = substr($write, 0, -$nRem); |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line. To visualize $a = "a";
$ab = "ab";
$abc = "abc";
will produce issues in the first and second line, while this second example $a = "a";
$ab = "ab";
$abc = "abc";
will produce no issues.
Loading history...
|
|||
242 | } |
||
243 | 2 | return $write; |
|
244 | } |
||
0 ignored issues
–
show
|
|||
245 | |||
246 | /** |
||
247 | * Writes the passed string to the underlying stream after encoding it. |
||
248 | * |
||
249 | * Note that reading and writing to the same stream without rewinding is not |
||
250 | * supported. |
||
251 | * |
||
252 | * Also note that some bytes may not be written until close or detach are |
||
253 | * called. This happens if written data doesn't align to a complete |
||
254 | * uuencoded 'line' of 45 bytes. In addition, the UU footer is only written |
||
255 | * when closing or detaching as well. |
||
256 | * |
||
257 | * @param string $string |
||
0 ignored issues
–
show
|
|||
258 | * @return int the number of bytes written |
||
0 ignored issues
–
show
|
|||
259 | */ |
||
260 | 2 | public function write($string) |
|
0 ignored issues
–
show
|
|||
261 | { |
||
0 ignored issues
–
show
|
|||
262 | 2 | $this->isWriting = true; |
|
0 ignored issues
–
show
|
|||
263 | 2 | if ($this->position === 0) { |
|
264 | 2 | $this->writeUUHeader(); |
|
265 | } |
||
266 | 2 | $write = $this->handleRemainder($string); |
|
267 | 2 | if ($write !== '') { |
|
268 | 2 | $this->writeEncoded($write); |
|
269 | } |
||
270 | 2 | $written = strlen($string); |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line. To visualize $a = "a";
$ab = "ab";
$abc = "abc";
will produce issues in the first and second line, while this second example $a = "a";
$ab = "ab";
$abc = "abc";
will produce no issues.
Loading history...
|
|||
271 | 2 | $this->position += $written; |
|
272 | 2 | return $written; |
|
273 | } |
||
0 ignored issues
–
show
|
|||
274 | |||
275 | /** |
||
276 | * Returns the filename set in the UUEncoded header (or null) |
||
277 | * |
||
278 | * @return string |
||
279 | */ |
||
280 | public function getFilename() |
||
281 | { |
||
0 ignored issues
–
show
|
|||
282 | return $this->filename; |
||
283 | } |
||
0 ignored issues
–
show
|
|||
284 | |||
285 | /** |
||
286 | * Sets the UUEncoded header file name written in the 'begin' header line. |
||
287 | * |
||
288 | * @param string $filename |
||
0 ignored issues
–
show
|
|||
289 | */ |
||
0 ignored issues
–
show
|
|||
290 | public function setFilename($filename) |
||
0 ignored issues
–
show
|
|||
291 | { |
||
0 ignored issues
–
show
|
|||
292 | $this->filename = $filename; |
||
293 | } |
||
0 ignored issues
–
show
|
|||
294 | |||
295 | /** |
||
296 | * Writes out any remaining bytes and the UU footer. |
||
297 | */ |
||
0 ignored issues
–
show
|
|||
298 | 2 | private function beforeClose() |
|
0 ignored issues
–
show
|
|||
299 | { |
||
0 ignored issues
–
show
|
|||
300 | 2 | if (!$this->isWriting) { |
|
0 ignored issues
–
show
|
|||
301 | 1 | return; |
|
302 | } |
||
303 | 2 | if ($this->remainder !== '') { |
|
304 | 2 | $this->writeEncoded($this->remainder); |
|
305 | } |
||
306 | 2 | $this->remainder = ''; |
|
307 | 2 | $this->isWriting = false; |
|
0 ignored issues
–
show
|
|||
308 | 2 | $this->writeUUFooter(); |
|
309 | 2 | } |
|
0 ignored issues
–
show
|
|||
310 | |||
311 | /** |
||
312 | * Writes any remaining bytes out followed by the uu-encoded footer, then |
||
313 | * closes the stream. |
||
314 | */ |
||
0 ignored issues
–
show
|
|||
315 | 2 | public function close() |
|
316 | { |
||
0 ignored issues
–
show
|
|||
317 | 2 | $this->beforeClose(); |
|
318 | 2 | $this->stream->close(); |
|
319 | 2 | } |
|
0 ignored issues
–
show
|
|||
320 | |||
321 | /** |
||
322 | * Writes any remaining bytes out followed by the uu-encoded footer, then |
||
323 | * detaches the stream. |
||
324 | */ |
||
0 ignored issues
–
show
|
|||
325 | public function detach() |
||
326 | { |
||
0 ignored issues
–
show
|
|||
327 | $this->beforeClose(); |
||
328 | $this->stream->detach(); |
||
329 | } |
||
0 ignored issues
–
show
|
|||
330 | } |
||
0 ignored issues
–
show
|
|||
331 |