1<?php
2
3/** PHPExcel root directory */
4if (!defined('PHPEXCEL_ROOT')) {
5    /**
6     * @ignore
7     */
8    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
9    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
10}
11
12/**
13 * PHPExcel_Reader_CSV
14 *
15 * Copyright (c) 2006 - 2015 PHPExcel
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
30 *
31 * @category   PHPExcel
32 * @package    PHPExcel_Reader
33 * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
34 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
35 * @version    ##VERSION##, ##DATE##
36 */
37class PHPExcel_Reader_CSV extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
38{
39    /**
40     * Input encoding
41     *
42     * @access    private
43     * @var    string
44     */
45    private $inputEncoding = 'UTF-8';
46
47    /**
48     * Delimiter
49     *
50     * @access    private
51     * @var string
52     */
53    private $delimiter = ',';
54
55    /**
56     * Enclosure
57     *
58     * @access    private
59     * @var    string
60     */
61    private $enclosure = '"';
62
63    /**
64     * Sheet index to read
65     *
66     * @access    private
67     * @var    int
68     */
69    private $sheetIndex = 0;
70
71    /**
72     * Load rows contiguously
73     *
74     * @access    private
75     * @var    int
76     */
77    private $contiguous = false;
78
79    /**
80     * Row counter for loading rows contiguously
81     *
82     * @var    int
83     */
84    private $contiguousRow = -1;
85
86
87    /**
88     * Create a new PHPExcel_Reader_CSV
89     */
90    public function __construct()
91    {
92        $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
93    }
94
95    /**
96     * Validate that the current file is a CSV file
97     *
98     * @return boolean
99     */
100    protected function isValidFormat()
101    {
102        return true;
103    }
104
105    /**
106     * Set input encoding
107     *
108     * @param string $pValue Input encoding
109     */
110    public function setInputEncoding($pValue = 'UTF-8')
111    {
112        $this->inputEncoding = $pValue;
113        return $this;
114    }
115
116    /**
117     * Get input encoding
118     *
119     * @return string
120     */
121    public function getInputEncoding()
122    {
123        return $this->inputEncoding;
124    }
125
126    /**
127     * Move filepointer past any BOM marker
128     *
129     */
130    protected function skipBOM()
131    {
132        rewind($this->fileHandle);
133
134        switch ($this->inputEncoding) {
135            case 'UTF-8':
136                fgets($this->fileHandle, 4) == "\xEF\xBB\xBF" ?
137                    fseek($this->fileHandle, 3) : fseek($this->fileHandle, 0);
138                break;
139            case 'UTF-16LE':
140                fgets($this->fileHandle, 3) == "\xFF\xFE" ?
141                    fseek($this->fileHandle, 2) : fseek($this->fileHandle, 0);
142                break;
143            case 'UTF-16BE':
144                fgets($this->fileHandle, 3) == "\xFE\xFF" ?
145                    fseek($this->fileHandle, 2) : fseek($this->fileHandle, 0);
146                break;
147            case 'UTF-32LE':
148                fgets($this->fileHandle, 5) == "\xFF\xFE\x00\x00" ?
149                    fseek($this->fileHandle, 4) : fseek($this->fileHandle, 0);
150                break;
151            case 'UTF-32BE':
152                fgets($this->fileHandle, 5) == "\x00\x00\xFE\xFF" ?
153                    fseek($this->fileHandle, 4) : fseek($this->fileHandle, 0);
154                break;
155            default:
156                break;
157        }
158    }
159
160    /**
161     * Identify any separator that is explicitly set in the file
162     *
163     */
164    protected function checkSeparator()
165    {
166        $line = fgets($this->fileHandle);
167        if ($line === false) {
168            return;
169        }
170
171        if ((strlen(trim($line, "\r\n")) == 5) && (stripos($line, 'sep=') === 0)) {
172            $this->delimiter = substr($line, 4, 1);
173            return;
174        }
175        return $this->skipBOM();
176    }
177
178    /**
179     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
180     *
181     * @param     string         $pFilename
182     * @throws    PHPExcel_Reader_Exception
183     */
184    public function listWorksheetInfo($pFilename)
185    {
186        // Open file
187        $this->openFile($pFilename);
188        if (!$this->isValidFormat()) {
189            fclose($this->fileHandle);
190            throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
191        }
192        $fileHandle = $this->fileHandle;
193
194        // Skip BOM, if any
195        $this->skipBOM();
196        $this->checkSeparator();
197
198        $escapeEnclosures = array( "\\" . $this->enclosure, $this->enclosure . $this->enclosure );
199
200        $worksheetInfo = array();
201        $worksheetInfo[0]['worksheetName'] = 'Worksheet';
202        $worksheetInfo[0]['lastColumnLetter'] = 'A';
203        $worksheetInfo[0]['lastColumnIndex'] = 0;
204        $worksheetInfo[0]['totalRows'] = 0;
205        $worksheetInfo[0]['totalColumns'] = 0;
206
207        // Loop through each line of the file in turn
208        while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
209            $worksheetInfo[0]['totalRows']++;
210            $worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
211        }
212
213        $worksheetInfo[0]['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex']);
214        $worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
215
216        // Close file
217        fclose($fileHandle);
218
219        return $worksheetInfo;
220    }
221
222    /**
223     * Loads PHPExcel from file
224     *
225     * @param     string         $pFilename
226     * @return PHPExcel
227     * @throws PHPExcel_Reader_Exception
228     */
229    public function load($pFilename)
230    {
231        // Create new PHPExcel
232        $objPHPExcel = new PHPExcel();
233
234        // Load into this instance
235        return $this->loadIntoExisting($pFilename, $objPHPExcel);
236    }
237
238    /**
239     * Loads PHPExcel from file into PHPExcel instance
240     *
241     * @param     string         $pFilename
242     * @param    PHPExcel    $objPHPExcel
243     * @return     PHPExcel
244     * @throws     PHPExcel_Reader_Exception
245     */
246    public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
247    {
248        $lineEnding = ini_get('auto_detect_line_endings');
249        ini_set('auto_detect_line_endings', true);
250
251        // Open file
252        $this->openFile($pFilename);
253        if (!$this->isValidFormat()) {
254            fclose($this->fileHandle);
255            throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
256        }
257        $fileHandle = $this->fileHandle;
258
259        // Skip BOM, if any
260        $this->skipBOM();
261        $this->checkSeparator();
262
263        // Create new PHPExcel object
264        while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) {
265            $objPHPExcel->createSheet();
266        }
267        $sheet = $objPHPExcel->setActiveSheetIndex($this->sheetIndex);
268
269        $escapeEnclosures = array( "\\" . $this->enclosure,
270                                   $this->enclosure . $this->enclosure
271                                 );
272
273        // Set our starting row based on whether we're in contiguous mode or not
274        $currentRow = 1;
275        if ($this->contiguous) {
276            $currentRow = ($this->contiguousRow == -1) ? $sheet->getHighestRow(): $this->contiguousRow;
277        }
278
279        // Loop through each line of the file in turn
280        while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
281            $columnLetter = 'A';
282            foreach ($rowData as $rowDatum) {
283                if ($rowDatum != '' && $this->readFilter->readCell($columnLetter, $currentRow)) {
284                    // Unescape enclosures
285                    $rowDatum = str_replace($escapeEnclosures, $this->enclosure, $rowDatum);
286
287                    // Convert encoding if necessary
288                    if ($this->inputEncoding !== 'UTF-8') {
289                        $rowDatum = PHPExcel_Shared_String::ConvertEncoding($rowDatum, 'UTF-8', $this->inputEncoding);
290                    }
291
292                    // Set cell value
293                    $sheet->getCell($columnLetter . $currentRow)->setValue($rowDatum);
294                }
295                ++$columnLetter;
296            }
297            ++$currentRow;
298        }
299
300        // Close file
301        fclose($fileHandle);
302
303        if ($this->contiguous) {
304            $this->contiguousRow = $currentRow;
305        }
306
307        ini_set('auto_detect_line_endings', $lineEnding);
308
309        // Return
310        return $objPHPExcel;
311    }
312
313    /**
314     * Get delimiter
315     *
316     * @return string
317     */
318    public function getDelimiter()
319    {
320        return $this->delimiter;
321    }
322
323    /**
324     * Set delimiter
325     *
326     * @param    string    $pValue        Delimiter, defaults to ,
327     * @return    PHPExcel_Reader_CSV
328     */
329    public function setDelimiter($pValue = ',')
330    {
331        $this->delimiter = $pValue;
332        return $this;
333    }
334
335    /**
336     * Get enclosure
337     *
338     * @return string
339     */
340    public function getEnclosure()
341    {
342        return $this->enclosure;
343    }
344
345    /**
346     * Set enclosure
347     *
348     * @param    string    $pValue        Enclosure, defaults to "
349     * @return PHPExcel_Reader_CSV
350     */
351    public function setEnclosure($pValue = '"')
352    {
353        if ($pValue == '') {
354            $pValue = '"';
355        }
356        $this->enclosure = $pValue;
357        return $this;
358    }
359
360    /**
361     * Get sheet index
362     *
363     * @return integer
364     */
365    public function getSheetIndex()
366    {
367        return $this->sheetIndex;
368    }
369
370    /**
371     * Set sheet index
372     *
373     * @param    integer        $pValue        Sheet index
374     * @return PHPExcel_Reader_CSV
375     */
376    public function setSheetIndex($pValue = 0)
377    {
378        $this->sheetIndex = $pValue;
379        return $this;
380    }
381
382    /**
383     * Set Contiguous
384     *
385     * @param boolean $contiguous
386     */
387    public function setContiguous($contiguous = false)
388    {
389        $this->contiguous = (bool) $contiguous;
390        if (!$contiguous) {
391            $this->contiguousRow = -1;
392        }
393
394        return $this;
395    }
396
397    /**
398     * Get Contiguous
399     *
400     * @return boolean
401     */
402    public function getContiguous()
403    {
404        return $this->contiguous;
405    }
406}
407