2015-07-30 16:37:42 +02:00
|
|
|
<?php
|
|
|
|
/*******************************************************************************
|
|
|
|
* Copyright (C) 2007 Easter-eggs
|
2021-04-13 18:04:19 +02:00
|
|
|
* https://ldapsaisie.org
|
2015-07-30 16:37:42 +02:00
|
|
|
*
|
|
|
|
* Author: See AUTHORS file in top-level directory.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License version 2
|
|
|
|
* as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
LSsession :: loadLSclass('LSioFormatDriver');
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Driver to manage CSV ioFormat file of LSldapObject import/export
|
|
|
|
*
|
|
|
|
* @author Benjamin Renard <brenard@easter-eggs.com>
|
|
|
|
*/
|
|
|
|
class LSioFormatCSV extends LSioFormatDriver {
|
|
|
|
|
2022-12-31 21:15:19 +01:00
|
|
|
/**
|
|
|
|
* Fields value delimiter
|
|
|
|
* @see fgetcsv()
|
|
|
|
* @see LSioFormatCSV::__construct()
|
|
|
|
* @var string|null
|
|
|
|
*/
|
2021-02-05 11:42:55 +01:00
|
|
|
private $delimiter = null;
|
2022-12-31 21:15:19 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fields value enclosure
|
|
|
|
* @see fgetcsv()
|
|
|
|
* @see LSioFormatCSV::__construct()
|
|
|
|
* @var string|null
|
|
|
|
*/
|
2021-02-05 11:42:55 +01:00
|
|
|
private $enclosure = null;
|
2022-12-31 21:15:19 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fields value escape character
|
|
|
|
* @see fgetcsv()
|
|
|
|
* @see LSioFormatCSV::__construct()
|
|
|
|
* @var string|null
|
|
|
|
*/
|
2021-02-05 11:42:55 +01:00
|
|
|
private $escape = null;
|
2022-12-31 21:15:19 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fields value maximum length
|
|
|
|
* @see fgetcsv()
|
|
|
|
* @see LSioFormatCSV::__construct()
|
|
|
|
* @var string|null
|
|
|
|
*/
|
2021-02-05 11:42:55 +01:00
|
|
|
private $length = null;
|
2022-12-31 21:15:19 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Delimiter for multiple-value inside a field value
|
|
|
|
* @see LSioFormatCSV::__construct()
|
|
|
|
* @var string|null
|
|
|
|
*/
|
2022-12-31 02:01:17 +01:00
|
|
|
private $multiple_value_delimiter = null;
|
2021-02-05 11:42:55 +01:00
|
|
|
|
2022-12-31 21:15:19 +01:00
|
|
|
/**
|
|
|
|
* CSV file parsed rows
|
|
|
|
* @see LSioFormatCSV::loadFile()
|
|
|
|
* @see LSioFormatCSV::isValid()
|
|
|
|
* @see LSioFormatCSV::getAll()
|
|
|
|
* @var array|null
|
|
|
|
*/
|
2021-02-05 11:42:55 +01:00
|
|
|
private $rows = null;
|
2022-12-31 21:15:19 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* CSV file parsed header row
|
|
|
|
* @see LSioFormatCSV::loadFile()
|
|
|
|
* @see LSioFormatCSV::isValid()
|
|
|
|
* @see LSioFormatCSV::getAll()
|
|
|
|
* @var array|null
|
|
|
|
*/
|
2021-02-05 11:42:55 +01:00
|
|
|
private $headers = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @param array $options Driver's options
|
2021-02-05 11:42:55 +01:00
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @return void
|
2021-02-05 11:42:55 +01:00
|
|
|
**/
|
|
|
|
public function __construct($options) {
|
|
|
|
parent :: __construct($options);
|
|
|
|
// As recommend in PHP doc, we enable this ini parameter to allow detection of
|
|
|
|
// Macintosh line-ending convention.
|
|
|
|
ini_set("auto_detect_line_endings", true);
|
|
|
|
|
|
|
|
// Set CSV input/output parameters
|
|
|
|
$this -> delimiter = $this -> getOption('delimiter', ",", "string");
|
|
|
|
$this -> enclosure = $this -> getOption('enclosure', '"', "string");
|
|
|
|
$this -> escape = $this -> getOption('escape', "\\", "string");
|
|
|
|
$this -> length = $this -> getOption('length', 0, "int");
|
|
|
|
$this -> multiple_value_delimiter = $this -> getOption('multiple_value_delimiter', '|', "string");
|
|
|
|
self :: log_debug(
|
|
|
|
'New LSioFormatCSV objet started with delimiter="'.$this -> delimiter.'", '.
|
|
|
|
'enclosure = <'.$this -> enclosure.'>, escape = "'.$this -> escape.'", '.
|
|
|
|
'length = '.$this -> length.' and multiple value delimiter = "'.
|
|
|
|
$this -> multiple_value_delimiter.'"'
|
|
|
|
);
|
|
|
|
}
|
2015-07-30 16:37:42 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Load file
|
|
|
|
*
|
2022-12-31 21:15:19 +01:00
|
|
|
* @param string $path The file path to load
|
2015-07-30 16:37:42 +02:00
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @return boolean True if file is loaded, false otherwise
|
2015-07-30 16:37:42 +02:00
|
|
|
**/
|
|
|
|
public function loadFile($path) {
|
2021-02-05 11:42:55 +01:00
|
|
|
self :: log_debug("loadFile($path)");
|
|
|
|
$fd = fopen($path, 'r');
|
|
|
|
if ($fd === false) {
|
|
|
|
self :: log_error("Fail to open file '$path'.");
|
|
|
|
return false;
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
2021-02-05 11:42:55 +01:00
|
|
|
|
|
|
|
$this -> rows = array();
|
|
|
|
while (
|
|
|
|
(
|
|
|
|
$row = fgetcsv(
|
|
|
|
$fd, $this -> length, $this -> delimiter,
|
|
|
|
$this -> enclosure, $this -> escape
|
|
|
|
)
|
|
|
|
) !== FALSE) {
|
|
|
|
$this -> rows[] = $row;
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
2021-02-05 11:42:55 +01:00
|
|
|
if (!$this -> rows)
|
|
|
|
return false;
|
|
|
|
$this -> headers = array_shift($this -> rows);
|
|
|
|
self :: log_trace("loadFile($path): headers = ".varDump($this -> headers));
|
|
|
|
self :: log_debug("loadFile($path): ".count($this -> rows)." row(s) loaded.");
|
|
|
|
return true;
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if loaded file data are valid
|
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @return boolean True if loaded file data are valid, false otherwise
|
2015-07-30 16:37:42 +02:00
|
|
|
**/
|
|
|
|
public function isValid() {
|
2021-02-05 11:42:55 +01:00
|
|
|
if (!is_array($this -> rows) && empty($this -> rows)) {
|
|
|
|
self :: log_error("No data loaded from input file");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$this -> headers) {
|
|
|
|
self :: log_error("Header line seem empty");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for($i = 0; $i < count($this -> rows); $i++) {
|
|
|
|
if (count($this -> rows[$i]) != count($this -> headers)) {
|
|
|
|
self :: log_error(
|
|
|
|
"Input row #$i contain ".count($this -> rows[$i])." field(s) when ".
|
|
|
|
"headers has ".count($this -> headers)
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
2021-02-05 11:42:55 +01:00
|
|
|
self :: log_debug("isValid(): all ".count($this -> rows)." row(s) are symetric.");
|
|
|
|
return True;
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-08-25 18:02:37 +02:00
|
|
|
* Retrieve all object data contained by the loaded file
|
2015-07-30 16:37:42 +02:00
|
|
|
*
|
|
|
|
* The objects are returned in array :
|
|
|
|
*
|
|
|
|
* array (
|
|
|
|
* array ( // Object 1
|
|
|
|
* '[field1]' => '[value1]',
|
|
|
|
* '[field2]' => '[value2]',
|
|
|
|
* [...]
|
|
|
|
* ),
|
|
|
|
* array ( // Object 2
|
|
|
|
* '[field1]' => '[value1]',
|
|
|
|
* '[field2]' => '[value2]',
|
|
|
|
* [...]
|
|
|
|
* ),
|
|
|
|
* )
|
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @return array The objects contained by the loaded file
|
2015-07-30 16:37:42 +02:00
|
|
|
**/
|
|
|
|
public function getAll() {
|
2021-02-05 11:42:55 +01:00
|
|
|
$objects = array();
|
|
|
|
foreach($this -> rows as $row) {
|
|
|
|
$object = array();
|
|
|
|
foreach ($this -> headers as $idx => $key) {
|
|
|
|
$values = explode($this -> multiple_value_delimiter, $row[$idx]);
|
|
|
|
$object[$key] = (count($values) == 1?$values[0]:$values);
|
|
|
|
}
|
|
|
|
$objects[] = $object;
|
|
|
|
}
|
|
|
|
self :: log_trace("getAll(): objects = ".varDump($objects));
|
|
|
|
return $objects;
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-08-25 18:02:37 +02:00
|
|
|
* Retrieve fields names of the loaded file
|
2015-07-30 16:37:42 +02:00
|
|
|
*
|
|
|
|
* The fields names are returned in array :
|
|
|
|
*
|
|
|
|
* array (
|
|
|
|
* '[field1]',
|
|
|
|
* '[field2]',
|
|
|
|
* [...]
|
|
|
|
* )
|
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @return array The fields names of the loaded file
|
2015-07-30 16:37:42 +02:00
|
|
|
**/
|
|
|
|
public function getFieldNames() {
|
2021-02-05 11:42:55 +01:00
|
|
|
return $this -> headers;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Export objects data
|
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @param array $objects_data of objects data to export
|
|
|
|
* @param resource|null $stream The output stream (optional, default: STDOUT)
|
2021-02-05 11:42:55 +01:00
|
|
|
*
|
2021-08-25 18:02:37 +02:00
|
|
|
* @return boolean True on success, False otherwise
|
2021-02-05 11:42:55 +01:00
|
|
|
*/
|
2021-02-05 18:12:44 +01:00
|
|
|
public function exportObjectsData($objects_data, $stream=null) {
|
2021-02-05 11:42:55 +01:00
|
|
|
if (!function_exists('fputcsv')) {
|
|
|
|
LSerror :: addErrorCode('LSioFormatCSV_01');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-05 18:12:44 +01:00
|
|
|
$stdout = false;
|
|
|
|
if (is_null($stream)) {
|
|
|
|
$stream = fopen('php://temp/maxmemory:'. (5*1024*1024), 'w+');
|
|
|
|
$stdout = true;
|
|
|
|
}
|
|
|
|
|
2021-02-05 11:42:55 +01:00
|
|
|
$first = true;
|
|
|
|
foreach($objects_data as $dn => $object_data) {
|
|
|
|
if ($first) {
|
|
|
|
$this -> writeRow($stream, array_keys($object_data));
|
|
|
|
$first = false;
|
|
|
|
}
|
|
|
|
$row = array();
|
|
|
|
foreach($object_data as $values)
|
|
|
|
$row[] = (is_array($values)?implode($this -> multiple_value_delimiter, $values):$values);
|
|
|
|
$this -> writeRow($stream, $row);
|
|
|
|
}
|
2021-02-05 18:12:44 +01:00
|
|
|
if (!$stdout)
|
|
|
|
return true;
|
2021-02-05 11:42:55 +01:00
|
|
|
header("Content-disposition: attachment; filename=export.csv");
|
|
|
|
header("Content-type: text/csv");
|
|
|
|
rewind($stream);
|
|
|
|
print stream_get_contents($stream);
|
|
|
|
@fclose($stream);
|
|
|
|
exit();
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
2019-03-11 22:42:20 +01:00
|
|
|
|
2021-02-05 11:42:55 +01:00
|
|
|
/**
|
|
|
|
* Write CSV row to stream
|
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @param resource $stream The CSV file description reference
|
|
|
|
* @param array[string] $row An array of a CSV row fields to write
|
2021-02-05 11:42:55 +01:00
|
|
|
*
|
|
|
|
* @author Benjamin Renard <brenard@easter-eggs.com>
|
|
|
|
*
|
2022-12-31 05:52:31 +01:00
|
|
|
* @return boolean True if CSV row is successfully writed, false in other case
|
2021-02-05 11:42:55 +01:00
|
|
|
*/
|
|
|
|
private function writeRow($stream, $row) {
|
|
|
|
// Escape character could only be specified since php 5.5.4
|
|
|
|
if (!defined('PHP_VERSION_ID') or PHP_VERSION_ID < 50504) {
|
|
|
|
$result = fputcsv($stream, $row, $this -> delimiter, $this -> enclosure);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$result = fputcsv($stream, $row, $this -> delimiter, $this -> enclosure, $this -> escape);
|
|
|
|
}
|
|
|
|
return ($result !== false);
|
|
|
|
}
|
|
|
|
|
2015-07-30 16:37:42 +02:00
|
|
|
}
|
2021-02-05 11:42:55 +01:00
|
|
|
|
|
|
|
LSerror :: defineError('LSioFormatCSV_01',
|
|
|
|
___("LSioFormatCSV: function fputcsv is not available.")
|
|
|
|
);
|