Completed
Push — master ( d8a5e5...b3757c )
by ignace nyamagana
03:17
created

Output::getEncodingFrom()   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 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
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 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 $encodingFrom = '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 4
    public function setEncodingFrom($str)
58
    {
59 4
        $str = str_replace('_', '-', $str);
60 4
        $str = filter_var($str, FILTER_SANITIZE_STRING, ['flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH]);
61 4
        if (empty($str)) {
62 2
            throw new InvalidArgumentException('you should use a valid charset');
63
        }
64 4
        $this->encodingFrom = strtoupper($str);
65
66 4
        return $this;
67
    }
68
69
    /**
70
     * Gets the source CSV encoding charset
71
     *
72
     * @return string
73
     */
74 2
    public function getEncodingFrom()
75
    {
76 2
        return $this->encodingFrom;
77
    }
78
79
    /**
80
     * Sets the BOM sequence to prepend the CSV on output
81
     *
82
     * @param string $str The BOM sequence
83
     *
84
     * @return static
85
     */
86 6
    public function setOutputBOM($str = null)
87
    {
88 6
        if (empty($str)) {
89 2
            $this->output_bom = null;
90
91 2
            return $this;
92
        }
93
94 6
        $this->output_bom = (string) $str;
95
96 6
        return $this;
97
    }
98
99
    /**
100
     * Returns the BOM sequence in use on Output methods
101
     *
102
     * @return string
103
     */
104 2
    public function getOutputBOM()
105
    {
106 2
        return $this->output_bom;
107
    }
108
109
    /**
110
     * Returns the BOM sequence of the given CSV
111
     *
112
     * @return string
113
     */
114 34
    public function getInputBOM()
115
    {
116 34
        if (!$this->input_bom) {
117
            $bom = [
118 34
                AbstractCsv::BOM_UTF32_BE, AbstractCsv::BOM_UTF32_LE,
119 34
                AbstractCsv::BOM_UTF16_BE, AbstractCsv::BOM_UTF16_LE, AbstractCsv::BOM_UTF8,
120 34
            ];
121 34
            $csv = $this->getIterator();
122 34
            $csv->setFlags(SplFileObject::READ_CSV);
123 34
            $csv->rewind();
124 34
            $line = $csv->fgets();
125
            $res  = array_filter($bom, function ($sequence) use ($line) {
126 34
                return strpos($line, $sequence) === 0;
127 34
            });
128
129 34
            $this->input_bom = array_shift($res);
130 34
        }
131
132 34
        return $this->input_bom;
133
    }
134
135
    /**
136
     * @inheritdoc
137
     */
138
    abstract public function getIterator();
139
140
    /**
141
     * Outputs all data on the CSV file
142
     *
143
     * @param string $filename CSV downloaded name if present adds extra headers
144
     *
145
     * @return int Returns the number of characters read from the handle
146
     *             and passed through to the output.
147
     */
148 4
    public function output($filename = null)
149
    {
150 4
        if (null !== $filename) {
151 4
            $filename = filter_var($filename, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
152 4
            header('Content-Type: application/octet-stream');
153 4
            header('Content-Transfer-Encoding: binary');
154 4
            header("Content-Disposition: attachment; filename=\"$filename\"");
155 4
        }
156
157 4
        return $this->fpassthru();
158
    }
159
160
    /**
161
     * Outputs all data from the CSV
162
     *
163
     * @return int Returns the number of characters read from the handle
164
     *             and passed through to the output.
165
     */
166 12
    protected function fpassthru()
167
    {
168 12
        $bom = '';
169 12
        $input_bom = $this->getInputBOM();
170 12
        if ($this->output_bom && $input_bom != $this->output_bom) {
171 4
            $bom = $this->output_bom;
172 4
        }
173 12
        $csv = $this->getIterator();
174 12
        $csv->setFlags(SplFileObject::READ_CSV);
175 12
        $csv->rewind();
176 12
        if (!empty($bom)) {
177 4
            $csv->fseek(mb_strlen($input_bom));
178 4
        }
179 12
        echo $bom;
180 12
        $res = $csv->fpassthru();
181
182 12
        return $res + strlen($bom);
183
    }
184
185
    /**
186
     * Retrieves the CSV content
187
     *
188
     * @return string
189
     */
190 8
    public function __toString()
191
    {
192 8
        ob_start();
193 8
        $this->fpassthru();
194
195 8
        return ob_get_clean();
196
    }
197
198
    /**
199
     * JsonSerializable Interface
200
     *
201
     * @return array
202
     */
203 4
    public function jsonSerialize()
204
    {
205 4
        return iterator_to_array($this->convertToUtf8($this->getQueryIterator()), false);
206
    }
207
208
    /**
209
     * Returns the CSV Iterator
210
     *
211
     * @return Iterator
212
     */
213
    abstract protected function getQueryIterator();
214
215
    /**
216
     * Convert Csv file into UTF-8
217
     *
218
     * @param Iterator $iterator
219
     *
220
     * @return Iterator
221
     */
222 14
    protected function convertToUtf8(Iterator $iterator)
223
    {
224 14
        if (stripos($this->encodingFrom, 'UTF-8') !== false) {
225 12
            return $iterator;
226
        }
227
228
        $convertCell = function ($value) {
229 2
            return mb_convert_encoding($value, 'UTF-8', $this->encodingFrom);
230 2
        };
231
232
        $convertRow = function (array $row) use ($convertCell) {
233 2
            return array_map($convertCell, $row);
234 2
        };
235
236 2
        return new MapIterator($iterator, $convertRow);
237
    }
238
239
    /**
240
     * Returns a HTML table representation of the CSV Table
241
     *
242
     * @param string $class_name optional classname
243
     *
244
     * @return string
245
     */
246 4
    public function toHTML($class_name = 'table-csv-data')
247
    {
248 4
        $doc = $this->toXML('table', 'tr', 'td');
249 4
        $doc->documentElement->setAttribute('class', $class_name);
250
251 4
        return $doc->saveHTML($doc->documentElement);
252
    }
253
254
    /**
255
     * Transforms a CSV into a XML
256
     *
257
     * @param string $root_name XML root node name
258
     * @param string $row_name  XML row node name
259
     * @param string $cell_name XML cell node name
260
     *
261
     * @return DomDocument
262
     */
263 10
    public function toXML($root_name = 'csv', $row_name = 'row', $cell_name = 'cell')
264
    {
265 10
        $doc = new DomDocument('1.0', 'UTF-8');
266 10
        $root = $doc->createElement($root_name);
267 10
        $iterator = $this->convertToUtf8($this->getQueryIterator());
268 10
        foreach ($iterator as $row) {
269 10
            $item = $doc->createElement($row_name);
270 10
            array_walk($row, function ($value) use (&$item, $doc, $cell_name) {
271 10
                $content = $doc->createTextNode($value);
272 10
                $cell = $doc->createElement($cell_name);
273 10
                $cell->appendChild($content);
274 10
                $item->appendChild($cell);
275 10
            });
276 10
            $root->appendChild($item);
277 10
        }
278 10
        $doc->appendChild($root);
279
280 10
        return $doc;
281
    }
282
}
283