2017-03-30 09:09:07 +02:00

147 lines
4.3 KiB
PHP

<?php
require_once(__DIR__.'/ArrayExtended.php');
class CSVReader
{
private $file_path = '';
private $params = array('enable_skip_line' => false, 'auto_detect'=>true, 'separator' => ',', 'enclosure' => '"', 'expected_header' => array());
private $handlers = array('start' => null, 'error' => null);
private $current_num_line = 0;
private $expected_cols_index = array();
function __construct($file_path)
{
$this->file_path = $file_path;
$this->handlers = array(
'start' => function() {},
'error' => function($failed_line_number) {},
'readline' => function(ArrayExtended $cols) { return true; }
);
// if required, convert the file to the correct format
$str = file_get_contents($file_path);
if (mb_detect_encoding($str, "UTF-8,ISO-8859-1", true) == 'ISO-8859-1') {
file_put_contents($file_path, utf8_encode(file_get_contents($file_path)));
}
}
function setExpectedHeader(array $expected_header)
{
$this->params['expected_header'] = $expected_header;
return $this;
}
function enableSkipHeader()
{
$this->params['enable_skip_line'] = true;
return $this;
}
// func : function()
function setOnStart(callable $func)
{
$this->handlers['start'] = $func;
return $this;
}
// func : function(ArrayExtended $columns)
function setOnEachLine(callable $func)
{
$this->handlers['readline'] = $func;
return $this;
}
// func : function(int failed_line_number)
function setOnError(callable $func)
{
$this->handlers['error'] = $func;
return $this;
}
function readLines()
{
$ok = false;
$this->current_num_line = 0;
if ($this->params['auto_detect']) {
$this->autoDetect($this->file_path);
}
$f = fopen($this->file_path, 'r');
if ($f) {
call_user_func($this->handlers['start']);
$ok = true;
if ($this->params['enable_skip_line'] || count($this->params['expected_header'])>0) {
$ok = $this->checkHeader(fgetcsv($f, 0, $this->params['separator'], $this->params['enclosure']));
}
while ($ok && ($cols = fgetcsv($f, 0, $this->params['separator'], $this->params['enclosure']))) {
$real_cols = array();
foreach($this->expected_cols_index as $real_index => $index) {
$real_cols[$index] = trim($cols[$real_index]);
}
$ok = call_user_func($this->handlers['readline'], new ArrayExtended($real_cols));
$this->current_num_line++;
}
fclose($f);
}
if (!$ok) {
call_user_func($this->handlers['error'], $this->current_num_line);
}
return $ok;
}
private function checkHeader(array $cols)
{
$ok = true;
foreach($this->params['expected_header'] as $expected_col => $expected_pos) {
$found = false;
foreach($cols as $index => $col) {
if (strtolower($col) == strtolower($expected_col)) {
$this->expected_cols_index[$index] = $expected_pos;
$found = true;
break;
}
}
$ok = $ok && $found;
}
return $ok;
}
private function autoDetect($file_path)
{
if ($f = fopen($file_path, 'r')) {
$line = fgets($f);
if ($line[0] == '"') {
$line[0] = '';
$line = str_replace("\\\"", '', $line);
$line = str_replace("\"\"", '', $line);
$line = strstr($line, '"');
if (strlen($line)>1) {
$this->params['separator'] = $line[1];
}
}
else {
if (strpos($line, ';')!==false) {
$this->params['separator'] = ';';
}
elseif (strpos($line, ',')!==false) {
$this->params['separator'] = ',';
}
elseif (strpos($line, '|')!==false) {
$this->params['separator'] = '|';
}
}
fclose($f);
}
}
}