File: Data.php

package info (click to toggle)
horde3 3.1.3-4etch7
  • links: PTS
  • area: main
  • in suites: etch
  • size: 22,876 kB
  • ctags: 18,071
  • sloc: php: 75,151; xml: 2,979; sql: 1,069; makefile: 79; sh: 64
file content (403 lines) | stat: -rw-r--r-- 14,705 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
<?php

require_once 'PEAR.php';

// Import constants
/** Import already mapped csv data.        */ define('IMPORT_MAPPED', 1);
/** Map date and time entries of csv data. */ define('IMPORT_DATETIME', 2);
/** Import generic CSV data.               */ define('IMPORT_CSV', 3);
/** Import MS Outlook data.                */ define('IMPORT_OUTLOOK', 4);
/** Import vCalendar/iCalendar data.       */ define('IMPORT_ICALENDAR', 5);
/** Import vCards.                         */ define('IMPORT_VCARD', 6);
/** Import generic tsv data.               */ define('IMPORT_TSV', 7);
/** Import Mulberry address book data      */ define('IMPORT_MULBERRY', 8);
/** Import Pine address book data.         */ define('IMPORT_PINE', 9);
/** Import file.                           */ define('IMPORT_FILE', 11);
/** Import data.                           */ define('IMPORT_DATA', 12);

// Export constants
/** Export generic CSV data. */ define('EXPORT_CSV', 100);
/** Export iCalendar data.   */ define('EXPORT_ICALENDAR', 101);
/** Export vCards.           */ define('EXPORT_VCARD', 102);
/** Export TSV data.         */ define('EXPORT_TSV', 103);
/** Export Outlook CSV data. */ define('EXPORT_OUTLOOKCSV', 104);

/**
 * Abstract class to handle different kinds of Data formats and to
 * help data exchange between Horde applications and external sources.
 *
 * $Horde: framework/Data/Data.php,v 1.80.10.12 2006/08/08 17:15:22 jan Exp $
 *
 * Copyright 1999-2006 Jan Schneider <jan@horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Jan Schneider <jan@horde.org>
 * @author  Chuck Hagenbuch <chuck@horde.org>
 * @since   Horde 1.3
 * @package Horde_Data
 */
class Horde_Data extends PEAR {

    var $_extension;
    var $_contentType = 'text/plain';

    /**
     * A list of warnings raised during the last operation.
     *
     * @since Horde 3.1
     */
    var $_warnings = array();

    /**
     * Stub to import passed data.
     */
    function importData()
    {
    }

    /**
     * Stub to return exported data.
     */
    function exportData()
    {
    }

    /**
     * Stub to import a file.
     */
    function importFile($filename, $header = false)
    {
        $data = file_get_contents($filename);
        return $this->importData($data, $header);
    }

    /**
     * Stub to export data to a file.
     */
    function exportFile()
    {
    }

    /**
     * Tries to determine the expected newline character based on the
     * platform information passed by the browser's agent header.
     *
     * @return string  The guessed expected newline characters, either \n, \r
     *                 or \r\n.
     */
    function getNewline()
    {
        require_once 'Horde/Browser.php';
        $browser = &Browser::singleton();

        switch ($browser->getPlatform()) {
        case 'win':
            return "\r\n";

        case 'mac':
            return "\r";

        case 'unix':
        default:
            return "\n";
        }
    }

    function getFilename($basename)
    {
        return $basename . '.' . $this->_extension;
    }

    function getContentType()
    {
        return $this->_contentType;
    }

    /**
     * Returns a list of warnings that have been raised during the last
     * operation.
     *
     * @since Horde 3.1
     *
     * @return array  A (possibly empty) list of warnings.
     */
    function warnings()
    {
        return $this->_warnings;
    }

    /**
     * Attempts to return a concrete Horde_Data instance based on $format.
     *
     * @param mixed $format  The type of concrete Horde_Data subclass to
     *                       return. If $format is an array, then we will look
     *                       in $format[0]/lib/Data/ for the subclass
     *                       implementation named $format[1].php.
     *
     * @return Horde_Data  The newly created concrete Horde_Data instance, or
     *                     false on an error.
     */
    function &factory($format)
    {
        if (is_array($format)) {
            $app = $format[0];
            $format = $format[1];
        }

        $format = basename($format);

        if (empty($format) || (strcmp($format, 'none') == 0)) {
            $data =& new Horde_Data();
            return $data;
        }

        if (!empty($app)) {
            require_once $GLOBALS['registry']->get('fileroot', $app) . '/lib/Data/' . $format . '.php';
        } else {
            require_once 'Horde/Data/' . $format . '.php';
        }
        $class = 'Horde_Data_' . $format;
        if (class_exists($class)) {
            $data =& new $class();
        } else {
            $data = PEAR::raiseError('Class definition of ' . $class . ' not found.');
        }

        return $data;
    }

    /**
     * Attempts to return a reference to a concrete Horde_Data instance
     * based on $format. It will only create a new instance if no Horde_Data
     * instance with the same parameters currently exists.
     *
     * This should be used if multiple data sources (and, thus, multiple
     * Horde_Data instances) are required.
     *
     * This method must be invoked as: $var = &Horde_Data::singleton()
     *
     * @param string $format  The type of concrete Horde_Data subclass to
     *                        return.
     *
     * @return Horde_Data  The concrete Horde_Data reference, or false on an
     *                     error.
     */
    function &singleton($format)
    {
        static $instances;
        if (!isset($instances)) {
            $instances = array();
        }

        $signature = serialize($format);
        if (!isset($instances[$signature])) {
            $instances[$signature] = &Horde_Data::factory($format);
        }

        return $instances[$signature];
    }

    /**
     * Maps a date/time string to an associative array.
     *
     * The method signature has changed in Horde 3.1.3.
     *
     * @access private
     *
     * @param string $date   The date.
     * @param string $type   One of 'date', 'time' or 'datetime'.
     * @param array $params  Two-dimensional array with additional information
     *                       about the formatting. Possible keys are:<pre>
     *                       delimiter -- The character that seperates the
     *                                    different date/time parts.
     *                       format -- If 'ampm' and $date contains a time we
     *                                 assume that it is in AM/PM format.
     *                       order -- If $type is 'datetime' the order of the
     *                                day and time parts: -1 (timestamp), 0
     *                                (day/time), 1 (time/day).
     * @param integer $key   The key to use for $params.
     *
     * @return string  The date or time in ISO format.
     */
    function mapDate($date, $type, $params, $key)
    {
        switch ($type) {
        case 'date':
        case 'monthday':
        case 'monthdayyear':
            $dates = explode($params['delimiter'][$key], $date);
            if (count($dates) != 3) {
                return $date;
            }
            $index = array_flip(explode('/', $params['format'][$key]));
            return $dates[$index['year']] . '-' . $dates[$index['month']] . '-' . $dates[$index['mday']];

        case 'time':
            $dates = explode($params['delimiter'][$key], $date);
            if (count($dates) < 2 || count($dates) > 3) {
                return $date;
            }
            if ($params['format'][$key] == 'ampm') {
                if (strpos(strtolower($dates[count($dates)-1]), 'pm') !== false) {
                    if ($dates[0] !== '12') {
                        $dates[0] += 12;
                    }
                } elseif ($dates[0] == '12') {
                    $dates[0] = '0';
                }
                $dates[count($dates) - 1] = sprintf('%02d', $dates[count($dates)-1]);
            }
            return $dates[0] . ':' . $dates[1] . (count($dates) == 3 ? (':' . $dates[2]) : ':00');

        case 'datetime':
            switch ($params['order'][$key]) {
            case -1:
                return (string)(int)$date == $date
                    ? date('Y-m-d H:i:s', $date)
                    : $date;
            case 0:
                list($day, $time) = explode(' ', $date, 2);
                break;
            case 1:
               list($time, $day) = explode(' ', $date, 2);
               break;
            }
            $date = $this->mapDate($day, 'date',
                                   array('delimiter' => $params['day_delimiter'],
                                         'format' => $params['day_format']),
                                   $key);
            $time = $this->mapDate($time, 'time',
                                   array('delimiter' => $params['time_delimiter'],
                                         'format' => $params['time_format']),
                                   $key);
            return $date . ' ' . $time;

        }
    }

    /**
     * Takes all necessary actions for the given import step, parameters and
     * form values and returns the next necessary step.
     *
     * @param integer $action  The current step. One of the IMPORT_* constants.
     * @param array $param     An associative array containing needed
     *                         parameters for the current step.
     *
     * @return mixed  Either the next step as an integer constant or imported
     *                data set after the final step.
     */
    function nextStep($action, $param = array())
    {
        /* First step. */
        if (is_null($action)) {
            $_SESSION['import_data'] = array();
            return IMPORT_FILE;
        }

        switch ($action) {
        case IMPORT_FILE:
            /* Sanitize uploaded file. */
            $import_format = Util::getFormData('import_format');
            $check_upload = Browser::wasFileUploaded('import_file', $param['file_types'][$import_format]);
            if (is_a($check_upload, 'PEAR_Error')) {
                return $check_upload;
            }
            if ($_FILES['import_file']['size'] <= 0) {
                return PEAR::raiseError(_("The file contained no data."));
            }
            $_SESSION['import_data']['format'] = $import_format;
            break;

        case IMPORT_MAPPED:
            $dataKeys = Util::getFormData('dataKeys', '');
            $appKeys = Util::getFormData('appKeys', '');
            if (empty($dataKeys) || empty($appKeys)) {
                global $registry;
                return PEAR::raiseError(sprintf(_("You didn't map any fields from the imported file to the corresponding fields in %s."),
                                                $registry->get('name')));
            }
            $dataKeys = explode("\t", $dataKeys);
            $appKeys = explode("\t", $appKeys);
            $map = array();
            $dates = array();
            foreach ($appKeys as $key => $app) {
                $map[$dataKeys[$key]] = $app;
                if (isset($param['time_fields']) &&
                    isset($param['time_fields'][$app])) {
                    $dates[$dataKeys[$key]]['type'] = $param['time_fields'][$app];
                    $dates[$dataKeys[$key]]['values'] = array();
                    $i = 0;
                    /* Build an example array of up to 10 date/time fields. */
                    while ($i < count($_SESSION['import_data']['data']) && count($dates[$dataKeys[$key]]['values']) < 10) {
                        if (!empty($_SESSION['import_data']['data'][$i][$dataKeys[$key]])) {
                            $dates[$dataKeys[$key]]['values'][] = $_SESSION['import_data']['data'][$i][$dataKeys[$key]];
                        }
                        $i++;
                    }
                }
            }
            $_SESSION['import_data']['map'] = $map;
            if (count($dates) > 0) {
                $_SESSION['import_data']['dates'] = $dates;
                return IMPORT_DATETIME;
            }
            return $this->nextStep(IMPORT_DATA, $param);

        case IMPORT_DATETIME:
        case IMPORT_DATA:
            if ($action == IMPORT_DATETIME) {
                $params = array('delimiter' => Util::getFormData('delimiter'),
                                'format' => Util::getFormData('format'),
                                'order' => Util::getFormData('order'),
                                'day_delimiter' => Util::getFormData('day_delimiter'),
                                'day_format' => Util::getFormData('day_format'),
                                'time_delimiter' => Util::getFormData('time_delimiter'),
                                'time_format' => Util::getFormData('time_format'));
            }
            if (!isset($_SESSION['import_data']['data'])) {
                return PEAR::raiseError(_("The uploaded data was lost since the previous step."));
            }
            /* Build the result data set as an associative array. */
            $data = array();
            foreach ($_SESSION['import_data']['data'] as $row) {
                $data_row = array();
                foreach ($row as $key => $val) {
                    if (isset($_SESSION['import_data']['map'][$key])) {
                        $mapped_key = $_SESSION['import_data']['map'][$key];
                        if ($action == IMPORT_DATETIME &&
                            !empty($val) &&
                            isset($param['time_fields']) &&
                            isset($param['time_fields'][$mapped_key])) {
                            $val = $this->mapDate($val, $param['time_fields'][$mapped_key], $params, $key);
                        }
                        $data_row[$_SESSION['import_data']['map'][$key]] = $val;
                    }
                }
                $data[] = $data_row;
            }
            return $data;
        }
    }

    /**
     * Cleans the session data up and removes any uploaded and moved
     * files. If a function called "_cleanup()" exists, this gets
     * called too.
     *
     * @return mixed  If _cleanup() was called, the return value of this call.
     *                This should be the value of the first import step.
     */
    function cleanup()
    {
        if (isset($_SESSION['import_data']['file_name'])) {
            @unlink($_SESSION['import_data']['file_name']);
        }
        $_SESSION['import_data'] = array();
        if (function_exists('_cleanup')) {
            return _cleanup();
        }
    }

}