Overview

Packages

  • Data

Classes

  • Horde_Data
  • Horde_Data_Base
  • Horde_Data_Csv
  • Horde_Data_Exception
  • Horde_Data_Icalendar
  • Horde_Data_Imc
  • Horde_Data_Outlookcsv
  • Horde_Data_Translation
  • Horde_Data_Tsv
  • Horde_Data_Vcard
  • Horde_Data_Vnote
  • Horde_Data_Vtodo
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * @category Horde
  4:  * @package  Data
  5:  */
  6: 
  7: /**
  8:  * Horde_Data implementation for comma-separated data (CSV).
  9:  *
 10:  * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
 11:  *
 12:  * See the enclosed file COPYING for license information (LGPL). If you
 13:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 14:  *
 15:  * @author   Jan Schneider <jan@horde.org>
 16:  * @author   Chuck Hagenbuch <chuck@horde.org>
 17:  * @category Horde
 18:  * @package  Data
 19:  */
 20: class Horde_Data_Csv extends Horde_Data_Base
 21: {
 22:     /**
 23:      * Default charset.
 24:      *
 25:      * @var string
 26:      */
 27:     protected $_charset = null;
 28: 
 29:     /**
 30:      * MIME content type.
 31:      *
 32:      * @var string
 33:      */
 34:     protected $_contentType = 'application/csv';
 35: 
 36:     /**
 37:      * File extension.
 38:      *
 39:      * @var string
 40:      */
 41:     protected $_extension = 'csv';
 42: 
 43:     /**
 44:      * Constructor.
 45:      *
 46:      * @param array $params  Optional parameters:
 47:      * <pre>
 48:      * 'charset' - (string) The default charset.
 49:      *             DEFAULT: NONE
 50:      * </pre>
 51:      *
 52:      * @throws InvalidArgumentException
 53:      */
 54:     public function __construct(array $params = array())
 55:     {
 56:         if (isset($params['charset'])) {
 57:             $this->_charset = $params['charset'];
 58:             unset($params['charset']);
 59:         }
 60: 
 61:         parent::__construct($params);
 62:     }
 63: 
 64:     /**
 65:      * Imports and parses a CSV file.
 66:      *
 67:      * @param string $filename  The name of the file to parse.
 68:      * @param boolean $header   Does the first line contain the field/column
 69:      *                          names?
 70:      * @param string $sep       The field/column separator.
 71:      * @param string $quote     The quoting character.
 72:      * @param integer $fields   The number or fields/columns.
 73:      * @param string $charset   The file's charset.
 74:      * @param string $crlf      The file's linefeed characters.
 75:      *
 76:      * @return array  A two-dimensional array of all imported data rows.  If
 77:      *                $header was true the rows are associative arrays with the
 78:      *                field/column names as the keys.
 79:      * @throws Horde_Data_Exception
 80:      */
 81:     public function importFile($filename, $header = false, $sep = ',',
 82:                                $quote = '', $fields = null,
 83:                                $import_mapping = array(), $charset = null,
 84:                                $crlf = null)
 85:     {
 86:         if (empty($fields)) {
 87:             return array();
 88:         }
 89: 
 90:         $conf = array(
 91:             'length' => $fields,
 92:             'quote' => $quote,
 93:             'separator' => $sep
 94:         );
 95: 
 96:         $fp = @fopen($filename, 'r');
 97:         if (!$fp) {
 98:             throw new Horde_Data_Exception(Horde_Data_Translation::t("Cannot open file."));
 99:         }
100: 
101:         /* Strip and keep the first line if it contains the field names. */
102:         if ($header) {
103:             $head = Horde_Util::getCsv($fp, $conf);
104:             if (!$head) {
105:                 return array();
106:             }
107:             if (!empty($charset)) {
108:                 $head = Horde_String::convertCharset($head, $charset, $this->_charset);
109:             }
110:         }
111: 
112:         $data = array();
113:         while ($line = Horde_Util::getCsv($fp, $conf)) {
114:             if (!empty($charset)) {
115:                 $line = Horde_String::convertCharset($line, $charset, $this->_charset);
116:             }
117:             if (!isset($head)) {
118:                 $data[] = $line;
119:             } else {
120:                 $newline = array();
121:                 for ($i = 0; $i < count($head); $i++) {
122:                     if (isset($import_mapping[$head[$i]])) {
123:                         $head[$i] = $import_mapping[$head[$i]];
124:                     }
125:                     $cell = $line[$i];
126:                     $cell = preg_replace("/\"\"/", "\"", $cell);
127:                     $newline[$head[$i]] = empty($cell) ? '' : $cell;
128:                 }
129:                 $data[] = $newline;
130:             }
131:         }
132: 
133:         return $data;
134:     }
135: 
136:     /**
137:      * Builds a CSV file from a given data structure and returns it as a
138:      * string.
139:      *
140:      * @param array $data      A two-dimensional array containing the data set.
141:      * @param boolean $header  If true, the rows of $data are associative
142:      *                         arrays with field names as their keys.
143:      *
144:      * @return string  The CSV data.
145:      */
146:     public function exportData($data, $header = false,
147:                                $export_mapping = array())
148:     {
149:         if (!is_array($data) || count($data) == 0) {
150:             return '';
151:         }
152: 
153:         $export = '';
154:         $eol = "\n";
155:         $head = array_keys(current($data));
156:         if ($header) {
157:             foreach ($head as $key) {
158:                 if (!empty($key)) {
159:                     if (isset($export_mapping[$key])) {
160:                         $key = $export_mapping[$key];
161:                     }
162:                     $export .= '"' . str_replace('"', '\\"', $key) . '"';
163:                 }
164:                 $export .= ',';
165:             }
166:             $export = substr($export, 0, -1) . $eol;
167:         }
168: 
169:         foreach ($data as $row) {
170:             foreach ($head as $key) {
171:                 $cell = $row[$key];
172:                 if (!empty($cell) || $cell === 0) {
173:                     $export .= '"' . str_replace('"', '\\"', $cell) . '"';
174:                 }
175:                 $export .= ',';
176:             }
177:             $export = substr($export, 0, -1) . $eol;
178:         }
179: 
180:         return $export;
181:     }
182: 
183:     /**
184:      * Builds a CSV file from a given data structure and triggers its
185:      * download.  It DOES NOT exit the current script but only outputs the
186:      * correct headers and data.
187:      *
188:      * @param string $filename  The name of the file to be downloaded.
189:      * @param array $data       A two-dimensional array containing the data
190:      *                          set.
191:      * @param boolean $header   If true, the rows of $data are associative
192:      *                          arrays with field names as their keys.
193:      */
194:     public function exportFile($filename, $data, $header = false,
195:                                $export_mapping = array())
196:     {
197:         if (!isset($this->_browser)) {
198:             throw new LogicException('Missing browser parameter.');
199:         }
200: 
201:         $export = $this->exportData($data, $header, $export_mapping);
202:         $this->_browser->downloadHeaders($filename, 'application/csv', false, strlen($export));
203:         echo $export;
204:     }
205: 
206:     /**
207:      * Takes all necessary actions for the given import step, parameters and
208:      * form values and returns the next necessary step.
209:      *
210:      * @param integer $action  The current step. One of the IMPORT_* constants.
211:      * @param array $param     An associative array containing needed
212:      *                         parameters for the current step.
213:      *
214:      * @return mixed  Either the next step as an integer constant or imported
215:      *                data set after the final step.
216:      * @throws Horde_Data_Exception
217:      */
218:     public function nextStep($action, $param = array())
219:     {
220:         $session = $GLOBALS['injector']->getInstance('Horde_Session');
221: 
222:         switch ($action) {
223:         case Horde_Data::IMPORT_FILE:
224:             parent::nextStep($action, $param);
225: 
226:             /* Move uploaded file so that we can read it again in the next
227:                step after the user gave some format details. */
228:             $file_name = Horde_Util::getTempFile('import', false);
229:             if (!move_uploaded_file($_FILES['import_file']['tmp_name'], $file_name)) {
230:                 throw new Horde_Data_Exception(Horde_Data_Translation::t("The uploaded file could not be saved."));
231:             }
232:             $session->set('horde', 'import_data/file_name', $file_name);
233: 
234:             /* Check if charset was specified. */
235:             $session->set('horde', 'import_data/charset', $this->_vars->charset);
236: 
237:             /* Read the file's first two lines to show them to the user. */
238:             $first_lines = '';
239:             if ($fp = @fopen($file_name, 'r')) {
240:                 for ($line_no = 1, $line = fgets($fp);
241:                      $line_no <= 3 && $line;
242:                      $line_no++, $line = fgets($fp)) {
243:                     $line = Horde_String::convertCharset($line, $this->_vars->charset, $this->_charset);
244:                     $first_lines .= Horde_String::truncate($line);
245:                     if (Horde_String::length($line) > 100) {
246:                         $first_lines .= "\n";
247:                     }
248:                 }
249:             }
250:             $session->set('horde', 'import_data/first_lines', $first_lines);
251: 
252:             /* Import the first line to guess the number of fields. */
253:             if ($first_lines) {
254:                 rewind($fp);
255:                 $line = Horde_Util::getCsv($fp);
256:                 if ($line) {
257:                     $session->set('horde', 'import_data/fields', count($line));
258:                 }
259:             }
260: 
261:             return Horde_Data::IMPORT_CSV;
262: 
263:         case Horde_Data::IMPORT_CSV:
264:             $session->set('horde', 'import_data/header', $this->_vars->header);
265:             $import_mapping = array();
266:             if (isset($param['import_mapping'])) {
267:                 $import_mapping = $param['import_mapping'];
268:             }
269:             $session->set('horde', 'import_data/data', $this->importFile(
270:                 $session->get('horde', 'import_data/file_name'),
271:                 $this->_vars->header,
272:                 $this->_vars->sep,
273:                 $this->_vars->quote,
274:                 $this->_vars->fields,
275:                 $import_mapping,
276:                 $session->get('horde', 'import_data/charset'),
277:                 $session->get('horde', 'import_data/crlf')
278:             ));
279:             $session->remove('horde', 'import_data/map');
280:             return Horde_Data::IMPORT_MAPPED;
281: 
282:         default:
283:             return parent::nextStep($action, $param);
284:         }
285:     }
286: 
287: }
288: 
API documentation generated by ApiGen