ldapsaisie/src/includes/class/class.LSioFormatCSV.php

296 lines
8.2 KiB
PHP
Raw Normal View History

2015-07-30 16:37:42 +02:00
<?php
/*******************************************************************************
* Copyright (C) 2007 Easter-eggs
* 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 {
/**
* Fields value delimiter
* @see fgetcsv()
* @see LSioFormatCSV::__construct()
* @var string|null
*/
private $delimiter = null;
/**
* Fields value enclosure
* @see fgetcsv()
* @see LSioFormatCSV::__construct()
* @var string|null
*/
private $enclosure = null;
/**
* Fields value escape character
* @see fgetcsv()
* @see LSioFormatCSV::__construct()
* @var string|null
*/
private $escape = null;
/**
* Fields value maximum length
* @see fgetcsv()
* @see LSioFormatCSV::__construct()
* @var string|null
*/
private $length = null;
/**
* Delimiter for multiple-value inside a field value
* @see LSioFormatCSV::__construct()
* @var string|null
*/
private $multiple_value_delimiter = null;
/**
* CSV file parsed rows
* @see LSioFormatCSV::loadFile()
* @see LSioFormatCSV::isValid()
* @see LSioFormatCSV::getAll()
* @var array|null
*/
private $rows = null;
/**
* CSV file parsed header row
* @see LSioFormatCSV::loadFile()
* @see LSioFormatCSV::isValid()
* @see LSioFormatCSV::getAll()
* @var array|null
*/
private $headers = null;
/**
* Constructor
*
* @param array $options Driver's options
*
* @return void
**/
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
*
* @param string $path The file path to load
2015-07-30 16:37:42 +02:00
*
* @return boolean True if file is loaded, false otherwise
2015-07-30 16:37:42 +02:00
**/
public function loadFile($path) {
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
}
$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
}
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
*
* @return boolean True if loaded file data are valid, false otherwise
2015-07-30 16:37:42 +02:00
**/
public function isValid() {
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
}
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]',
* [...]
* ),
* )
*
* @return array The objects contained by the loaded file
2015-07-30 16:37:42 +02:00
**/
public function getAll() {
$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]',
* [...]
* )
*
* @return array The fields names of the loaded file
2015-07-30 16:37:42 +02:00
**/
public function getFieldNames() {
return $this -> headers;
}
/**
* Export objects data
*
* @param array $objects_data of objects data to export
* @param resource|null $stream The output stream (optional, default: STDOUT)
*
2021-08-25 18:02:37 +02:00
* @return boolean True on success, False otherwise
*/
2021-02-05 18:12:44 +01:00
public function exportObjectsData($objects_data, $stream=null) {
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;
}
$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;
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
/**
* Write CSV row to stream
*
* @param resource $stream The CSV file description reference
* @param array[string] $row An array of a CSV row fields to write
*
* @author Benjamin Renard <brenard@easter-eggs.com>
*
* @return boolean True if CSV row is successfully writed, false in other case
*/
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
}
LSerror :: defineError('LSioFormatCSV_01',
___("LSioFormatCSV: function fputcsv is not available.")
);