<?
class CSV
{
var $CSVFile;
var $CSVData;
var $CSVError;
var $FieldNames; //beinhaltet die Feldnamen der Felder. FieldNames[field_id] = Feldname
var $Fields; //beinhaltet ein array mit den ganzen zeilen und feldern Fields[line][field_id] = value
var $FieldTypes; //enthält die Typ-Definitionen für die Felder FieldTypes[field_id] = type
var $fetchCursor; //Interner Zähler der von den Fetch-Funktionen benutzt wird
var $Filter;
function CSV()
{
$this->CSVError = array();
$this->CSVData = "";
$this->Filter = array();
}
function setFile($file)
{
/*
Bestimmt die CSV-Datei und setzt den Inhalt der Datei
in die CSVData in einem String
*/
$this->CSVFile = $file;
if(file_exists($this->CSVFile) && ($this->CSVFile != "none") && !empty($this->CSVFile))
{
$this->setData(join("",file($this->CSVFile)));
}
else
{
$this->CSVError[] = "Datei " . $file . " existiert nicht oder keine Lese-Rechte";
return FALSE;
}
}
function setData($string)
{
/*
Sollte zum Import von CSV-Daten keine Datei benutzt werden, so
kann hier der String übergeben werden.
*/
$this->CSVData = $string;
//Löschung von gefüllten Arrays
$this->Fields = array();
$this->FieldTypes = array();
$this->FieldNames = array();
}
function CSVFetchRow()
{
if($this->fetchCursor <= $this->CSVNumRows())
{
$r = $this->Fields[$this->fetchCursor];
$this->fetchCursor++;
return $r;
}
else
{
$this->CSVError[] = "Es existieren keine weiteren Datensätze";
return FALSE;
}
}
function CSVFetchArray($resultTyp = "BOTH")
{
if($this->fetchCursor <= $this->CSVNumRows())
{
if( ($resultTyp == "NUM") || ($resultTyp == "BOTH") )
{
$r = $this->CSVFetchRow();
if($resultTyp == "NUM") return $r;
$this->fetchCursor--; //Weil diese var von der Funktion CSVFetchRow inkrementiert und im nächsten Fall "ASSOC" dann scheisse liefert
}
if( ($resultTyp == "ASSOC") || ($resultTyp == "BOTH") )
{
if(is_array($this->Fields[$this->fetchCursor]))
{
reset($this->Fields[$this->fetchCursor]);
while(list($field_id, $field) = each($this->Fields[$this->fetchCursor]))
{
$r[$this->FieldNames[$field_id]] = $field;
}
}
}
$this->fetchCursor++;
return $r;
}
else
{
$this->CSVError[] = "Es existieren keine weiteren Datensätze";
return FALSE;
}
}
function CSVFetchFieldNames()
{
return $this->FieldNames;
}
function CSVFieldName($field_id)
{
return $this->FieldNames[$field_id];
}
function CSVNumRows()
{
return count($this->Fields);
}
function CSVNumFields()
{
return count($this->FieldNames);
}
function setCursor($pos)
{
$this->fetchCursor = $pos;
}
function getCursor()
{
return $this->fetchCursor;
}
function resetCursor()
{
$this->setCursor(0);
}
function getFieldID($search_field)
{
if(!is_array($this->FieldNames)) return FALSE;
foreach($this->FieldNames AS $field_id => $field_name)
{
//echo $search_field . " " . $field_name . " hallo<br>";
if(trim($search_field) == trim($field_name))
{
return $field_id;
}
}
return FALSE;
}
function addFilter($field, $operator, $match_value)
{
if(!$fieldID = $this->getFieldID($field)) $fieldID = $field;
$field = $fieldID . "||" . count($this->Filter);
$this->Filter[$field]["operator"] = $operator;
$this->Filter[$field]["match_value"] = $match_value;
}
function applyFilter()
{
if(!count($this->Filter)) return FALSE;
$results = array();
$cc = 0;
foreach($this->Filter AS $match_field => $match_values)
{
$match_field = substr($match_field, 0, strpos($match_field, "||"));
//Bei Trennzeichen-CSV-Dateien steht im key anstatt der id der name des Feldes. Hier wird die id des feldes ermittelt
if(!is_numeric($match_field) && (($fieldID = $this->getFieldID($match_field)) !== FALSE) ) $match_field = $fieldID;
$operator = $match_values["operator"];
$match_value = $match_values["match_value"];
$results[$cc] = $this->Fields;
foreach($this->Fields AS $line => $fields)
{
$filterResult = FALSE;
switch($operator)
{
case "==": case "=":
if($fields[$match_field] == $match_value) $filterResult = TRUE;
break;
case "!=" : case "!":
if($fields[$match_field] != $match_value) $filterResult = TRUE;
break;
case "<": case "lt":
if($fields[$match_field] < $match_value) $filterResult = TRUE;
break;
case ">": case "gt":
if($fields[$match_field] > $match_value) $filterResult = TRUE;
break;
}
if(!$filterResult)
{
unset($results[$cc][$line]);
}
}
$cc++;
}
//Die einzelnen Ergebnisse jedes Filters werden jetzt zusammengefasst
$this->Fields = array();
foreach($results AS $fields) $this->Fields = $this->array_merge_better($this->Fields, $fields);
//Lückenlose (d.h. durchgehend nummeriert) Arrayzusammensetzung
$r = "";
foreach($this->Fields AS $fields) $r[] = $fields;
$this->Fields = $r;
return TRUE;
}
function setFieldType($field, $type="")
{
$this->FieldTypes[$field] = $type;
}
function _prepareFieldTypes()
{
foreach($this->FieldTypes AS $field => $value)
{
if(is_string($field))
{
unset($this->FieldTypes[$field]);
if(($fieldID = $this->getFieldID($field)) !== FALSE) $this->FieldTypes[$fieldID] = $value;
}
}
}
function convertFieldType()
{
if(!count($this->FieldTypes)) return FALSE;
$this->_prepareFieldTypes();
$valid_holder = array("m", "h", "D", "M", "Y"); //erlaubte Platzhalter in der Datum-Definition
foreach($this->Fields AS $line_id => $line)
{
foreach($line AS $field_id => $value)
{
if(!isset($this->FieldTypes[$field_id]) || empty($this->FieldTypes[$field_id]) || empty($value)) continue;
$convert_type = $this->FieldTypes[$field_id];
$convert_arg = substr($convert_type, strpos($convert_type, "(")+1, strlen($convert_type) - (strpos($convert_type, "(") + 2));
if(strpos($convert_arg, ",")) //mehrere Argumente
{
$convert_arg = explode(",", $convert_arg);
reset($convert_arg);
while(list($key2, $value2) = each($convert_arg))
{
$value2 = trim($value2);
if(substr($value2, 0, 1) == "'") $value2 = str_replace("'", "", $value2);
$convert_arg[$key2] = $value2;
}
}
$convert_value = "";
switch(trim(strtolower(substr($convert_type, 0, strpos($convert_type, "(")))))
{
case "decimal": case "double":
$convert_value = substr($value, 0, strlen($value) - $convert_arg) . "." . substr($value, $convert_arg * -1) ;
$convert_value = doubleval($convert_value);
break;
case "number": case "int": case "integer":
$convert_value = str_replace(",", ".", $value);
$convert_value = doubleval($convert_value);
break;
case "date":
$holder_define = $convert_arg[0]; //hier wurden die Platzhalter definiert
if(isset($holder_values)) unset($holder_values);
for($cc = 0; $cc < strlen($value); $cc++)
{
$sub_value = substr($value, $cc, 1);
$holder = substr($holder_define, $cc, 1);
if(in_array($holder, $valid_holder))
{
$holder_values[$holder] .= $sub_value;
}
}
$holder_define = $convert_arg[1];
for($cc = 0; $cc < strlen($holder_define); $cc++)
{
$holder = substr($holder_define, $cc, 1);
if(in_array($holder, $valid_holder))
{
$convert_value .= substr($holder_values[$holder], 0, 1);
$holder_values[$holder] = substr($holder_values[$holder], 1);
}
else
{
$convert_value .= $holder;
}
}
break;
}
if($convert_value !== $value) $this->Fields[$line_id][$field_id] = $convert_value;
}
}
}
function echoCSVError()
{
/*
gibt alle Fehler aus
*/
foreach($this->CSVError AS $pos => $error_str)
{
echo "- " . ($pos+1) . ". " . $error_str . "<br>";
}
}
function isOK($error_output = TRUE)
{
//Liefert TRUE or FALSE, ob alles ok ist. Der optionale Parameter gibt die fehler aus.
if($error_output) $this->echoCSVError();
return ((count($this->CSVError) > 0) ? FALSE : TRUE);
}
function array_merge_better($a1,$a2)
{
if(!is_array($a1)) $a1 = array();
if(!is_array($a2)) $a2 = array();
// if(!is_array($a1) || !is_array($a2)) return false;
$newarray = $a1;
while (list($key, $val) = each($a2))
{
if (is_array($val) && is_array($newarray[$key]))
{
$newarray[$key] = $this->array_merge_better($newarray[$key], $val);
}
else
{
$newarray[$key] = $val;
}
}
return $newarray;
}
function dumpResult()
{
$prevFetchCursor = $this->getCursor();
$this->resetCursor();
$fields = $this->CSVFetchFieldNames();
echo "<table border='1'><tr>";
foreach($fields AS $feld)
{
echo "<td><b>" . $feld . "</b></td>";
}
echo "</tr>";
while($row = $this->CSVFetchArray("ASSOC"))
{
echo "<tr>";
foreach($row AS $k => $feld)
{
echo "<td> " . $feld . "</td>";
}
echo "</tr>";
}
echo "</table>";
$this->setCursor($prevFetchCursor);
}
}
class CSVImport extends CSV
{
var $FieldDelim;
function CSVImport()
{
parent::CSV();
$this->FieldDelim = ";";
}
function setDelim($delimiter)
{
$this->FieldDelim = $delimiter;
}
function parseCSV()
{
if($this->CSVData)
{
$akt_line = 0;
$akt_field = 0;
$akt_field_value = "";
$last_char = "";
$quote = 0;
$field_input = 0;
$head_complete = 0;
$end_cc = strlen($this->CSVData);
for($cc = 0; $cc < $end_cc; $cc++)
{
$akt_char = substr($this->CSVData,$cc,1);
if(($akt_char == "\"") && ($last_char != "\\")) //Abschliessung des eingeschlossenen Feldes. beschreibung siehe unten
{
$quote = !$quote;
$akt_char = "";
}
if(!$quote)
{
if($akt_char == $this->FieldDelim) //Trennzeichen
{
$field_input = !$field_input;
$akt_char = "";
$akt_field++;
$akt_field_value = "";
}
elseif(($akt_char == "\\") && $field_input) //Escape-Zeichen
{
$field_input++;
$quote++;
}
elseif($akt_char == "\"") //Anführungszeichen kennzeichenen ein eingeschlossenes Feld, d.h. dieses Feld kann das Trennzeichen als Text enthalten und mehrzeilig sein.
{
$quote--;
if($field_input)
$field_input--;
else
$field_input++;
}
elseif($akt_char == "\n") //Neuer Datensatz
{
if($head_complete && (($akt_field+1) > $this->CSVNumFields()))
{
$this->CSVError[] = "Fehler in <b>Zeile " . ($akt_line + 2) . "</b>";
}
$akt_line++;
$akt_field = 0;
if(!$head_complete) $akt_line = 0;
$head_complete = 1;
$akt_char = "";
$akt_field_value = "";
}
}
$last_char = $akt_char;
if($akt_char == "\\") $akt_char = "";
$akt_field_value .= $akt_char;
if($head_complete)
{
$this->Fields[$akt_line][$akt_field] = trim($akt_field_value); //Felder befüllung
}
else
{
$this->FieldNames[$akt_field] = trim($akt_field_value); //Feldernamen befüllung
}
}
if(!$akt_field) //Leeren Abschluss-Datensatz entfernen
{
unset($this->Fields[$akt_line]);
}
parent::convertFieldType();
parent::applyFilter();
$this->fetchCursor = 0;
}
else
{
$this->CSVError[] = "Das CSV-Data ist nicht gefüllt";
return FALSE;
}
}
}
class CSVFixImport extends CSV
{
var $FieldLengths; //Array mit den Längen der Felder
function CSVFixImport()
{
parent::CSV(); //Konstruktor der Eltern-Klasse aufrufen
$this->FieldLengths = array();
}
function addCSVField($name, $length, $type = "")
{
$cursor = count($this->FieldNames);
if(!$name) $name = "Feld " . ($cursor + 1);
$this->FieldNames[$cursor] = $name;
$this->FieldLengths[$cursor] = $length;
$this->setFieldType($cursor, $type);
}
function setFile($file)
{
parent::setFile($file);
$this->CSVData = explode("\n", trim($this->CSVData));
}
function parseCSV()
{
if($this->CSVData)
{
if(!count($this->FieldLengths))
{
$this->CSVError[] = "Die Felder wurden nicht definiert";
return FALSE;
}
$currentLine = 0;
foreach($this->CSVData AS $line)
{
$currentField = 0;
$currentStringPos = 0;
foreach($this->FieldLengths AS $FieldLength)
{
$value = trim(substr($line, $currentStringPos, $FieldLength));
$this->Fields[$currentLine][$currentField] = $value;
$currentStringPos += $FieldLength;
$currentField++;
}
$currentLine++;
}
parent::convertFieldType();
parent::applyFilter();
$this->fetchCursor = 0;
}
else
{
$this->CSVError[] = "Keine zu importierende Daten gesetzt";
return FALSE;
}
}
}
?>