Completed
Push — master ( 35706b...37c225 )
by ignace nyamagana
02:12
created

StreamIterator::key()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 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 8.2.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
namespace League\Csv\Modifier;
14
15
use InvalidArgumentException;
16
use Iterator;
17
use SplFileObject;
18
19
/**
20
 *  A Stream Iterator
21
 *
22
 * @package League.csv
23
 * @since  8.2.0
24
 * @internal used internally to iterate over a stream resource
25
 *
26
 */
27
class StreamIterator implements Iterator
28
{
29
    protected $stream;
30
31
    protected $current_line;
32
33
    protected $current_line_number;
34
35
    protected $flags = SplFileObject::READ_CSV;
36
37
    /**
38
     * the field delimiter (one character only)
39
     *
40
     * @var string
41
     */
42
    protected $delimiter = ',';
43
44
    /**
45
     * the field enclosure character (one character only)
46
     *
47
     * @var string
48
     */
49
    protected $enclosure = '"';
50
51
    /**
52
     * the field escape character (one character only)
53
     *
54
     * @var string
55
     */
56
    protected $escape = '\\';
57
58
    /**
59
     * New instance
60
     *
61
     * @param resource $stream stream type resource
62
     */
63
    public function __construct($stream)
64
    {
65
        if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
66
            throw new InvalidArgumentException(sprintf(
67
                'Expected resource to be a stream, received %s instead',
68
                is_object($stream) ? get_class($stream) : gettype($stream)
69
            ));
70
        }
71
72
        $data = stream_get_meta_data($stream);
73
        if (!$data['seekable']) {
74
            throw new InvalidArgumentException('The stream must be seekable');
75
        }
76
77
        $this->stream = $stream;
78
    }
79
80
    /**
81
     * Get the delimiter, enclosure and escape character for CSV
82
     *
83
     * @see http://php.net/manual/en/splfileinfo.iswritable.php
84
     *
85
     * @return array
86
     */
87
    public function getCsvControl()
88
    {
89
        return [
90
            $this->delimiter,
91
            $this->enclosure,
92
            $this->escape,
93
        ];
94
    }
95
96
    /**
97
     * Set CSV control
98
     *
99
     * @see http://php.net/manual/en/splfileobject.setcsvcontrol.php
100
     *
101
     * @param string $delimiter
102
     * @param string $enclosure
103
     * @param string $escape
104
     */
105
    public function setCsvControl($delimiter = ',', $enclosure = '"', $escape = '\\')
106
    {
107
        $this->delimiter = $this->filterControl($delimiter, 'delimiter');
108
        $this->enclosure = $this->filterControl($enclosure, 'enclosure');
109
        $this->escape = $this->filterControl($escape, 'escape');
110
    }
111
112
    /**
113
     * Filter Csv control character
114
     *
115
     * @param string $char Csv control character
116
     * @param string $type Csv control character type
117
     *
118
     * @throws InvalidArgumentException If the Csv control character is not one character only.
119
     *
120
     * @return string
121
     */
122
    private function filterControl($char, $type)
123
    {
124
        if (1 == strlen($char)) {
125
            return $char;
126
        }
127
        throw new InvalidArgumentException(sprintf('The %s character must be a single character', $type));
128
    }
129
130
    /**
131
     * Set Flags
132
     *
133
     * @see http://php.net/manual/en/splfileobject.setflags.php
134
     *
135
     * @param int $flags
136
     */
137
    public function setFlags($flags)
138
    {
139
        if (false === filter_var($flags, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
140
            throw new InvalidArgumentException('The flags must be a positive integer');
141
        }
142
143
        $this->flags = $flags;
144
    }
145
146
    /**
147
     * Write a field array as a CSV line
148
     *
149
     * @see http://php.net/manual/en/splfileobject.fputcsv.php
150
     *
151
     * @param array  $fields
152
     * @param string $delimiter
153
     * @param string $enclosure
154
     * @param string $escape
155
     *
156
     * @return int
157
     */
158
    public function fputcsv(array $fields, $delimiter = null, $enclosure = null, $escape = null)
159
    {
160
        return fputcsv(
161
            $this->stream,
162
            $fields,
163
            null !== $delimiter ? $this->filterControl($delimiter, 'delimiter') : $this->delimiter,
164
            null !== $enclosure ? $this->filterControl($enclosure, 'enclosure') : $this->enclosure,
165
            null !== $escape ? $this->filterControl($escape, 'escape') : $this->escape
166
        );
167
    }
168
169
    /**
170
     * Retrieves the current line of the file.
171
     *
172
     * @return string|array
173
     */
174
    public function current()
175
    {
176
        if (false !== $this->current_line) {
177
            return $this->current_line;
178
        }
179
180
        if (($this->flags & SplFileObject::READ_CSV) == SplFileObject::READ_CSV) {
181
            $this->current_line = $this->getCurrentRecord();
182
            return $this->current_line;
183
        }
184
185
        $this->current_line = $this->getCurrentLine();
186
        return $this->current_line;
187
    }
188
189
    /**
190
     * Retrieves the current line as a CSV Record
191
     *
192
     * @return array
193
     */
194
    protected function getCurrentRecord()
195
    {
196
        do {
197
            $ret = fgetcsv($this->stream, 0, $this->delimiter, $this->enclosure, $this->escape);
198
        } while ($this->flags & SplFileObject::SKIP_EMPTY && $ret !== false && $ret[0] === null);
199
200
        return $ret;
201
    }
202
203
    /**
204
     * Retrieves the current line as a string
205
     *
206
     * @return string
207
     */
208
    protected function getCurrentLine()
209
    {
210
        do {
211
            $line = fgets($this->stream);
212
        } while ($this->flags & SplFileObject::SKIP_EMPTY && $line !== false && rtrim($line, "\r\n") !== '');
213
214
        return $line;
215
    }
216
217
    /**
218
     * Get line number
219
     *
220
     * @return int
221
     */
222
    public function key()
223
    {
224
        return $this->current_line_number;
225
    }
226
227
    /**
228
     * Read next line
229
     */
230
    public function next()
231
    {
232
        $this->current_line = false;
233
        $this->current_line_number++;
234
    }
235
236
    /**
237
     * Rewind the file to the first line
238
     */
239
    public function rewind()
240
    {
241
        rewind($this->stream);
242
        $this->current_line_number = 0;
243
        $this->current_line = false;
244
        if ($this->flags & SplFileObject::READ_AHEAD) {
245
            $this->current();
246
        }
247
    }
248
249
    /**
250
     * Not at EOF
251
     *
252
     * @return bool
253
     */
254
    public function valid()
255
    {
256
        if ($this->flags & SplFileObject::READ_AHEAD) {
257
            return $this->current() !== false;
258
        }
259
260
        return !feof($this->stream);
261
    }
262
263
    /**
264
     * Gets line from file
265
     *
266
     * @see http://php.net/manual/en/splfileobject.fgets.php
267
     *
268
     * @return string
269
     */
270
    public function fgets()
271
    {
272
        if (false !== $this->current_line) {
273
            $this->next();
274
        }
275
        return $this->current_line = $this->getCurrentLine();
276
    }
277
278
    /**
279
     * Output all remaining data on a file pointer
280
     *
281
     * @see http://php.net/manual/en/splfileobject.fpatssthru.php
282
     *
283
     * @return int
284
     */
285
    public function fpassthru()
286
    {
287
        return fpassthru($this->stream);
288
    }
289
290
    /**
291
     * Seek to a position
292
     *
293
     * @see http://php.net/manual/en/splfileobject.fseek.php
294
     *
295
     * @param int $offset
296
     * @param int $whence
297
     *
298
     * @return int
299
     */
300
    public function fseek($offset, $whence = SEEK_SET)
301
    {
302
        return fseek($this->stream, $offset, $whence);
303
    }
304
305
    /**
306
     * Write to stream
307
     *
308
     * @see http://php.net/manual/en/splfileobject.fwrite.php
309
     *
310
     * @param string $str
311
     * @param int    $length
312
     *
313
     * @return int
314
     */
315
    public function fwrite($str, $length = 0)
316
    {
317
        return fwrite($this->stream, $str, $length);
318
    }
319
320
    /**
321
     * close the file pointer
322
     */
323
    public function __destruct()
324
    {
325
        $this->stream = null;
326
    }
327
}
328