Completed
Push — master ( 5264dc...493789 )
by ignace nyamagana
04:14
created

StreamIterator::fread()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
* This file is part of the League.csv library
4
*
5
* @license http://opensource.org/licenses/MIT
6
* @link https://github.com/thephpleague/csv/
7
* @version 9.0.0
8
* @package League.csv
9
*
10
* For the full copyright and license information, please view the LICENSE
11
* file that was distributed with this source code.
12
*/
13
declare(strict_types=1);
14
15
namespace League\Csv;
16
17
use League\Csv\Exception\InvalidArgumentException;
18
use League\Csv\Exception\LogicException;
19
use SeekableIterator;
20
use SplFileObject;
21
22
/**
23
 * An object oriented API for a seekable stream resource.
24
 *
25
 * @package  League.csv
26
 * @since    8.2.0
27
 * @author   Ignace Nyamagana Butera <[email protected]>
28
 * @internal used internally to iterate over a stream resource
29
 *
30
 */
31
class StreamIterator implements SeekableIterator
32
{
33
    use ValidatorTrait;
34
35
    /**
36
     * Attached filters
37
     *
38
     * @var resource[]
39
     */
40
    protected $filters;
41
42
    /**
43
     * Stream pointer
44
     *
45
     * @var resource
46
     */
47
    protected $stream;
48
49
    /**
50
     * Current iterator value
51
     *
52
     * @var mixed
53
     */
54
    protected $value;
55
56
    /**
57
     * Current iterator key
58
     *
59
     * @var int
60
     */
61
    protected $offset;
62
63
    /**
64
     * Flags for the StreamIterator
65
     *
66
     * @var int
67
     */
68
    protected $flags = 0;
69
70
    /**
71
     * the field delimiter (one character only)
72
     *
73
     * @var string
74
     */
75
    protected $delimiter = ',';
76
77
    /**
78
     * the field enclosure character (one character only)
79
     *
80
     * @var string
81
     */
82
    protected $enclosure = '"';
83
84
    /**
85
     * the field escape character (one character only)
86
     *
87
     * @var string
88
     */
89
    protected $escape = '\\';
90
91
    /**
92
     * New instance
93
     *
94
     * @param resource $stream stream type resource
95
     */
96 78
    public function __construct($stream)
97
    {
98 78
        if (!is_resource($stream)) {
99 4
            throw new InvalidArgumentException(sprintf('Argument passed must be a resource, %s given', is_object($stream) ? get_class($stream) : gettype($stream)));
100
        }
101
102 74
        if ('stream' !== ($type = get_resource_type($stream))) {
103 2
            throw new InvalidArgumentException(sprintf('Argument passed must be a stream resource, %s resource given', $type));
104
        }
105
106 72
        if (!stream_get_meta_data($stream)['seekable']) {
107 2
            throw new InvalidArgumentException(sprintf('Argument passed must be a seekable stream resource'));
108
        }
109
110 70
        $this->stream = $stream;
111 70
    }
112
113
    /**
114
     * close the file pointer
115
     */
116 70
    public function __destruct()
117
    {
118 70
        $this->stream = null;
119 70
    }
120
121
    /**
122
     * Set CSV control
123
     *
124
     * @see http://php.net/manual/en/splfileobject.setcsvcontrol.php
125
     *
126
     * @param string $delimiter
127
     * @param string $enclosure
128
     * @param string $escape
129
     */
130 30
    public function setCsvControl(string $delimiter = ',', string $enclosure = '"', string $escape = '\\')
131
    {
132 30
        $this->delimiter = $this->filterControl($delimiter, 'delimiter');
133 28
        $this->enclosure = $this->filterControl($enclosure, 'enclosure');
134 28
        $this->escape = $this->filterControl($escape, 'escape');
135 28
    }
136
137
    /**
138
     * Set StreamIterator Flags
139
     *
140
     * @see http://php.net/manual/en/splfileobject.setflags.php
141
     *
142
     * @param int $flags
143
     */
144 56
    public function setFlags(int $flags)
145
    {
146 56
        $this->flags = $flags;
147 56
    }
148
149
    /**
150
     * Write a field array as a CSV line
151
     *
152
     * @see http://php.net/manual/en/splfileobject.fputcsv.php
153
     *
154
     * @param array  $fields
155
     * @param string $delimiter
156
     * @param string $enclosure
157
     * @param string $escape
158
     *
159
     * @return int|bool
160
     */
161 12
    public function fputcsv(array $fields, string $delimiter = ',', string $enclosure = '"', string $escape = '\\')
162
    {
163 12
        return fputcsv(
164 12
            $this->stream,
165
            $fields,
166 12
            $this->filterControl($delimiter, 'delimiter'),
167 12
            $this->filterControl($enclosure, 'enclosure'),
168 12
            $this->filterControl($escape, 'escape')
169
        );
170
    }
171
172
    /**
173
     * Get line number
174
     *
175
     * @see http://php.net/manual/en/splfileobject.key.php
176
     *
177
     * @return int
178
     */
179 32
    public function key()
180
    {
181 32
        return $this->offset;
182
    }
183
184
    /**
185
     * Read next line
186
     *
187
     * @see http://php.net/manual/en/splfileobject.next.php
188
     *
189
     */
190 30
    public function next()
191
    {
192 30
        $this->value = false;
193 30
        $this->offset++;
194 30
    }
195
196
    /**
197
     * Rewind the file to the first line
198
     *
199
     * @see http://php.net/manual/en/splfileobject.rewind.php
200
     *
201
     */
202 56
    public function rewind()
203
    {
204 56
        rewind($this->stream);
205 56
        $this->offset = 0;
206 56
        $this->value = false;
207 56
        if ($this->flags & SplFileObject::READ_AHEAD) {
208 32
            $this->current();
209
        }
210 56
    }
211
212
    /**
213
     * Not at EOF
214
     *
215
     * @see http://php.net/manual/en/splfileobject.valid.php
216
     *
217
     * @return bool
218
     */
219 52
    public function valid()
220
    {
221 52
        if ($this->flags & SplFileObject::READ_AHEAD) {
222 30
            return $this->current() !== false;
223
        }
224
225 22
        return !feof($this->stream);
226
    }
227
228
    /**
229
     * Retrieves the current line of the file.
230
     *
231
     * @see http://php.net/manual/en/splfileobject.current.php
232
     *
233
     * @return mixed
234
     */
235 34
    public function current()
236
    {
237 34
        if (false !== $this->value) {
238 32
            return $this->value;
239
        }
240
241 34
        if (($this->flags & SplFileObject::READ_CSV) == SplFileObject::READ_CSV) {
242 32
            $this->value = $this->getCurrentRecord();
243
244 32
            return $this->value;
245
        }
246
247 2
        $this->value = $this->getCurrentLine();
248
249 2
        return $this->value;
250
    }
251
252
    /**
253
     * Retrieves the current line as a CSV Record
254
     *
255
     * @return array|bool
256
     */
257 32
    protected function getCurrentRecord()
258
    {
259
        do {
260 32
            $ret = fgetcsv($this->stream, 0, $this->delimiter, $this->enclosure, $this->escape);
261 32
        } while ($this->flags & SplFileObject::SKIP_EMPTY && $ret !== false && $ret[0] === null);
262
263 32
        return $ret;
264
    }
265
266
    /**
267
     * Retrieves the current line as a string
268
     *
269
     * @return string|bool
270
     */
271 52
    protected function getCurrentLine()
272
    {
273
        do {
274 52
            $line = fgets($this->stream);
275 52
        } while ($this->flags & SplFileObject::SKIP_EMPTY && $line !== false && rtrim($line, "\r\n") !== '');
276
277 52
        return $line;
278
    }
279
280
    /**
281
     * Seek to specified line
282
     *
283
     * @see http://php.net/manual/en/splfileobject.seek.php
284
     *
285
     * @param int $position
286
     */
287 20
    public function seek($position)
288
    {
289 20
        $position = $this->filterMinRange((int) $position, 0, 'Can\'t seek stream to negative line %d');
290 18
        foreach ($this as $key => $value) {
291 18
            if ($key === $position || feof($this->stream)) {
292 18
                $this->offset--;
293 18
                break;
294
            }
295
        }
296
297 18
        $this->current();
298 18
    }
299
300
    /**
301
     * Gets line from file
302
     *
303
     * @see http://php.net/manual/en/splfileobject.fgets.php
304
     *
305
     * @return string|bool
306
     */
307 52
    public function fgets()
308
    {
309 52
        if (false !== $this->value) {
310 2
            $this->next();
311
        }
312
313 52
        return $this->value = $this->getCurrentLine();
314
    }
315
316
    /**
317
     * Output all remaining data on a file pointer
318
     *
319
     * @see http://php.net/manual/en/splfileobject.fpatssthru.php
320
     *
321
     * @return int
322
     */
323 2
    public function fpassthru()
324
    {
325 2
        return fpassthru($this->stream);
326
    }
327
328
    /**
329
     * Read from file
330
     *
331
     * @see http://php.net/manual/en/splfileobject.fread.php
332
     *
333
     * @param int $length The number of bytes to read
334
     *
335
     * @return string|false
336
     */
337 20
    public function fread($length)
338
    {
339 20
        return fread($this->stream, $length);
340
    }
341
342
    /**
343
     * Seek to a position
344
     *
345
     * @see http://php.net/manual/en/splfileobject.fseek.php
346
     *
347
     * @param int $offset
348
     * @param int $whence
349
     *
350
     * @return int
351
     */
352 8
    public function fseek(int $offset, int $whence = SEEK_SET)
353
    {
354 8
        return fseek($this->stream, $offset, $whence);
355
    }
356
357
    /**
358
     * Write to stream
359
     *
360
     * @see http://php.net/manual/en/splfileobject.fwrite.php
361
     *
362
     * @param string $str
363
     * @param int    $length
364
     *
365
     * @return int|bool
366
     */
367 2
    public function fwrite(string $str, int $length = 0)
368
    {
369 2
        return fwrite($this->stream, $str, $length);
370
    }
371
372
    /**
373
     * append a filter
374
     *
375
     * @see http://php.net/manual/en/function.stream-filter-append.php
376
     *
377
     * @param string $filter_name
378
     * @param int    $read_write
379
     * @param mixed  $params
380
     *
381
     * @throws InvalidArgumentException if the filter can not be appended
382
     *
383
     * @return resource
384
     */
385 14
    public function appendFilter(string $filter_name, int $read_write, $params = null)
386
    {
387 14
        $res = @stream_filter_append($this->stream, $filter_name, $read_write, $params);
388 14
        if (is_resource($res)) {
389 14
            return $res;
390
        }
391
392 2
        throw new InvalidArgumentException(error_get_last()['message']);
393
    }
394
395
    /**
396
     * Removes a registered filter
397
     *
398
     * @see http://php.net/manual/en/function.stream-filter-remove.php
399
     *
400
     * @param resource $resource
401
     */
402 14
    public function removeFilter($resource)
403
    {
404 14
        return stream_filter_remove($resource);
405
    }
406
407
    /**
408
     * Flushes the output to a file
409
     *
410
     * @see http://php.net/manual/en/splfileobject.fwrite.php
411
     *
412
     * @return bool
413
     */
414 20
    public function fflush()
415
    {
416 20
        return fflush($this->stream);
417
    }
418
419
    /**
420
     * @inheritdoc
421
     */
422 2
    public function __clone()
423
    {
424 2
        throw new LogicException('An object of class '.StreamIterator::class.' cannot be cloned');
425
    }
426
}
427