937f80a8cbefcb2560aa071579c6c5c60a8d4e87
[core.git] / inc / main / classes / file_directories / text / input / csv / class_CsvInputFile.php
1 <?php
2 /**
3  * A CSV file input class for writing CSV files
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 class CsvInputFile extends BaseInputTextFile implements CsvInputStreamer {
25         /**
26          * Protected constructor
27          *
28          * @return      void
29          */
30         protected function __construct () {
31                 // Call parent constructor
32                 parent::__construct(__CLASS__);
33         }
34
35         /**
36          * Creates an instance of this File class and prepares it for usage
37          *
38          * @param       $fileName               Name of the index file
39          * @return      $fileInstance   An instance of this File class
40          */
41         public final static function createCsvInputFile ($fileName) {
42                 // Get a new instance
43                 $fileInstance = new CsvInputFile();
44
45                 // Set file name
46                 $fileInstance->setFileName($fileName);
47
48                 // Init this abstract file
49                 $fileInstance->initFile($fileName);
50
51                 // Return the prepared instance
52                 return $fileInstance;
53         }
54
55         /**
56          * Reads a line from CSV file and returns it as an indexed array. Please
57          * note that strings *must* be always in double-quotes, else any found
58          * column separators will be parsed or they may be interpreted incorrectly.
59          *
60          * @param       $columnSeparator        Character to use separting columns
61          * @return      $lineArray                      An indexed array with the read line
62          */
63         public function readCsvFileLine ($columnSeparator) {
64                 // Debug message
65                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] columnSeparator=%s - CALLED!', __METHOD__, __LINE__, $columnSeparator));
66
67                 // Read raw line
68                 $data = $this->getPointerInstance()->readLine();
69
70                 // Debug message
71                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] data()=%d', __METHOD__, __LINE__, strlen($data)));
72
73                 // Parse data
74                 $lineArray = $this->parseDataToIndexedArray($data, $columnSeparator);
75
76                 // Debug message
77                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - EXIT!', __METHOD__, __LINE__, count($lineArray)));
78
79                 // Return it
80                 return $lineArray;
81         }
82
83         /**
84          * Parses given data into an array
85          *
86          * @param       $data                           Raw data e.g. returned from readLine()
87          * @param       $columnSeparator        Character to use separting columns
88          * @return      $lineArray                      An indexed array with the read line
89          */
90         private function parseDataToIndexedArray ($data, $columnSeparator) {
91                 // Debug message
92                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] data()=%d,columnSeparator=%s - CALLED!', __METHOD__, __LINE__, strlen($data), $columnSeparator));
93
94                 // Init return array
95                 $lineArray = array();
96
97                 // Whether the parser reads a quoted string (which may contain the column separator again)
98                 $isInQuotes = FALSE;
99
100                 // Init column data
101                 $column = '';
102
103                 // Now parse the line
104                 for ($idx = 0; $idx < strlen($data); $idx++) {
105                         // "Cache" char
106                         $char = substr($data, $idx, 1);
107
108                         // Debug message
109                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] idx=%s,char=%s ...', __METHOD__, __LINE__, $idx, $char));
110
111                         // Is the column separator found and not within quotes?
112                         if (($isInQuotes === FALSE) && ($char == $columnSeparator)) {
113                                 // Debug message
114                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Adding column=%s ...', __METHOD__, __LINE__, $column));
115
116                                 // Add this line to the array
117                                 array_push($lineArray, $column);
118
119                                 // Debug message
120                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - After add!', __METHOD__, __LINE__, count($lineArray)));
121
122                                 // Clear variable ...
123                                 $column = '';
124
125                                 // ... and skip it
126                                 continue;
127                         } elseif ($char == chr(34)) {
128                                 // Debug message
129                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] column=%s ...', __METHOD__, __LINE__, $column));
130
131                                 // $column must be empty at this point if we are at starting quote
132                                 assert(($isInQuotes === TRUE) || (empty($column)));
133
134                                 // Double-quote found, so flip variable
135                                 $isInQuotes = (!$isInQuotes);
136
137                                 // Debug message
138                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInQuotes=%d ...', __METHOD__, __LINE__, intval($isInQuotes)));
139
140                                 // Skip double-quote (escaping of them is not yet supported)
141                                 continue;
142                         }
143
144                         // Debug message
145                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Adding char=%s ...', __METHOD__, __LINE__, $idx, $char));
146
147                         // Add char to column
148                         $column .= $char;
149                 } // END - for
150
151                 // Is there something outstanding?
152                 if (!empty($column)) {
153                         // Debug message
154                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Adding column=%s ...', __METHOD__, __LINE__, $column));
155
156                         // Then don't forget this. :-)
157                         array_push($lineArray, $column);
158
159                         // Debug message
160                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - After add!', __METHOD__, __LINE__, count($lineArray)));
161                 } // END - if
162
163                 // Debug message
164                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - EXIT!', __METHOD__, __LINE__, count($lineArray)));
165
166                 // Return it
167                 return $lineArray;
168         }
169 }
170
171 // [EOF]
172 ?>