Completed
Pull Request — master (#207)
by ignace nyamagana
09:14
created

AbstractCsv::__destruct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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\Config\ControlsTrait;
18
use League\Csv\Config\StreamTrait;
19
use SplFileObject;
20
21
/**
22
 *  An abstract class to enable basic CSV manipulation
23
 *
24
 * @package League.csv
25
 * @since  4.0.0
26
 *
27
 */
28
abstract class AbstractCsv
29
{
30
    use ControlsTrait;
31
    use StreamTrait;
32
33
    /**
34
     *  UTF-8 BOM sequence
35
     */
36
    const BOM_UTF8 = "\xEF\xBB\xBF";
37
38
    /**
39
     * UTF-16 BE BOM sequence
40
     */
41
    const BOM_UTF16_BE = "\xFE\xFF";
42
43
    /**
44
     * UTF-16 LE BOM sequence
45
     */
46
    const BOM_UTF16_LE = "\xFF\xFE";
47
48
    /**
49
     * UTF-32 BE BOM sequence
50
     */
51
    const BOM_UTF32_BE = "\x00\x00\xFE\xFF";
52
53
    /**
54
     * UTF-32 LE BOM sequence
55
     */
56
    const BOM_UTF32_LE = "\xFF\xFE\x00\x00";
57
58
    /**
59
     * The file open mode flag
60
     *
61
     * @var string
62
     */
63
    protected $open_mode;
64
65
    /**
66
     * Creates a new instance
67
     *
68
     * The file path can be:
69
     *
70
     * - a string
71
     * - a SplFileObject
72
     * - a StreamIterator
73
     *
74
     * @param mixed  $path      The file path
75
     * @param string $open_mode The file open mode flag
76
     */
77
    protected function __construct($path, string $open_mode = 'r+')
78
    {
79
        $this->open_mode = strtolower($open_mode);
80
        $this->path = $path;
81
        $this->initStreamFilter();
82
    }
83
84
    /**
85
     * The destructor
86
     */
87
    public function __destruct()
88
    {
89
        $this->path = null;
90
    }
91
92
    /**
93
     * Return a new {@link AbstractCsv} from a SplFileObject
94
     *
95
     * @param SplFileObject $file
96
     *
97
     * @return static
98
     */
99
    public static function createFromFileObject(SplFileObject $file): self
100
    {
101
        $csv = new static($file);
102
        $controls = $file->getCsvControl();
103
        $csv->setDelimiter($controls[0]);
104
        $csv->setEnclosure($controls[1]);
105 357
        if (isset($controls[2])) {
106
            $csv->setEscape($controls[2]);
107 357
        }
108 357
109 357
        return $csv;
110 357
    }
111
112
    /**
113
     * Return a new {@link AbstractCsv} from a PHP resource stream
114
     *
115 240
     * @param resource $stream
116
     *
117 240
     * @return static
118 240
     */
119
    public static function createFromStream($stream): self
120
    {
121
        return new static(new StreamIterator($stream));
122
    }
123
124
    /**
125
     * Return a new {@link AbstractCsv} from a string
126
     *
127 312
     * The string must be an object that implements the `__toString` method,
128
     * or a string
129 312
     *
130
     * @param string $str the string
131
     *
132
     * @return static
133
     */
134
    public static function createFromString(string $str): self
135
    {
136
        $stream = fopen('php://temp', 'r+');
137
        fwrite($stream, $str);
138
139
        return new static(new StreamIterator($stream));
140
    }
141
142 27
    /**
143
     * Return a new {@link AbstractCsv} from a file path
144 27
     *
145 27
     * @param string $path      file path
146
     * @param string $open_mode the file open mode flag
147 27
     *
148
     * @return static
149
     */
150
    public static function createFromPath(string $path, string $open_mode = 'r+'): self
151
    {
152
        return new static($path, $open_mode);
153
    }
154
155
    /**
156
     * Return a new {@link AbstractCsv} instance from another {@link AbstractCsv} object
157
     *
158
     * @param string $class     the class to be instantiated
159 90
     * @param string $open_mode the file open mode flag
160
     *
161 90
     * @return static
162 87
     */
163
    protected function newInstance(string $class, string $open_mode): self
164 3
    {
165
        $csv = new $class($this->path, $open_mode);
166
        $csv->delimiter = $this->delimiter;
167
        $csv->enclosure = $this->enclosure;
168
        $csv->escape = $this->escape;
169
        $csv->input_bom = $this->input_bom;
170
        $csv->output_bom = $this->output_bom;
171
        $csv->newline = $this->newline;
172
173
        return $csv;
174
    }
175
176
    /**
177 54
     * Return a new {@link Writer} instance from a {@link AbstractCsv} object
178
     *
179 54
     * @param string $open_mode the file open mode flag
180 3
     *
181
     * @return Writer
182
     */
183 51
    public function newWriter(string $open_mode = 'r+'): self
184 3
    {
185 2
        return $this->newInstance(Writer::class, $open_mode);
186
    }
187 51
188
    /**
189
     * Return a new {@link Reader} instance from a {@link AbstractCsv} object
190
     *
191
     * @param string $open_mode the file open mode flag
192
     *
193
     * @return Reader
194
     */
195
    public function newReader(string $open_mode = 'r+'): self
196
    {
197
        return $this->newInstance(Reader::class, $open_mode);
198 6
    }
199
200 6
    /**
201 6
     * Set the Inner Iterator
202 6
     *
203 6
     * @return StreamIterator|SplFileObject
204 6
     */
205 6
    protected function getCsvDocument()
206 6
    {
207 6
        if ($this->path instanceof StreamIterator || $this->path instanceof SplFileObject) {
208
            return $this->path;
209 6
        }
210
211
        return new SplFileObject($this->getStreamFilterPath(), $this->open_mode);
212
    }
213
214
    /**
215
     * Outputs all data on the CSV file
216
     *
217
     * @param string $filename CSV downloaded name if present adds extra headers
218
     *
219 3
     * @return int Returns the number of characters read from the handle
220
     *             and passed through to the output.
221 3
     */
222
    public function output(string $filename = null): int
223
    {
224
        if (null !== $filename) {
225
            $filename = filter_var($filename, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
226
            header('Content-Type: text/csv');
227
            header('Content-Transfer-Encoding: binary');
228
            header("Content-Disposition: attachment; filename=\"$filename\"");
229
        }
230
231 3
        return $this->fpassthru();
232
    }
233 3
234
    /**
235
     * Outputs all data from the CSV
236
     *
237
     * @return int Returns the number of characters read from the handle
238
     *             and passed through to the output.
239
     */
240
    protected function fpassthru(): int
241 267
    {
242
        $bom = '';
243 267
        $input_bom = $this->getInputBOM();
244 267
        if ($this->output_bom && $input_bom != $this->output_bom) {
245 33
            $bom = $this->output_bom;
246 22
        }
247 267
        $csv = $this->getCsvDocument();
248 267
        $csv->rewind();
249
        if ('' !== $bom) {
250 267
            $csv->fseek(mb_strlen($input_bom));
251
        }
252
        echo $bom;
253
        $res = $csv->fpassthru();
254
255
        return $res + strlen($bom);
256
    }
257
258
    /**
259
     * Retrieves the CSV content
260
     *
261
     * @return string
262
     */
263
    public function __toString(): string
264
    {
265
        ob_start();
266
        $this->fpassthru();
267
268
        return ob_get_clean();
269
    }
270
}
271