<?php
/* $Id: csv.php,v 1.8.2.2 2006/04/21 07:54:53 nijel Exp $ */
// vim: expandtab sw=4 ts=4 sts=4:
/* CSV import plugin for phpMyAdmin */
if ($plugin_param == 'table') {
if (isset($plugin_list)) {
$plugin_list['csv'] = array(
'text' => 'strCSV',
'extension' => 'csv',
'options' => array(
array('type' => 'bool', 'name' => 'replace', 'text' => 'strReplaceTable'),
array('type' => 'bool', 'name' => 'ignore', 'text' => 'strIgnoreDuplicates'),
array('type' => 'text', 'name' => 'terminated', 'text' => 'strFieldsTerminatedBy', 'size' => 2, 'len' => 2),
array('type' => 'text', 'name' => 'enclosed', 'text' => 'strFieldsEnclosedBy', 'size' => 2, 'len' => 2),
array('type' => 'text', 'name' => 'escaped', 'text' => 'strFieldsEscapedBy', 'size' => 2, 'len' => 2),
array('type' => 'text', 'name' => 'new_line', 'text' => 'strLinesTerminatedBy', 'size' => 2),
array('type' => 'text', 'name' => 'columns', 'text' => 'strColumnNames'),
),
'options_text' => 'strCSVImportOptions',
);
} else {
/* We do not define function when plugin is just queried for information above */
$replacements = array(
'\\n' => "\n",
'\\t' => "\t",
'\\r' => "\r",
);
$csv_terminated = strtr($csv_terminated, $replacements);
$csv_enclosed = strtr($csv_enclosed, $replacements);
$csv_escaped = strtr($csv_escaped, $replacements);
$csv_new_line = strtr($csv_new_line, $replacements);
if (strlen($csv_terminated) != 1) {
$message = sprintf($strInvalidCSVParameter, $strFieldsTerminatedBy);
$show_error_header = TRUE;
$error = TRUE;
} elseif (strlen($csv_enclosed) != 1) {
$message = sprintf($strInvalidCSVParameter, $strFieldsEnclosedBy);
$show_error_header = TRUE;
$error = TRUE;
} elseif (strlen($csv_escaped) != 1) {
$message = sprintf($strInvalidCSVParameter, $strFieldsEscapedBy);
$show_error_header = TRUE;
$error = TRUE;
} elseif (strlen($csv_new_line) != 1 && $csv_new_line != 'auto') {
$message = sprintf($strInvalidCSVParameter, $strLinesTerminatedBy);
$show_error_header = TRUE;
$error = TRUE;
}
$buffer = '';
if (isset($csv_replace)) {
$sql_template = 'REPLACE';
} else {
$sql_template = 'INSERT';
if (isset($csv_ignore)) {
$sql_template .= ' IGNORE';
}
}
$sql_template .= ' INTO ' . PMA_backquote($table);
$tmp_fields = PMA_DBI_get_fields($db, $table);
if (empty($csv_columns)) {
$fields = $tmp_fields;
} else {
$sql_template .= ' (';
$fields = array();
$tmp = split(',( ?)', $csv_columns);
foreach ($tmp as $key => $val) {
if (count($fields) > 0) {
$sql_template .= ', ';
}
$val = trim($val);
$found = FALSE;
foreach ($tmp_fields as $id => $field) {
if ($field['Field'] == $val) {
$found = TRUE;
break;
}
}
if (!$found) {
$message = sprintf($strInvalidColumn, $val);
$show_error_header = TRUE;
$error = TRUE;
break;
}
$fields[] = $field;
$sql_template .= PMA_backquote($val);
}
$sql_template .= ') ';
}
$required_fields = count($fields);
$sql_template .= ' VALUES (';
// Defaults for parser
$i = 0;
$len = 0;
$line = 1;
$lasti = -1;
$values = array();
$csv_finish = FALSE;
while (!($finished && $i >= $len) && !$error && !$timeout_passed) {
$data = PMA_importGetNextChunk();
if ($data === FALSE) {
// subtract data we didn't handle yet and stop processing
$offset -= strlen($buffer);
break;
} elseif ($data === TRUE) {
// Handle rest of buffer
} else {
// Append new data to buffer
$buffer .= $data;
// Do not parse string when we're not at the end and don't have new line inside
if (($csv_new_line == 'auto' && strpos($buffer, "\r") === FALSE && strpos($buffer, "\n") === FALSE)
|| ($csv_new_line != 'auto' && strpos($buffer, $csv_new_line) === FALSE)) {
continue;
}
}
// Current length of our buffer
$len = strlen($buffer);
// Currently parsed char
$ch = $buffer[$i];
while ($i < $len) {
// Deadlock protection
if ($lasti == $i && $lastlen == $len) {
$message = sprintf($strInvalidCSVFormat, $line);
$show_error_header = TRUE;
$error = TRUE;
break;
}
$lasti = $i;
$lastlen = $len;
// This can happen with auto EOL and \r at the end of buffer
if (!$csv_finish) {
// Grab empty field
if ($ch == $csv_terminated) {
$values[] = '';
if ($i == $len - 1) {
break;
}
$i++;
$ch = $buffer[$i];
continue;
}
// Grab one field
$fallbacki = $i;
if ($ch == $csv_enclosed) {
$need_end = TRUE;
if ($i == $len - 1) {
break;
}
$i++;
$ch = $buffer[$i];
} else {
$need_end = FALSE;
}
$fail = FALSE;
$value = '';
while (($need_end && $ch != $csv_enclosed) || (!$need_end && !($ch == $csv_terminated || $ch == $csv_new_line || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n"))))) {
if ($ch == $csv_escaped) {
if ($i == $len - 1) {
$fail = TRUE;
break;
}
$i++;
$ch = $buffer[$i];
}
$value .= $ch;
if ($i == $len - 1) {
if (!$finished) {
$fail = TRUE;
}
break;
}
$i++;
$ch = $buffer[$i];
}
if ($fail) {
$i = $fallbacki;
$ch = $buffer[$i];
break;
}
// Need to strip trailing enclosing char?
if ($need_end && $ch == $csv_enclosed) {
if ($finished && $i == $len - 1) {
$ch = NULL;
} elseif ($i == $len - 1) {
$i = $fallbacki;
$ch = $buffer[$i];
break;
} else {
$i++;
$ch = $buffer[$i];
}
}
// Are we at the end?
if ($ch == $csv_new_line || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) || ($finished && $i == $len - 1)) {
$csv_finish = TRUE;
}
// Go to next char
if ($ch == $csv_terminated) {
if ($i == $len - 1) {
$i = $fallbacki;
$ch = $buffer[$i];
break;
}
$i++;
$ch = $buffer[$i];
}
// If everything went okay, store value
$values[] = $value;
}
// End of line
if ($csv_finish || $ch == $csv_new_line || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n"))) {
if ($csv_new_line == 'auto' && $ch == "\r") { // Handle "\r\n"
if ($i >= ($len - 2) && !$finished) {
break; // We need more data to decide new line
}
if ($buffer[$i + 1] == "\n") {
$i++;
}
}
// We didn't parse value till the end of line, so there was empty one
if (!$csv_finish) {
$values[] = '';
}
// Do we have correct count of values?
if (count($values) != $required_fields) {
$message = sprintf($strInvalidCSVFieldCount, $line);
$show_error_header = TRUE;
$error = TRUE;
break;
}
$first = TRUE;
$sql = $sql_template;
foreach ($values as $key => $val) {
if (!$first) {
$sql .= ', ';
}
$sql .= '\'' . addslashes($val) . '\'';
$first = FALSE;
}
$sql .= ')';
// FIXME: maybe we could add original line to verbose SQL in comment
PMA_importRunQuery($sql, $sql);
$line++;
$csv_finish = FALSE;
$values = array();
$buffer = substr($buffer, $i + 1);
$len = strlen($buffer);
$i = 0;
$lasti = -1;
$ch = $buffer[0];
}
} // End of parser loop
} // End of import loop
// Commit any possible data in buffers
PMA_importRunQuery();
if (count($values) != 0 && !$error) {
$message = sprintf($strInvalidCSVFormat, $line);
$show_error_header = TRUE;
$error = TRUE;
}
}
}
?>