return new $class($params);
}
- throw new Horde_Data_Exception('Driver not found: ' . $driver);
+ throw new Horde_Data_Exception('Driver not found: ' . $class);
}
}
--- /dev/null
+<?php
+/**
+ * Abstract class that Data drivers extend.
+ *
+ * Copyright 1999-2010 The Horde Project (http://www.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>
+ * @category Horde
+ * @package Data
+ */
+abstract class Horde_Data_Base
+{
+ /**
+ * Browser object.
+ *
+ * @var Horde_Browser
+ */
+ protected $_browser;
+
+ /**
+ * File extension.
+ *
+ * @var string
+ */
+ protected $_extension = '';
+
+ /**
+ * MIME content type.
+ *
+ * @var string
+ */
+ protected $_contentType = 'text/plain';
+
+ /**
+ * Cleanup callback function.
+ *
+ * @var callback
+ */
+ protected $_cleanupCallback;
+
+ /**
+ * Variables object.
+ *
+ * @var Horde_Variables
+ */
+ protected $_vars;
+
+ /**
+ * A list of warnings raised during the last operation.
+ *
+ * @var array
+ */
+ protected $_warnings = array();
+
+ /**
+ * Constructor.
+ *
+ * @param array $params Optional parameters:
+ * <pre>
+ * 'browser' - (Horde_Browser) A Horde_Browser object.
+ * 'cleanup' - (callback) A callback to call at cleanup time.
+ * </pre>
+ *
+ * @throws Horde_Data_Exception
+ */
+ public function __construct(array $params = array())
+ {
+ if (!isset($params['browser'])) {
+ throw new Horde_Data_Exception('Missing browser parameter.');
+ }
+ $this->_browser = $params['browser'];
+
+ if (isset($params['cleanup']) &&
+ is_callable($params['cleanup'])) {
+ $this->_cleanupCallback = $params['cleanup'];
+ }
+
+ $this->_vars = isset($params['vars'])
+ ? $params['vars']
+ : Horde_Variables::getDefaultVariables();
+ }
+
+ /**
+ * Stub to import passed data.
+ */
+ public function importData($text)
+ {
+ }
+
+ /**
+ * Stub to return exported data.
+ */
+ abstract public function exportData($data, $method = 'REQUEST');
+
+ /**
+ * Stub to import a file.
+ */
+ public function importFile($filename, $header = false)
+ {
+ $data = file_get_contents($filename);
+ return $this->importData($data, $header);
+ }
+
+ /**
+ * Stub to export data to a file.
+ */
+ abstract public function exportFile($filename, $data);
+
+ /**
+ * 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.
+ */
+ public function getNewline()
+ {
+ switch ($this->_browser->getPlatform()) {
+ case 'win':
+ return "\r\n";
+
+ case 'mac':
+ return "\r";
+
+ case 'unix':
+ default:
+ return "\n";
+ }
+ }
+
+ /**
+ * Returns the full filename including the basename and extension.
+ *
+ * @param string $basename Basename for the file.
+ *
+ * @return string The file name.
+ */
+ public function getFilename($basename)
+ {
+ return $basename . '.' . $this->_extension;
+ }
+
+ /**
+ * Returns the content type.
+ *
+ * @return string The content type.
+ */
+ public function getContentType()
+ {
+ return $this->_contentType;
+ }
+
+ /**
+ * Returns a list of warnings that have been raised during the last
+ * operation.
+ *
+ * @return array A (possibly empty) list of warnings.
+ */
+ public function warnings()
+ {
+ return $this->_warnings;
+ }
+
+ /**
+ * Maps a date/time string to an associative array.
+ *
+ * @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:
+ * - 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.
+ */
+ protected 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.
+ * @throws Horde_Data_Exception
+ */
+ public function nextStep($action, $param = array())
+ {
+ /* First step. */
+ if (is_null($action)) {
+ $_SESSION['import_data'] = array();
+ return Horde_Data::IMPORT_FILE;
+ }
+
+ switch ($action) {
+ case Horde_Data::IMPORT_FILE:
+ /* Sanitize uploaded file. */
+ try {
+ $this->_browser->wasFileUploaded('import_file', $param['file_types'][$this->_vars->import_format]);
+ } catch (Horde_Exception $e) {
+ throw new Horde_Data_Exception($e);
+ }
+ if ($_FILES['import_file']['size'] <= 0) {
+ return PEAR::raiseError(_("The file contained no data."));
+ }
+ $_SESSION['import_data']['format'] = $this->_vars->import_format;
+ break;
+
+ case Horde_Data::IMPORT_MAPPED:
+ if (!$this->_vars->dataKeys || !$this->_vars->appKeys) {
+ throw new Horde_Data_Exception('You didn\'t map any fields from the imported file to the corresponding fields.');
+ }
+ $dataKeys = explode("\t", $this->_vars->dataKeys);
+ $appKeys = explode("\t", $this->_vars->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) {
+ foreach ($dates as $key => $data) {
+ if (count($data['values'])) {
+ $_SESSION['import_data']['dates'] = $dates;
+ return Horde_Data::IMPORT_DATETIME;
+ }
+ }
+ }
+ return $this->nextStep(Horde_Data::IMPORT_DATA, $param);
+
+ case Horde_Data::IMPORT_DATETIME:
+ case Horde_Data::IMPORT_DATA:
+ if ($action == Horde_Data::IMPORT_DATETIME) {
+ $params = array(
+ 'delimiter' => $this->_vars->delimiter,
+ 'format' => $this->_vars->format,
+ 'order' => $this->_vars->order,
+ 'day_delimiter' => $this->_vars->day_delimiter,
+ 'day_format' => $this->_vars->day_format,
+ 'time_delimiter' => $this->_vars->time_delimiter,
+ 'time_format' => $this->_vars->time_format
+ );
+ }
+
+ if (!isset($_SESSION['import_data']['data'])) {
+ throw new Horde_Data_Exception('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 == Horde_Data::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.
+ *
+ * @return mixed If callback called, the return value of this call.
+ * This should be the value of the first import step.
+ */
+ public function cleanup()
+ {
+ if (isset($_SESSION['import_data']['file_name'])) {
+ @unlink($_SESSION['import_data']['file_name']);
+ }
+ $_SESSION['import_data'] = array();
+
+ if ($this->_cleanupCallback) {
+ return call_user_func($this->_cleanupCallback);
+ }
+ }
+
+}
* @category Horde
* @package Data
*/
-class Horde_Data_Csv extends Horde_Data_Driver
+class Horde_Data_Csv extends Horde_Data_Base
{
/**
* File extension.
* @return array A two-dimensional array of all imported data rows. If
* $header was true the rows are associative arrays with the
* field/column names as the keys.
- *@throws Horde_File_Csv_Exception
+ * @throws Horde_File_Csv_Exception
*/
public function importFile($filename, $header = false, $sep = ',',
$quote = '', $fields = null,
+++ /dev/null
-<?php
-/**
- * Abstract class that Data drivers extend.
- *
- * Copyright 1999-2010 The Horde Project (http://www.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>
- * @category Horde
- * @package Data
- */
-abstract class Horde_Data
-{
- /**
- * Browser object.
- *
- * @var Horde_Browser
- */
- protected $_browser;
-
- /**
- * File extension.
- *
- * @var string
- */
- protected $_extension = '';
-
- /**
- * MIME content type.
- *
- * @var string
- */
- protected $_contentType = 'text/plain';
-
- /**
- * Cleanup callback function.
- *
- * @var callback
- */
- protected $_cleanupCallback;
-
- /**
- * Variables object.
- *
- * @var Horde_Variables
- */
- protected $_vars;
-
- /**
- * A list of warnings raised during the last operation.
- *
- * @var array
- */
- protected $_warnings = array();
-
- /**
- * Constructor.
- *
- * @param array $params Optional parameters:
- * <pre>
- * 'browser' - (Horde_Browser) A Horde_Browser object.
- * 'cleanup' - (callback) A callback to call at cleanup time.
- * </pre>
- *
- * @throws Horde_Data_Exception
- */
- public function __construct(array $params = array())
- {
- if (!isset($params['browser'])) {
- throw new Horde_Data_Exception('Missing browser parameter.');
- }
- $this->_browser = $params['browser'];
-
- if (isset($params['cleanup']) &&
- is_callable($params['cleanup'])) {
- $this->_cleanupCallback = $params['cleanup'];
- }
-
- $this->_vars = isset($params['vars'])
- ? $params['vars']
- : Horde_Variables::getDefaultVariables();
- }
-
- /**
- * Stub to import passed data.
- */
- abstract public function importData();
-
- /**
- * Stub to return exported data.
- */
- abstract public function exportData();
-
- /**
- * Stub to import a file.
- */
- public function importFile($filename, $header = false)
- {
- $data = file_get_contents($filename);
- return $this->importData($data, $header);
- }
-
- /**
- * Stub to export data to a file.
- */
- abstract public 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.
- */
- public function getNewline()
- {
- switch ($this->_browser->getPlatform()) {
- case 'win':
- return "\r\n";
-
- case 'mac':
- return "\r";
-
- case 'unix':
- default:
- return "\n";
- }
- }
-
- /**
- * Returns the full filename including the basename and extension.
- *
- * @param string $basename Basename for the file.
- *
- * @return string The file name.
- */
- public function getFilename($basename)
- {
- return $basename . '.' . $this->_extension;
- }
-
- /**
- * Returns the content type.
- *
- * @return string The content type.
- */
- public function getContentType()
- {
- return $this->_contentType;
- }
-
- /**
- * Returns a list of warnings that have been raised during the last
- * operation.
- *
- * @return array A (possibly empty) list of warnings.
- */
- public function warnings()
- {
- return $this->_warnings;
- }
-
- /**
- * Maps a date/time string to an associative array.
- *
- * @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:
- * - 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.
- */
- protected 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.
- * @throws Horde_Data_Exception
- */
- public function nextStep($action, $param = array())
- {
- /* First step. */
- if (is_null($action)) {
- $_SESSION['import_data'] = array();
- return Horde_Data::IMPORT_FILE;
- }
-
- switch ($action) {
- case Horde_Data::IMPORT_FILE:
- /* Sanitize uploaded file. */
- try {
- $this->_browser->wasFileUploaded('import_file', $param['file_types'][$this->_vars->import_format]);
- } catch (Horde_Exception $e) {
- throw new Horde_Data_Exception($e);
- }
- if ($_FILES['import_file']['size'] <= 0) {
- return PEAR::raiseError(_("The file contained no data."));
- }
- $_SESSION['import_data']['format'] = $this->_vars->import_format;
- break;
-
- case Horde_Data::IMPORT_MAPPED:
- if (!$this->_vars->dataKeys || !$this->_vars->appKeys) {
- throw new Horde_Data_Exception('You didn\'t map any fields from the imported file to the corresponding fields.');
- }
- $dataKeys = explode("\t", $this->_vars->dataKeys);
- $appKeys = explode("\t", $this->_vars->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) {
- foreach ($dates as $key => $data) {
- if (count($data['values'])) {
- $_SESSION['import_data']['dates'] = $dates;
- return Horde_Data::IMPORT_DATETIME;
- }
- }
- }
- return $this->nextStep(Horde_Data::IMPORT_DATA, $param);
-
- case Horde_Data::IMPORT_DATETIME:
- case Horde_Data::IMPORT_DATA:
- if ($action == Horde_Data::IMPORT_DATETIME) {
- $params = array(
- 'delimiter' => $this->_vars->delimiter,
- 'format' => $this->_vars->format,
- 'order' => $this->_vars->order,
- 'day_delimiter' => $this->_vars->day_delimiter,
- 'day_format' => $this->_vars->day_format,
- 'time_delimiter' => $this->_vars->time_delimiter,
- 'time_format' => $this->_vars->time_format
- );
- }
-
- if (!isset($_SESSION['import_data']['data'])) {
- throw new Horde_Data_Exception('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 == Horde_Data::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.
- *
- * @return mixed If callback called, the return value of this call.
- * This should be the value of the first import step.
- */
- public function cleanup()
- {
- if (isset($_SESSION['import_data']['file_name'])) {
- @unlink($_SESSION['import_data']['file_name']);
- }
- $_SESSION['import_data'] = array();
-
- if ($this->_cleanupCallback) {
- return call_user_func($this->_cleanupCallback);
- }
- }
-
-}
* @category Horde
* @package Data
*/
-class Horde_Data_Imc extends Horde_Data_Driver
+class Horde_Data_Imc extends Horde_Data_Base
{
/**
* @var
* @category Horde
* @package Data
*/
-class Horde_Data_Tsv extends Horde_Data_Driver
+class Horde_Data_Tsv extends Horde_Data_Base
{
/**
* File extension.
<dir name="lib">
<dir name="Horde">
<dir name="Data">
+ <file name="Base.php" role="php" />
<file name="Csv.php" role="php" />
- <file name="Driver.php" role="php" />
<file name="Exception.php" role="php" />
<file name="Icalendar.php" role="php" />
<file name="Imc.php" role="php" />
</dependencies>
<phprelease>
<filelist>
+ <install name="lib/Horde/Data/Base.php" as="Horde/Data/Base.php" />
<install name="lib/Horde/Data/Csv.php" as="Horde/Data/Csv.php" />
- <install name="lib/Horde/Data/Driver.php" as="Horde/Data/Driver.php" />
<install name="lib/Horde/Data/Exception.php" as="Horde/Data/Exception.php" />
<install name="lib/Horde/Data/Icalendar.php" as="Horde/Data/Icalendar.php" />
<install name="lib/Horde/Data/Imc.php" as="Horde/Data/Imc.php" />
exit;
case 'ldif':
- // TODO
- //$injector->getInstance('Horde_Data')->getData('Csv', array('cleanup' => '_cleanupData'))
- $ldif = Horde_Data::singleton(array('turba', 'ldif'));
+ $ldif = new Turba_Data_Ldif(
+ array('browser' => $this->_injector->getInstance('Horde_Browser'),
+ 'vars' => Horde_Variables::getDefaultVariables(),
+ 'cleanup' => '_cleanupData'));
$ldif->exportFile(_("contacts.ldif"), $data, true);
exit;
}
if (!$error && !empty($import_format)) {
// TODO
if ($import_format == 'ldif') {
- $data = Horde_Data::singleton(array('turba', $import_format));
+ $data = new Turba_Data_Ldif(
+ array('browser' => $this->_injector->getInstance('Horde_Browser'),
+ 'vars' => Horde_Variables::getDefaultVariables(),
+ 'cleanup' => '_cleanupData'));
} else {
- $data = Horde_Data::singleton($import_format);
+ $data = $injector->getInstance('Horde_Data')->getData($import_format, array('cleanup' => '_cleanupData'));
}
if ($data instanceof PEAR_Error) {
$notification->push(_("This file format is not supported."), 'horde.error');
--- /dev/null
+<?php
+/**
+ * Horde_Data implementation for LDAP Data Interchange Format (LDIF).
+ *
+ * Copyright 2007-2010 The Horde Project (http://www.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 Rita Selsky <ritaselsky@gmail.com>
+ * @package Horde_Data
+ */
+class Turba_Data_Ldif extends Horde_Data
+{
+ var $_extension = 'ldif';
+
+ var $_contentType = 'text/ldif';
+
+ /**
+ * Useful Mozilla address book attribute names.
+ *
+ * @private
+ * @var array
+ */
+ var $_mozillaAttr = array('cn', 'givenName', 'sn', 'mail', 'mozillaNickname',
+ 'homeStreet', 'mozillaHomeStreet2', 'mozillaHomeLocalityName',
+ 'mozillaHomeState', 'mozillaHomePostalCode',
+ 'mozillaHomeCountryName', 'street',
+ 'mozillaWorkStreet2', 'l', 'st', 'postalCode',
+ 'c', 'homePhone', 'telephoneNumber', 'mobile',
+ 'fax', 'title', 'company', 'description', 'mozillaWorkUrl',
+ 'department', 'mozillaNickname');
+
+ /**
+ * Useful Turba address book attribute names.
+ *
+ * @private
+ * @var array
+ */
+ var $_turbaAttr = array('name', 'firstname', 'lastname', 'email', 'alias',
+ 'homeAddress', 'homeStreet', 'homeCity',
+ 'homeProvince', 'homePostalCode', 'homeCountry',
+ 'workAddress', 'workStreet', 'workCity', 'workProvince',
+ 'workPostalCode', 'workCountry',
+ 'homePhone', 'workPhone', 'cellPhone',
+ 'fax', 'title', 'company', 'notes', 'website',
+ 'department', 'nickname');
+ /**
+ * Turba address book attribute names and the corresponding Mozilla name.
+ *
+ * @private
+ * @var array
+ */
+ var $_turbaMozillaMap = array('name' => 'cn',
+ 'firstname' => 'givenName',
+ 'lastname' => 'sn',
+ 'email' => 'mail',
+ 'alias' => 'mozillaNickname',
+ 'homePhone' => 'homePhone',
+ 'workPhone' => 'telephoneNumber',
+ 'cellPhone' => 'mobile',
+ 'fax' => 'fax',
+ 'title' => 'title',
+ 'company' => 'company',
+ 'notes' => 'description',
+ 'homeAddress' => 'homeStreet',
+ 'homeStreet' => 'mozillaHomeStreet2',
+ 'homeCity' => 'mozillaHomeLocalityName',
+ 'homeProvince' => 'mozillaHomeState',
+ 'homePostalCode' => 'mozillaHomePostalCode',
+ 'homeCountry' => 'mozillaHomeCountryName',
+ 'workAddress' => 'street',
+ 'workStreet' => 'mozillaWorkStreet2',
+ 'workCity' => 'l',
+ 'workProvince' => 'st',
+ 'workPostalCode' => 'postalCode',
+ 'workCountry' => 'c',
+ 'website' => 'mozillaWorkUrl',
+ 'department' => 'department',
+ 'nickname' => 'mozillaNickname');
+
+ /**
+ * Check if a string is safe according to RFC 2849, or if it needs to be
+ * base64 encoded.
+ *
+ * @private
+ *
+ * @param string $str The string to check.
+ *
+ * @return boolean True if the string is safe, false otherwise.
+ */
+ function _is_safe_string($str)
+ {
+ /* SAFE-CHAR = %x01-09 / %x0B-0C / %x0E-7F
+ * ; any value <= 127 decimal except NUL, LF,
+ * ; and CR
+ *
+ * SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F /
+ * %x21-39 / %x3B / %x3D-7F
+ * ; any value <= 127 except NUL, LF, CR,
+ * ; SPACE, colon (":", ASCII 58 decimal)
+ * ; and less-than ("<" , ASCII 60 decimal) */
+ if (!strlen($str)) {
+ return true;
+ }
+ if ($str[0] == ' ' || $str[0] == ':' || $str[0] == '<') {
+ return false;
+ }
+ for ($i = 0; $i < strlen($str); ++$i) {
+ if (ord($str[$i]) > 127 || $str[$i] == NULL || $str[$i] == "\n" ||
+ $str[$i] == "\r") {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ function importData($contents, $header = false)
+ {
+ $data = array();
+ $records = preg_split('/(\r?\n){2}/', $contents);
+ foreach ($records as $record) {
+ if (trim($record) == '') {
+ /* Ignore empty records */
+ continue;
+ }
+ /* one key:value pair per line */
+ $lines = preg_split('/\r?\n/', $record);
+ $hash = array();
+ foreach ($lines as $line) {
+ list($key, $delimiter, $value) = preg_split('/(:[:<]?) */', $line, 2, PREG_SPLIT_DELIM_CAPTURE);
+ if (in_array($key, $this->_mozillaAttr)) {
+ $hash[$key] = ($delimiter == '::' ? base64_decode($value) : $value);
+ }
+ }
+ $data[] = $hash;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Builds a LDIF file from a given data structure and triggers its download.
+ * It DOES NOT exit the current script but only outputs the correct headers
+ * and data.
+ *
+ * @param string $filename The name of the file to be downloaded.
+ * @param array $data A two-dimensional array containing the data
+ * set.
+ * @param boolean $header If true, the rows of $data are associative
+ * arrays with field names as their keys.
+ */
+ function exportFile($filename, $data, $header = false)
+ {
+ $export = $this->exportData($data, $header);
+ $GLOBALS['browser']->downloadHeaders($filename, 'text/ldif', false, strlen($export));
+ echo $export;
+ }
+
+ /**
+ * Builds a LDIF file from a given data structure and returns it as a
+ * string.
+ *
+ * @param array $data A two-dimensional array containing the data set.
+ * @param boolean $header If true, the rows of $data are associative
+ * arrays with field names as their keys.
+ *
+ * @return string The LDIF data.
+ */
+ function exportData($data, $header = false)
+ {
+ if (!is_array($data) || !count($data)) {
+ return '';
+ }
+ $export = '';
+ $mozillaTurbaMap = array_flip($this->_turbaMozillaMap) ;
+ foreach ($data as $row) {
+ $recordData = '';
+ foreach ($this->_mozillaAttr as $value) {
+ if (isset($row[$mozillaTurbaMap[$value]])) {
+ // Base64 encode each value as necessary and store it.
+ // Store cn and mail separately for use in record dn
+ if (!$this->_is_safe_string($row[$mozillaTurbaMap[$value]])) {
+ $recordData .= $value . ':: ' . base64_encode($row[$mozillaTurbaMap[$value]]) . "\n";
+ } else {
+ $recordData .= $value . ': ' . $row[$mozillaTurbaMap[$value]] . "\n";
+ }
+ }
+ }
+
+ $dn = 'cn=' . $row[$mozillaTurbaMap['cn']] . ',mail=' . $row[$mozillaTurbaMap['mail']];
+ if (!$this->_is_safe_string($dn)) {
+ $export .= 'dn:: ' . base64_encode($dn) . "\n";
+ } else {
+ $export .= 'dn: ' . $dn . "\n";
+ }
+
+ $export .= "objectclass: top\n"
+ . "objectclass: person\n"
+ . "objectclass: organizationalPerson\n"
+ . "objectclass: inetOrgPerson\n"
+ . "objectclass: mozillaAbPersonAlpha\n"
+ . $recordData . "modifytimestamp: 0Z\n\n";
+ }
+
+ return $export;
+ }
+
+ /**
+ * 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())
+ {
+ switch ($action) {
+ case Horde_Data::IMPORT_FILE:
+ $next_step = parent::nextStep($action, $param);
+ if (is_a($next_step, 'PEAR_Error')) {
+ return $next_step;
+ }
+
+ $_SESSION['import_data']['data'] = $this->importFile($_FILES['import_file']['tmp_name']);
+ $data = array();
+ foreach ($_SESSION['import_data']['data'] as $record) {
+ $turbaHash = array();
+ foreach ($this->_turbaAttr as $value) {
+ switch ($value) {
+ case 'homeAddress':
+ // These are the keys we're interested in.
+ $keys = array('homeStreet', 'mozillaHomeStreet2',
+ 'mozillaHomeLocalityName', 'mozillaHomeState',
+ 'mozillaHomePostalCode', 'mozillaHomeCountryName');
+
+ // Grab all of them that exist in $record.
+ $values = array_intersect_key($record, array_flip($keys));
+
+ // Special handling for State if both State
+ // and Locality Name are set.
+ if (isset($values['mozillaHomeLocalityName'])
+ && isset($values['mozillaHomeState'])) {
+ $values['mozillaHomeLocalityName'] .= ', ' . $values['mozillaHomeState'];
+ unset($values['mozillaHomeState']);
+ }
+
+ if ($values) {
+ $turbaHash[$value] = implode("\n", $values);
+ }
+ break;
+
+ case 'workAddress':
+ // These are the keys we're interested in.
+ $keys = array('street', 'mozillaWorkStreet2', 'l',
+ 'st', 'postalCode', 'c');
+
+ // Grab all of them that exist in $record.
+ $values = array_intersect_key($record, array_flip($keys));
+
+ // Special handling for "st" if both "st" and
+ // "l" are set.
+ if (isset($values['l']) && isset($values['st'])) {
+ $values['l'] .= ', ' . $values['st'];
+ unset($values['st']);
+ }
+
+ if ($values) {
+ $turbaHash[$value] = implode("\n", $values);
+ }
+ break;
+
+ default:
+ if (isset($record[$this->_turbaMozillaMap[$value]])) {
+ $turbaHash[$value] = $record[$this->_turbaMozillaMap[$value]];
+ }
+ break;
+ }
+ }
+
+ $data[] = $turbaHash;
+ }
+
+ unset($_SESSION['import_data']['data']);
+ return $data;
+
+ default:
+ return parent::nextStep($action, $param);
+ }
+ }
+
+}
+++ /dev/null
-<?php
-/**
- * Horde_Data implementation for LDAP Data Interchange Format (LDIF).
- *
- * Copyright 2007-2010 The Horde Project (http://www.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 Rita Selsky <ritaselsky@gmail.com>
- * @package Horde_Data
- */
-class Horde_Data_Ldif extends Horde_Data
-{
- var $_extension = 'ldif';
-
- var $_contentType = 'text/ldif';
-
- /**
- * Useful Mozilla address book attribute names.
- *
- * @private
- * @var array
- */
- var $_mozillaAttr = array('cn', 'givenName', 'sn', 'mail', 'mozillaNickname',
- 'homeStreet', 'mozillaHomeStreet2', 'mozillaHomeLocalityName',
- 'mozillaHomeState', 'mozillaHomePostalCode',
- 'mozillaHomeCountryName', 'street',
- 'mozillaWorkStreet2', 'l', 'st', 'postalCode',
- 'c', 'homePhone', 'telephoneNumber', 'mobile',
- 'fax', 'title', 'company', 'description', 'mozillaWorkUrl',
- 'department', 'mozillaNickname');
-
- /**
- * Useful Turba address book attribute names.
- *
- * @private
- * @var array
- */
- var $_turbaAttr = array('name', 'firstname', 'lastname', 'email', 'alias',
- 'homeAddress', 'homeStreet', 'homeCity',
- 'homeProvince', 'homePostalCode', 'homeCountry',
- 'workAddress', 'workStreet', 'workCity', 'workProvince',
- 'workPostalCode', 'workCountry',
- 'homePhone', 'workPhone', 'cellPhone',
- 'fax', 'title', 'company', 'notes', 'website',
- 'department', 'nickname');
- /**
- * Turba address book attribute names and the corresponding Mozilla name.
- *
- * @private
- * @var array
- */
- var $_turbaMozillaMap = array('name' => 'cn',
- 'firstname' => 'givenName',
- 'lastname' => 'sn',
- 'email' => 'mail',
- 'alias' => 'mozillaNickname',
- 'homePhone' => 'homePhone',
- 'workPhone' => 'telephoneNumber',
- 'cellPhone' => 'mobile',
- 'fax' => 'fax',
- 'title' => 'title',
- 'company' => 'company',
- 'notes' => 'description',
- 'homeAddress' => 'homeStreet',
- 'homeStreet' => 'mozillaHomeStreet2',
- 'homeCity' => 'mozillaHomeLocalityName',
- 'homeProvince' => 'mozillaHomeState',
- 'homePostalCode' => 'mozillaHomePostalCode',
- 'homeCountry' => 'mozillaHomeCountryName',
- 'workAddress' => 'street',
- 'workStreet' => 'mozillaWorkStreet2',
- 'workCity' => 'l',
- 'workProvince' => 'st',
- 'workPostalCode' => 'postalCode',
- 'workCountry' => 'c',
- 'website' => 'mozillaWorkUrl',
- 'department' => 'department',
- 'nickname' => 'mozillaNickname');
-
- /**
- * Check if a string is safe according to RFC 2849, or if it needs to be
- * base64 encoded.
- *
- * @private
- *
- * @param string $str The string to check.
- *
- * @return boolean True if the string is safe, false otherwise.
- */
- function _is_safe_string($str)
- {
- /* SAFE-CHAR = %x01-09 / %x0B-0C / %x0E-7F
- * ; any value <= 127 decimal except NUL, LF,
- * ; and CR
- *
- * SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F /
- * %x21-39 / %x3B / %x3D-7F
- * ; any value <= 127 except NUL, LF, CR,
- * ; SPACE, colon (":", ASCII 58 decimal)
- * ; and less-than ("<" , ASCII 60 decimal) */
- if (!strlen($str)) {
- return true;
- }
- if ($str[0] == ' ' || $str[0] == ':' || $str[0] == '<') {
- return false;
- }
- for ($i = 0; $i < strlen($str); ++$i) {
- if (ord($str[$i]) > 127 || $str[$i] == NULL || $str[$i] == "\n" ||
- $str[$i] == "\r") {
- return false;
- }
- }
-
- return true;
- }
-
- function importData($contents, $header = false)
- {
- $data = array();
- $records = preg_split('/(\r?\n){2}/', $contents);
- foreach ($records as $record) {
- if (trim($record) == '') {
- /* Ignore empty records */
- continue;
- }
- /* one key:value pair per line */
- $lines = preg_split('/\r?\n/', $record);
- $hash = array();
- foreach ($lines as $line) {
- list($key, $delimiter, $value) = preg_split('/(:[:<]?) */', $line, 2, PREG_SPLIT_DELIM_CAPTURE);
- if (in_array($key, $this->_mozillaAttr)) {
- $hash[$key] = ($delimiter == '::' ? base64_decode($value) : $value);
- }
- }
- $data[] = $hash;
- }
-
- return $data;
- }
-
- /**
- * Builds a LDIF file from a given data structure and triggers its download.
- * It DOES NOT exit the current script but only outputs the correct headers
- * and data.
- *
- * @param string $filename The name of the file to be downloaded.
- * @param array $data A two-dimensional array containing the data
- * set.
- * @param boolean $header If true, the rows of $data are associative
- * arrays with field names as their keys.
- */
- function exportFile($filename, $data, $header = false)
- {
- $export = $this->exportData($data, $header);
- $GLOBALS['browser']->downloadHeaders($filename, 'text/ldif', false, strlen($export));
- echo $export;
- }
-
- /**
- * Builds a LDIF file from a given data structure and returns it as a
- * string.
- *
- * @param array $data A two-dimensional array containing the data set.
- * @param boolean $header If true, the rows of $data are associative
- * arrays with field names as their keys.
- *
- * @return string The LDIF data.
- */
- function exportData($data, $header = false)
- {
- if (!is_array($data) || !count($data)) {
- return '';
- }
- $export = '';
- $mozillaTurbaMap = array_flip($this->_turbaMozillaMap) ;
- foreach ($data as $row) {
- $recordData = '';
- foreach ($this->_mozillaAttr as $value) {
- if (isset($row[$mozillaTurbaMap[$value]])) {
- // Base64 encode each value as necessary and store it.
- // Store cn and mail separately for use in record dn
- if (!$this->_is_safe_string($row[$mozillaTurbaMap[$value]])) {
- $recordData .= $value . ':: ' . base64_encode($row[$mozillaTurbaMap[$value]]) . "\n";
- } else {
- $recordData .= $value . ': ' . $row[$mozillaTurbaMap[$value]] . "\n";
- }
- }
- }
-
- $dn = 'cn=' . $row[$mozillaTurbaMap['cn']] . ',mail=' . $row[$mozillaTurbaMap['mail']];
- if (!$this->_is_safe_string($dn)) {
- $export .= 'dn:: ' . base64_encode($dn) . "\n";
- } else {
- $export .= 'dn: ' . $dn . "\n";
- }
-
- $export .= "objectclass: top\n"
- . "objectclass: person\n"
- . "objectclass: organizationalPerson\n"
- . "objectclass: inetOrgPerson\n"
- . "objectclass: mozillaAbPersonAlpha\n"
- . $recordData . "modifytimestamp: 0Z\n\n";
- }
-
- return $export;
- }
-
- /**
- * 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())
- {
- switch ($action) {
- case Horde_Data::IMPORT_FILE:
- $next_step = parent::nextStep($action, $param);
- if (is_a($next_step, 'PEAR_Error')) {
- return $next_step;
- }
-
- $_SESSION['import_data']['data'] = $this->importFile($_FILES['import_file']['tmp_name']);
- $data = array();
- foreach ($_SESSION['import_data']['data'] as $record) {
- $turbaHash = array();
- foreach ($this->_turbaAttr as $value) {
- switch ($value) {
- case 'homeAddress':
- // These are the keys we're interested in.
- $keys = array('homeStreet', 'mozillaHomeStreet2',
- 'mozillaHomeLocalityName', 'mozillaHomeState',
- 'mozillaHomePostalCode', 'mozillaHomeCountryName');
-
- // Grab all of them that exist in $record.
- $values = array_intersect_key($record, array_flip($keys));
-
- // Special handling for State if both State
- // and Locality Name are set.
- if (isset($values['mozillaHomeLocalityName'])
- && isset($values['mozillaHomeState'])) {
- $values['mozillaHomeLocalityName'] .= ', ' . $values['mozillaHomeState'];
- unset($values['mozillaHomeState']);
- }
-
- if ($values) {
- $turbaHash[$value] = implode("\n", $values);
- }
- break;
-
- case 'workAddress':
- // These are the keys we're interested in.
- $keys = array('street', 'mozillaWorkStreet2', 'l',
- 'st', 'postalCode', 'c');
-
- // Grab all of them that exist in $record.
- $values = array_intersect_key($record, array_flip($keys));
-
- // Special handling for "st" if both "st" and
- // "l" are set.
- if (isset($values['l']) && isset($values['st'])) {
- $values['l'] .= ', ' . $values['st'];
- unset($values['st']);
- }
-
- if ($values) {
- $turbaHash[$value] = implode("\n", $values);
- }
- break;
-
- default:
- if (isset($record[$this->_turbaMozillaMap[$value]])) {
- $turbaHash[$value] = $record[$this->_turbaMozillaMap[$value]];
- }
- break;
- }
- }
-
- $data[] = $turbaHash;
- }
-
- unset($_SESSION['import_data']['data']);
- return $data;
-
- default:
- return parent::nextStep($action, $param);
- }
- }
-
-}