Completed
Pull Request — master (#210)
by ignace nyamagana
02:41
created

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