Completed
Push — master ( 0a1b53...8f18dd )
by ignace nyamagana
12:46
created

Output::setInputEncoding()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
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 8.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
namespace League\Csv\Config;
14
15
use DomDocument;
16
use InvalidArgumentException;
17
use Iterator;
18
use League\Csv\AbstractCsv;
19
use League\Csv\Modifier\MapIterator;
20
use SplFileObject;
21
22
/**
23
 *  A trait to output CSV
24
 *
25
 * @package League.csv
26
 * @since  6.3.0
27
 *
28
 */
29
trait Output
30
{
31
    /**
32
     * Charset Encoding for the CSV
33
     *
34
     * @var string
35
     */
36
    protected $input_encoding = 'UTF-8';
37
38
    /**
39
     * The Input file BOM character
40
     * @var string
41
     */
42
    protected $input_bom;
43
44
    /**
45
     * The Output file BOM character
46
     * @var string
47
     */
48
    protected $output_bom = '';
49
50
    /**
51
     * Sets the CSV encoding charset
52
     *
53
     * @param string $str
54
     *
55
     * @return static
56
     */
57 6
    public function setInputEncoding($str)
58
    {
59 6
        $str = str_replace('_', '-', $str);
60 6
        $str = filter_var($str, FILTER_SANITIZE_STRING, ['flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH]);
61 6
        if (empty($str)) {
62 3
            throw new InvalidArgumentException('you should use a valid charset');
63
        }
64 6
        $this->input_encoding = strtoupper($str);
65
66 6
        return $this;
67
    }
68
69
    /**
70
     * Sets the CSV encoding charset
71
     *
72
     * DEPRECATION WARNING! This method will be removed in the next major point release
73
     *
74 3
     * @deprecated deprecated since version 4.1
75
     *
76 3
     * @param string $str
77
     *
78
     * @return static
79
     */
80
    public function setEncodingFrom($str)
81
    {
82
        return $this->setInputEncoding($str);
83
    }
84
85
    /**
86 9
     * Gets the source CSV encoding charset
87
     *
88 9
     * @return string
89 3
     */
90
    public function getInputEncoding()
91 3
    {
92
        return $this->input_encoding;
93
    }
94 9
95
    /**
96 9
     * Gets the source CSV encoding charset
97
     *
98
     * DEPRECATION WARNING! This method will be removed in the next major point release
99
     *
100
     * @deprecated deprecated since version 4.1
101
     *
102
     * @return string
103
     */
104 3
    public function getEncodingFrom()
105
    {
106 3
        return $this->input_encoding;
107
    }
108
109
    /**
110
     * Sets the BOM sequence to prepend the CSV on output
111
     *
112
     * @param string $str The BOM sequence
113
     *
114 51
     * @return static
115
     */
116 51
    public function setOutputBOM($str)
117
    {
118 51
        if (empty($str)) {
119 34
            $this->output_bom = '';
120 34
121 51
            return $this;
122 51
        }
123 51
124 51
        $this->output_bom = (string) $str;
125
126 51
        return $this;
127 51
    }
128
129 51
    /**
130 34
     * Returns the BOM sequence in use on Output methods
131
     *
132 51
     * @return string
133
     */
134
    public function getOutputBOM()
135
    {
136
        return $this->output_bom;
137
    }
138
139
    /**
140
     * Returns the BOM sequence of the given CSV
141
     *
142
     * @return string
143
     */
144
    public function getInputBOM()
145
    {
146
        if (null === $this->input_bom) {
147
            $bom = [
148 6
                AbstractCsv::BOM_UTF32_BE, AbstractCsv::BOM_UTF32_LE,
149
                AbstractCsv::BOM_UTF16_BE, AbstractCsv::BOM_UTF16_LE, AbstractCsv::BOM_UTF8,
150 6
            ];
151 6
            $csv = $this->getIterator();
152 6
            $csv->setFlags(SplFileObject::READ_CSV);
153 6
            $csv->rewind();
154 6
            $line = $csv->fgets();
155 4
            $res  = array_filter($bom, function ($sequence) use ($line) {
156
                return strpos($line, $sequence) === 0;
157 6
            });
158
159
            $this->input_bom = (string) array_shift($res);
160
        }
161
162
        return $this->input_bom;
163
    }
164
165
    /**
166 18
     * @inheritdoc
167
     */
168 18
    abstract public function getIterator();
169 18
170 18
    /**
171 6
     * Outputs all data on the CSV file
172 4
     *
173 18
     * @param string $filename CSV downloaded name if present adds extra headers
174 18
     *
175 18
     * @return int Returns the number of characters read from the handle
176 18
     *             and passed through to the output.
177 6
     */
178 4
    public function output($filename = null)
179 18
    {
180 18
        if (null !== $filename) {
181
            $filename = filter_var($filename, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
182 18
            header('Content-Type: application/octet-stream');
183
            header('Content-Transfer-Encoding: binary');
184
            header("Content-Disposition: attachment; filename=\"$filename\"");
185
        }
186
187
        return $this->fpassthru();
188
    }
189
190 12
    /**
191
     * Outputs all data from the CSV
192 12
     *
193 12
     * @return int Returns the number of characters read from the handle
194
     *             and passed through to the output.
195 12
     */
196
    protected function fpassthru()
197
    {
198
        $bom = '';
199
        $input_bom = $this->getInputBOM();
200
        if ($this->output_bom && $input_bom != $this->output_bom) {
201
            $bom = $this->output_bom;
202
        }
203 6
        $csv = $this->getIterator();
204
        $csv->setFlags(SplFileObject::READ_CSV);
205 6
        $csv->rewind();
206
        if (!empty($bom)) {
207
            $csv->fseek(mb_strlen($input_bom));
208
        }
209
        echo $bom;
210
        $res = $csv->fpassthru();
211
212
        return $res + strlen($bom);
213
    }
214
215
    /**
216
     * Retrieves the CSV content
217
     *
218
     * @return string
219
     */
220
    public function __toString()
221
    {
222 21
        ob_start();
223
        $this->fpassthru();
224 21
225 18
        return ob_get_clean();
226
    }
227
228
    /**
229 3
     * @inheritdoc
230 3
     */
231
    public function jsonSerialize()
232
    {
233 3
        return iterator_to_array($this->convertToUtf8($this->getQueryIterator()), false);
234 3
    }
235
236 3
    /**
237
     * Returns the CSV Iterator
238
     *
239
     * @return Iterator
240
     */
241
    abstract protected function getQueryIterator();
242
243
    /**
244
     * Convert Csv file into UTF-8
245
     *
246 6
     * @param Iterator $iterator
247
     *
248 6
     * @return Iterator
249 6
     */
250
    protected function convertToUtf8(Iterator $iterator)
251 6
    {
252
        if (stripos($this->input_encoding, 'UTF-8') !== false) {
253
            return $iterator;
254
        }
255
256
        $convertCell = function ($value) {
257
            return mb_convert_encoding($value, 'UTF-8', $this->input_encoding);
258
        };
259
260
        $convertRow = function (array $row) use ($convertCell) {
261
            return array_map($convertCell, $row);
262
        };
263 15
264
        return new MapIterator($iterator, $convertRow);
265 15
    }
266 15
267 15
    /**
268 15
     * Returns a HTML table representation of the CSV Table
269 15
     *
270 15
     * @param string $class_attr optional classname
271 15
     *
272 15
     * @return string
273 15
     */
274 15
    public function toHTML($class_attr = 'table-csv-data')
275 15
    {
276 15
        $doc = $this->toXML('table', 'tr', 'td');
277 10
        $doc->documentElement->setAttribute('class', $class_attr);
278 15
279
        return $doc->saveHTML($doc->documentElement);
280 15
    }
281
282
    /**
283
     * Transforms a CSV into a XML
284
     *
285
     * @param string $root_name XML root node name
286
     * @param string $row_name  XML row node name
287
     * @param string $cell_name XML cell node name
288
     *
289
     * @return DomDocument
290
     */
291
    public function toXML($root_name = 'csv', $row_name = 'row', $cell_name = 'cell')
292
    {
293
        $doc = new DomDocument('1.0', 'UTF-8');
294
        $root = $doc->createElement($root_name);
295
        foreach ($this->convertToUtf8($this->getQueryIterator()) as $row) {
296
            $rowElement = $doc->createElement($row_name);
297
            array_walk($row, function ($value) use (&$rowElement, $doc, $cell_name) {
298
                $content = $doc->createTextNode($value);
299
                $cell = $doc->createElement($cell_name);
300
                $cell->appendChild($content);
301
                $rowElement->appendChild($cell);
302
            });
303
            $root->appendChild($rowElement);
304
        }
305
        $doc->appendChild($root);
306
307
        return $doc;
308
    }
309
}
310