" . Adminer\upload_error($files) . "\n";
return true;
}
foreach ($files as $file) {
foreach ($this->_untar($file[0], $file[1]) as $csv) {
if (!$this->_import($csv[0], $csv[1], $_POST["csv_exists"]) && $_POST["error_stops"]) {
break 2;
}
}
}
return true;
}
/** Get files stored in a TAR archive, e.g. an export of several tables to CSV
* @param string $name name of the file
* @param string $tar contents of the file
* @return list " . Adminer\h($name) . ": ";
if (substr($csv, 0, 3) == "\xEF\xBB\xBF") {
$csv = substr($csv, 3); // UTF-8 BOM, get_files() removes it only from the uploaded file, not from the files in an archive
}
if (!Adminer\is_utf8($csv)) {
echo $error_prefix . $this->lang('File must be in UTF-8 encoding.') . "\n";
return false;
}
if (($memory_limit = Adminer\ini_bytes("memory_limit")) != "-1") {
Adminer\ini_set("memory_limit", max($memory_limit, strval(10 * strlen($csv) + memory_get_usage() + 8e6))); // 10 - the parsed data take more memory than the file
}
$rows = Adminer\parse_csv($csv, $this->_separator($csv));
$header = array_map('Adminer\csv_value', (array) array_shift($rows));
while ($header && end($header) === "") {
array_pop($header); // the first row ends with the separator
}
$message_prefix = "
\n";
}
}
$columns = array();
foreach ($header as $column) {
$columns[] = Adminer\idf_escape($column);
}
$insert = "INSERT INTO " . Adminer\table($table) . " (" . implode(", ", $columns) . ") VALUES\n";
// Oracle supports a single row in INSERT, MS SQL is limited to 1000, 0 - no limit
$max_rows = (Adminer\JUSH == "oracle" ? 1 : (Adminer\JUSH == "mssql" ? 1000 : 0));
Adminer\driver()->begin();
$affected = 0;
$failed = false;
$values = array();
$length = 0;
foreach ($rows as $row) {
$set = array();
foreach ($header as $key => $column) {
$val = (string) $row[$key]; // a shorter row leaves the remaining values empty
$set[] = ($val == "" && $fields[$column]["null"] ? "NULL" : Adminer\q(Adminer\csv_value($val)));
}
$value = "(" . implode(", ", $set) . ")";
if ($values && (count($values) === $max_rows || strlen($insert) + $length + strlen($value) > 1e6)) { // 1e6 - default max_allowed_packet
$failed = !Adminer\connection()->query($insert . implode(",\n", $values));
if ($failed) {
break;
}
$values = array();
$length = 0;
}
$values[] = $value;
$length += strlen($value) + 2;
$affected++;
}
if (!$failed && $values) {
$failed = !Adminer\connection()->query($insert . implode(",\n", $values));
}
if ($failed) {
echo $error_prefix . Adminer\adminer()->error() . "\n";
Adminer\driver()->rollback();
return false;
}
Adminer\driver()->commit();
echo $message_prefix . ($created ? $this->lang('Table has been created.') . " " : "") . $this->lang('%d row(s) have been imported.', $affected) . "\n";
return true;
}
/** Autodetect separator of CSV data by its first row
* @param string $csv
* @return string
*/
protected function _separator($csv) {
preg_match('~(?>"[^"]*"|[^"\r\n]+)+~', $csv, $match); // the first row, the same expression as in parse_csv()
$return = ",";
$max = 0;
foreach (array(",", ";", "\t") as $separator) {
$rows = Adminer\parse_csv((string) $match[0], $separator);
$count = count((array) $rows[0]);
if ($count > $max) { // the separator splitting the row to most values wins
$max = $count;
$return = $separator;
}
}
return $return;
}
/** Get fields of a table created from CSV data
* @param list" . Adminer\adminer()->sqlCommandQuery(implode("\n", array_slice(Adminer\Queries::$queries, $start))) . "> $rows values as they are in the file
* @return Adminer\Field[] [$name => Field]
*/
protected function _fields($header, $rows) {
$return = array();
foreach ($header as $key => $name) {
$type = "";
$chars = 0; // maximal number of characters
$integers = 0; // maximal number of digits before the decimal point
$decimals = 0; // maximal number of digits after the decimal point
$big = false;
$null = false;
$unique = array(); // values of the first column
foreach ($rows as $row) {
$val = (string) $row[$key];
if ($val == "") { // an empty value is NULL, an empty string is "" in the file
$null = true;
continue;
}
$val = Adminer\csv_value($val);
if (!$key) {
$unique[$val] = true;
}
$val_type = $this->_valueType($val);
$type = $this->_commonType($type, $val_type);
$chars = max($chars, $this->_strlen($val));
if ($val_type == "int") {
$big = $big || $val > 2147483647 || $val < -2147483648;
$integers = max($integers, strlen(ltrim($val, "-")));
} elseif ($val_type == "decimal") {
preg_match('~^-?([0-9]+)\.([0-9]+)$~', $val, $match);
$integers = max($integers, strlen($match[1]));
$decimals = max($decimals, strlen($match[2]));
}
}
$length = "";
if ($type == "") { // no data
$type = "varchar";
$chars = 200;
}
if ($type == "int" && $big) {
$type = "bigint";
}
if ($type == "decimal") {
// the precision is limited to 65 digits in MySQL, to 38 in Oracle and MS SQL
$max_digits = (Adminer\JUSH == "sql" ? 65 : (preg_match('~^(oracle|mssql)$~', Adminer\JUSH) ? 38 : 1000));
if ($integers + $decimals > $max_digits) {
$type = "float";
} else {
$length = ($integers + $decimals) . ",$decimals";
}
}
if ($type == "varchar") {
foreach (array(20, 50, 100, 200) as $length) {
if ($chars <= $length) {
break;
}
}
}
$return[$name] = array(
"field" => $name,
"type" => $this->_type($type),
"length" => (Adminer\JUSH == "sqlite" ? "" : strval($length)), // SQLite types have no length
"unsigned" => "",
"null" => $null && !preg_match('~varchar|text~', $type), // an empty string is a valid value of a string column
"auto_increment" => false,
"collation" => "",
"privileges" => array(),
"comment" => "",
// the first column identifies the rows if it has no empty and no repeated value; text is not usable as a key in MySQL
"primary" => !$key && $rows && count($unique) == count($rows) && $type != "text",
"generated" => "",
"on_update" => "",
"full_type" => "",
);
}
return $return;
}
/** Get type of a single value in CSV data
* @param string $val
* @return string int, decimal, float, date, time, datetime, varchar or text
*/
protected function _valueType($val) {
$number = '-?([1-9][0-9]*|0)'; // leading zeros are significant, e.g. in ZIP codes
if (preg_match("~^$number\$~", $val)) {
return "int";
}
if (preg_match("~^$number\\.[0-9]{1,3}\$~", $val)) {
return "decimal";
}
if (preg_match("~^$number(\\.[0-9]+)?([eE][-+]?[0-9]+)?\$~", $val)) { // more than three decimal places or exponent
return "float";
}
if (preg_match('~^[0-9]{4}-[0-9]{2}-[0-9]{2}$~', $val)) {
return "date";
}
if (preg_match('~^[0-9]{2}:[0-9]{2}(:[0-9]{2})?$~', $val)) {
return "time";
}
if (preg_match('~^[0-9]{4}-[0-9]{2}-[0-9]{2}[ T][0-9]{2}:[0-9]{2}(:[0-9]{2})?(\.[0-9]+)?$~', $val)) { // time zone is not accepted, it would be lost
return "datetime";
}
return (strpos($val, "\n") !== false || $this->_strlen($val) > 200 ? "text" : "varchar");
}
/** Get type usable for values of two types
* @param string $type1
* @param string $type2
* @return string
*/
protected function _commonType($type1, $type2) {
if ($type1 == "" || $type1 == $type2) {
return $type2;
}
$numbers = array("int" => 1, "decimal" => 2, "float" => 3);
if ($numbers[$type1] && $numbers[$type2]) {
return ($numbers[$type1] > $numbers[$type2] ? $type1 : $type2);
}
return ($type1 == "text" || $type2 == "text" ? "text" : "varchar"); // e.g. a date among numbers
}
/** Get name of a type detected in CSV data in the current driver
* @param string $type
* @return string
*/
protected function _type($type) {
if (Adminer\JUSH == "sqlite") {
if (preg_match('~int~', $type)) {
return "integer";
}
return ($type == "float" ? "real" : ($type == "decimal" ? "numeric" : "text"));
}
if (Adminer\JUSH == "pgsql") {
$types = array("int" => "integer", "decimal" => "numeric", "float" => "double precision", "datetime" => "timestamp", "varchar" => "character varying");
return ($types[$type] ?: $type);
}
if (Adminer\JUSH == "oracle") {
$types = array(
"int" => "number", "bigint" => "number", "decimal" => "number", "float" => "binary_double",
"time" => "varchar2(8)", // Oracle has no time type, 8 characters hold HH:MM:SS
"datetime" => "timestamp", "varchar" => "varchar2", "text" => "clob",
);
return ($types[$type] ?: $type);
}
if (Adminer\JUSH == "mssql") {
$types = array("datetime" => "datetime2", "varchar" => "nvarchar", "text" => "nvarchar(max)"); // the length is not used with (max)
return ($types[$type] ?: $type);
}
$types = array("float" => "double", "text" => "mediumtext"); // MySQL
return ($types[$type] ?: $type);
}
/** Get length of a string in characters, the string must be in UTF-8
* @param string $val
* @return int
*/
protected function _strlen($val) {
return strlen(preg_replace('~[\x80-\xBF]~', '', $val)); // continuation bytes don't start a character
}
protected $translations = array(
'cs' => array(
'' => 'Vytvoření tabulky z nahraného CSV souboru',
'If the table exists' => 'Pokud tabulka existuje',
'Insert' => 'Vložit',
'Truncate' => 'Vyprázdnit',
'Drop' => 'Odstranit',
'Import' => 'Import',
'File must be in UTF-8 encoding.' => 'Soubor musí být v kódování UTF-8.',
'Column %s does not exist.' => 'Sloupec %s neexistuje.',
'Table has been created.' => 'Tabulka byla vytvořena.',
'%d row(s) have been imported.' => array('Byl importován %d záznam.', 'Byly importovány %d záznamy.', 'Bylo importováno %d záznamů.'),
),
'de' => array(
'' => 'Erstellt eine Tabelle aus einer importierten CSV-Datei', // Claude Opus 5
),
'en' => array(
'%d row(s) have been imported.' => array('%d row has been imported.', '%d rows have been imported.'),
),
'ja' => array(
'' => 'インポートした CSV ファイルからテーブルを作成', // Claude Opus 5
),
'pl' => array(
'' => 'Tworzy tabelę z zaimportowanego pliku CSV', // Claude Opus 5
),
'ro' => array(
'' => 'Creează un tabel dintr-un fișier CSV importat', // Claude Opus 5
),
'sk' => array(
'' => 'Vytvorenie tabuľky z nahraného CSV súboru', // Claude Opus 5
),
'zh' => array(
'' => '从导入的 CSV 文件创建表', // Claude Opus 5
'If the table exists' => '如果表已存在', // Claude Opus 5
'Insert' => '插入', // Claude Opus 5
'Truncate' => '清空', // Claude Opus 5
'Drop' => '删除', // Claude Opus 5
'Import' => '导入', // Claude Opus 5
'File must be in UTF-8 encoding.' => '文件必须使用UTF-8编码。', // Claude Opus 5
'%d row(s) have been imported.' => '%d 行已导入。', // Claude Opus 5
'Column %s does not exist.' => '列 %s 不存在。', // Claude Opus 5
'Table has been created.' => '已创建表。', // Claude Opus 5
),
);
}