1<?php
2
3namespace Box\Spout\Reader\CSV;
4
5use Box\Spout\Common\Exception\IOException;
6use Box\Spout\Reader\Common\Entity\Options;
7use Box\Spout\Reader\CSV\Creator\InternalEntityFactory;
8use Box\Spout\Reader\ReaderAbstract;
9
10/**
11 * Class Reader
12 * This class provides support to read data from a CSV file.
13 */
14class Reader extends ReaderAbstract
15{
16    /** @var resource Pointer to the file to be written */
17    protected $filePointer;
18
19    /** @var SheetIterator To iterator over the CSV unique "sheet" */
20    protected $sheetIterator;
21
22    /** @var string Original value for the "auto_detect_line_endings" INI value */
23    protected $originalAutoDetectLineEndings;
24
25    /**
26     * Sets the field delimiter for the CSV.
27     * Needs to be called before opening the reader.
28     *
29     * @param string $fieldDelimiter Character that delimits fields
30     * @return Reader
31     */
32    public function setFieldDelimiter($fieldDelimiter)
33    {
34        $this->optionsManager->setOption(Options::FIELD_DELIMITER, $fieldDelimiter);
35
36        return $this;
37    }
38
39    /**
40     * Sets the field enclosure for the CSV.
41     * Needs to be called before opening the reader.
42     *
43     * @param string $fieldEnclosure Character that enclose fields
44     * @return Reader
45     */
46    public function setFieldEnclosure($fieldEnclosure)
47    {
48        $this->optionsManager->setOption(Options::FIELD_ENCLOSURE, $fieldEnclosure);
49
50        return $this;
51    }
52
53    /**
54     * Sets the encoding of the CSV file to be read.
55     * Needs to be called before opening the reader.
56     *
57     * @param string $encoding Encoding of the CSV file to be read
58     * @return Reader
59     */
60    public function setEncoding($encoding)
61    {
62        $this->optionsManager->setOption(Options::ENCODING, $encoding);
63
64        return $this;
65    }
66
67    /**
68     * Returns whether stream wrappers are supported
69     *
70     * @return bool
71     */
72    protected function doesSupportStreamWrapper()
73    {
74        return true;
75    }
76
77    /**
78     * Opens the file at the given path to make it ready to be read.
79     * If setEncoding() was not called, it assumes that the file is encoded in UTF-8.
80     *
81     * @param  string $filePath Path of the CSV file to be read
82     * @throws \Box\Spout\Common\Exception\IOException
83     * @return void
84     */
85    protected function openReader($filePath)
86    {
87        $this->originalAutoDetectLineEndings = ini_get('auto_detect_line_endings');
88        ini_set('auto_detect_line_endings', '1');
89
90        $this->filePointer = $this->globalFunctionsHelper->fopen($filePath, 'r');
91        if (!$this->filePointer) {
92            throw new IOException("Could not open file $filePath for reading.");
93        }
94
95        /** @var InternalEntityFactory $entityFactory */
96        $entityFactory = $this->entityFactory;
97
98        $this->sheetIterator = $entityFactory->createSheetIterator(
99            $this->filePointer,
100            $this->optionsManager,
101            $this->globalFunctionsHelper
102        );
103    }
104
105    /**
106     * Returns an iterator to iterate over sheets.
107     *
108     * @return SheetIterator To iterate over sheets
109     */
110    protected function getConcreteSheetIterator()
111    {
112        return $this->sheetIterator;
113    }
114
115    /**
116     * Closes the reader. To be used after reading the file.
117     *
118     * @return void
119     */
120    protected function closeReader()
121    {
122        if ($this->filePointer) {
123            $this->globalFunctionsHelper->fclose($this->filePointer);
124        }
125
126        ini_set('auto_detect_line_endings', $this->originalAutoDetectLineEndings);
127    }
128}
129