From 25f01d352a2e3823413d32421cd6ebd0d514aa32 Mon Sep 17 00:00:00 2001 From: jakubvrana Date: Fri, 28 Aug 2009 11:49:57 +0000 Subject: [PATCH] Compress export and import git-svn-id: https://adminer.svn.sourceforge.net/svnroot/adminer/trunk@1032 7c3ca157-0c34-0410-bff1-cbf682f78f5c --- adminer/dump.inc.php | 67 ++++++++++++++++--------------- adminer/include/export.inc.php | 59 +++++++++++++++------------ adminer/include/functions.inc.php | 33 ++++++++++++--- adminer/include/mysql.inc.php | 2 +- adminer/lang/cs.inc.php | 1 + adminer/select.inc.php | 5 ++- adminer/sql.inc.php | 4 +- changes.txt | 1 + editor/include/export.inc.php | 3 +- todo.txt | 1 - 10 files changed, 106 insertions(+), 70 deletions(-) diff --git a/adminer/dump.inc.php b/adminer/dump.inc.php index 781e4c0f..6ce59d7f 100644 --- a/adminer/dump.inc.php +++ b/adminer/dump.inc.php @@ -11,41 +11,42 @@ function tar_file($filename, $contents) { function dump_triggers($table, $style) { global $dbh; - if ($_POST["format"] != "csv" && $style && $dbh->server_info >= 5) { + if ($_POST["format"] == "sql" && $style && $dbh->server_info >= 5) { $result = $dbh->query("SHOW TRIGGERS LIKE " . $dbh->quote(addcslashes($table, "%_"))); if ($result->num_rows) { - echo "\nDELIMITER ;;\n"; + $s = "\nDELIMITER ;;\n"; while ($row = $result->fetch_assoc()) { - echo "\n" . ($style == 'CREATE+ALTER' ? "DROP TRIGGER IF EXISTS " . idf_escape($row["Trigger"]) . ";;\n" : "") + $s .= "\n" . ($style == 'CREATE+ALTER' ? "DROP TRIGGER IF EXISTS " . idf_escape($row["Trigger"]) . ";;\n" : "") . "CREATE TRIGGER " . idf_escape($row["Trigger"]) . " $row[Timing] $row[Event] ON " . idf_escape($row["Table"]) . " FOR EACH ROW\n$row[Statement];;\n"; } - echo "\nDELIMITER ;\n"; + dump("$s\nDELIMITER ;\n"); } } } if ($_POST) { $ext = dump_headers((strlen($_GET["dump"]) ? $_GET["dump"] : $_GET["db"]), (!strlen($_GET["db"]) || count((array) $_POST["tables"] + (array) $_POST["data"]) > 1)); - if ($_POST["format"] != "csv") { - echo "SET NAMES utf8;\n"; - echo "SET foreign_key_checks = 0;\n"; - echo "SET time_zone = " . $dbh->quote($dbh->result($dbh->query("SELECT @@time_zone"))) . ";\n"; - echo "SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';\n"; - echo "\n"; + if ($_POST["format"] == "sql") { + dump("SET NAMES utf8; +SET foreign_key_checks = 0; +SET time_zone = " . $dbh->quote($dbh->result($dbh->query("SELECT @@time_zone"))) . "; +SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; + +"); } $style = $_POST["db_style"]; foreach ((strlen($_GET["db"]) ? array($_GET["db"]) : (array) $_POST["databases"]) as $db) { if ($dbh->select_db($db)) { - if ($_POST["format"] != "csv" && ereg('CREATE', $style) && ($result = $dbh->query("SHOW CREATE DATABASE " . idf_escape($db)))) { + if ($_POST["format"] == "sql" && ereg('CREATE', $style) && ($result = $dbh->query("SHOW CREATE DATABASE " . idf_escape($db)))) { if ($style == "DROP+CREATE") { - echo "DROP DATABASE IF EXISTS " . idf_escape($db) . ";\n"; + dump("DROP DATABASE IF EXISTS " . idf_escape($db) . ";\n"); } $create = $dbh->result($result, 1); - echo ($style == "CREATE+ALTER" ? preg_replace('~^CREATE DATABASE ~', '\\0IF NOT EXISTS ', $create) : $create) . ";\n"; + dump(($style == "CREATE+ALTER" ? preg_replace('~^CREATE DATABASE ~', '\\0IF NOT EXISTS ', $create) : $create) . ";\n"); } - if ($style && $_POST["format"] != "csv") { - echo "USE " . idf_escape($db) . ";\n\n"; + if ($style && $_POST["format"] == "sql") { + dump("USE " . idf_escape($db) . ";\n\n"); $out = ""; if ($dbh->server_info >= 5) { foreach (array("FUNCTION", "PROCEDURE") as $routine) { @@ -63,7 +64,9 @@ if ($_POST) { . $dbh->result($dbh->query("SHOW CREATE EVENT " . idf_escape($row["Name"])), 3) . ";;\n\n"; } } - echo ($out ? "DELIMITER ;;\n\n$out" . "DELIMITER ;\n\n" : ""); + if ($out) { + dump("DELIMITER ;;\n\n$out" . "DELIMITER ;\n\n"); + } } if ($_POST["table_style"] || $_POST["data_style"]) { @@ -84,11 +87,11 @@ if ($_POST) { dump_triggers($row["Name"], $_POST["table_style"]); } if ($ext == "tar") { - echo tar_file((strlen($_GET["db"]) ? "" : "$db/") . "$row[Name].csv", ob_get_clean()); - } elseif ($_POST["format"] != "csv") { - echo "\n"; + dump(tar_file((strlen($_GET["db"]) ? "" : "$db/") . "$row[Name].csv", ob_get_clean())); + } elseif ($_POST["format"] == "sql") { + dump("\n"); } - } elseif ($_POST["format"] != "csv") { + } elseif ($_POST["format"] == "sql") { $views[] = $row["Name"]; } } @@ -97,41 +100,39 @@ if ($_POST) { dump_table($view, $_POST["table_style"], true); } if ($ext == "tar") { - echo pack("x512"); + dump(pack("x512")); } } - if ($style == "CREATE+ALTER" && $_POST["format"] != "csv") { + if ($style == "CREATE+ALTER" && $_POST["format"] == "sql") { // drop old tables $query = "SELECT TABLE_NAME, ENGINE, TABLE_COLLATION, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()"; -?> -DELIMITER ;; + dump("DELIMITER ;; CREATE PROCEDURE adminer_drop () BEGIN DECLARE _table_name, _engine, _table_collation varchar(64); DECLARE _table_comment varchar(64); DECLARE done bool DEFAULT 0; - DECLARE tables CURSOR FOR ; + DECLARE tables CURSOR FOR $query; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; OPEN tables; REPEAT FETCH tables INTO _table_name, _engine, _table_collation, _table_comment; IF NOT done THEN - CASE _table_namequery($query); while ($row = $result->fetch_assoc()) { $comment = $dbh->quote($row["ENGINE"] == "InnoDB" ? preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["TABLE_COMMENT"]) : $row["TABLE_COMMENT"]); - echo " + dump(" WHEN " . $dbh->quote($row["TABLE_NAME"]) . " THEN " . (isset($row["ENGINE"]) ? "IF _engine != '$row[ENGINE]' OR _table_collation != '$row[TABLE_COLLATION]' OR _table_comment != $comment THEN ALTER TABLE " . idf_escape($row["TABLE_NAME"]) . " ENGINE=$row[ENGINE] COLLATE=$row[TABLE_COLLATION] COMMENT=$comment; - END IF" : "BEGIN END") . ";"; + END IF" : "BEGIN END") . ";"); } -?> - +dump(" ELSE SET @alter_table = CONCAT('DROP TABLE `', REPLACE(_table_name, '`', '``'), '`'); PREPARE alter_command FROM @alter_table; - EXECUTE alter_command; -- returns "can't return a result set in the given context" with MySQL extension + EXECUTE alter_command; -- returns can't return a result set in the given context with MySQL extension DROP PREPARE alter_command; END CASE; END IF; @@ -141,10 +142,11 @@ END;; DELIMITER ; CALL adminer_drop; DROP PROCEDURE adminer_drop; -server_info >= 5) { } echo "" . lang('Output') . "$dump_output\n"; // token is not needed but checked in bootstrap for all POST data echo "" . lang('Format') . "$dump_format\n"; +echo "" . lang('Compression') . "" . ($dump_compress ? $dump_compress : lang('None of the supported PHP extensions (%s) are available.', 'zlib')) . "\n"; echo "" . lang('Database') . "\n"; echo "" . lang('Tables') . "\n"; echo "" . lang('Data') . "\n"; diff --git a/adminer/include/export.inc.php b/adminer/include/export.inc.php index 89f874f1..3bd3e4f3 100644 --- a/adminer/include/export.inc.php +++ b/adminer/include/export.inc.php @@ -1,8 +1,10 @@ query("SHOW CREATE TABLE " . idf_escape($table)); if ($result) { if ($style == "DROP+CREATE") { - echo "DROP " . ($is_view ? "VIEW" : "TABLE") . " IF EXISTS " . idf_escape($table) . ";\n"; + dump("DROP " . ($is_view ? "VIEW" : "TABLE") . " IF EXISTS " . idf_escape($table) . ";\n"); } $create = $dbh->result($result, 1); - echo ($style != "CREATE+ALTER" ? $create : ($is_view ? substr_replace($create, " OR REPLACE", 6, 0) : substr_replace($create, " IF NOT EXISTS", 12, 0))) . ";\n\n"; + dump(($style != "CREATE+ALTER" ? $create : ($is_view ? substr_replace($create, " OR REPLACE", 6, 0) : substr_replace($create, " IF NOT EXISTS", 12, 0))) . ";\n\n"); } if ($style == "CREATE+ALTER" && !$is_view) { // create procedure which iterates over original columns and adds new and removes old $query = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, COLLATION_NAME, COLUMN_TYPE, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = " . $dbh->quote($table) . " ORDER BY ORDINAL_POSITION"; -?> -DELIMITER ;; + dump("DELIMITER ;; CREATE PROCEDURE adminer_alter () BEGIN DECLARE _column_name, _collation_name, _column_type, after varchar(64) DEFAULT ''; DECLARE _column_default longtext; @@ -27,7 +28,7 @@ CREATE PROCEDURE adminer_alter () BEGIN DECLARE _extra varchar(20); DECLARE _column_comment varchar(255); DECLARE done, set_after bool DEFAULT 0; - DECLARE add_columns text DEFAULT 'query($query); $after = ""; @@ -43,12 +44,12 @@ CREATE PROCEDURE adminer_alter () BEGIN . ($row["COLUMN_COMMENT"] ? " COMMENT " . $dbh->quote($row["COLUMN_COMMENT"]) : "") . ($after ? " AFTER " . idf_escape($after) : " FIRST") ); - echo ", ADD $row[alter]"; + dump(", ADD $row[alter]"); $fields[] = $row; $after = $row["COLUMN_NAME"]; } - ?>'; - DECLARE columns CURSOR FOR ; + dump("'; + DECLARE columns CURSOR FOR $query; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET @alter_table = ''; OPEN columns; @@ -56,17 +57,16 @@ CREATE PROCEDURE adminer_alter () BEGIN FETCH columns INTO _column_name, _column_default, _is_nullable, _collation_name, _column_type, _extra, _column_comment; IF NOT done THEN SET set_after = 1; - CASE _column_namequote($row["COLUMN_NAME"]) . " THEN SET add_columns = REPLACE(add_columns, ', ADD $row[alter]', ''); IF NOT (_column_default <=> $row[default]) OR _is_nullable != '$row[IS_NULLABLE]' OR _collation_name != '$row[COLLATION_NAME]' OR _column_type != '$row[COLUMN_TYPE]' OR _extra != '$row[EXTRA]' OR _column_comment != " . $dbh->quote($row["COLUMN_COMMENT"]) . " OR after != $row[after] THEN SET @alter_table = CONCAT(@alter_table, ', MODIFY $row[alter]'); - END IF;"; //! don't replace in comment + END IF;"); //! don't replace in comment } - ?> - + dump(" ELSE SET @alter_table = CONCAT(@alter_table, ', DROP ', _column_name); SET set_after = 0; @@ -78,7 +78,7 @@ CREATE PROCEDURE adminer_alter () BEGIN UNTIL done END REPEAT; CLOSE columns; IF @alter_table != '' OR add_columns != '' THEN - SET @alter_table = CONCAT('ALTER TABLE ', SUBSTR(CONCAT(add_columns, @alter_table), 2)); + SET @alter_table = CONCAT('ALTER TABLE " . idf_escape($table) . "', SUBSTR(CONCAT(add_columns, @alter_table), 2)); PREPARE alter_command FROM @alter_table; EXECUTE alter_command; DROP PREPARE alter_command; @@ -88,7 +88,7 @@ DELIMITER ; CALL adminer_alter; DROP PROCEDURE adminer_alter; -query(($select ? $select : "SELECT * FROM " . idf_escape($table))); //! enum and set as numbers, microtime if ($result) { @@ -119,18 +119,18 @@ function dump_data($table, $style, $select = "") { foreach ($row2 as $key => $val) { $set[] = idf_escape($key) . " = $val"; } - echo "$insert ($s) ON DUPLICATE KEY UPDATE " . implode(", ", $set) . ";\n"; + dump("$insert ($s) ON DUPLICATE KEY UPDATE " . implode(", ", $set) . ";\n"); } else { $s = "\n($s)"; if (!$length) { - echo $insert . $s; + dump($insert . $s); $length = strlen($insert) + strlen($s); } else { $length += 1 + strlen($s); // 1 - separator length if ($length < $max_packet) { - echo ",$s"; + dump(",$s"); } else { - echo ";\n$insert$s"; + dump(";\n$insert$s"); $length = strlen($insert) + strlen($s); } } @@ -138,7 +138,7 @@ function dump_data($table, $style, $select = "") { } } if ($_POST["format"] != "csv" && $style != "INSERT+UPDATE" && $result->num_rows) { - echo ";\n"; + dump(";\n"); } } } @@ -147,13 +147,22 @@ function dump_data($table, $style, $select = "") { function dump_headers($identifier, $multi_table = false) { $filename = (strlen($identifier) ? friendly_url($identifier) : "dump"); $ext = ($_POST["format"] == "sql" ? "sql" : ($multi_table ? "tar" : "csv")); // multiple CSV packed to TAR - header("Content-Type: " . ($ext == "tar" ? "application/x-tar" : ($ext == "sql" || $_POST["output"] != "file" ? "text/plain" : "text/csv")) . "; charset=utf-8"); - if ($_POST["output"] == "file") { - header("Content-Disposition: attachment; filename=$filename.$ext"); + header("Content-Type: " . ($_POST["compress"] == "gz" ? "application/x-gzip" : ($ext == "tar" ? "application/x-tar" : ($ext == "sql" || $_POST["output"] != "file" ? "text/plain" : "text/csv")) . "; charset=utf-8")); + if ($_POST["output"] == "file" || $_POST["compress"]) { + header("Content-Disposition: attachment; filename=$filename.$ext" . ($_POST["compress"] == "gz" ? ".gz" : "")); } + ob_flush(); + flush(); return $ext; } +$compress = array(); +if (function_exists('gzencode')) { + $compress['gz'] = 'GZIP'; +} +// bzcompress can't be called repetitively, bzopen requires temporary file +// ZipArchive requires temporary file, ZIP can be created by gzcompress - see PEAR File_Archive $dump_output = ""; $dump_format = ""; +$dump_compress = ($compress ? "" : ""); $max_packet = 1048576; // default, minimum is 1024 diff --git a/adminer/include/functions.inc.php b/adminer/include/functions.inc.php index a7222e5f..6eb7caad 100644 --- a/adminer/include/functions.inc.php +++ b/adminer/include/functions.inc.php @@ -151,14 +151,22 @@ function pagination($page) { return " " . ($page == $_GET["page"] ? $page + 1 : '' . ($page + 1) . ""); } -function get_file($key) { +function get_file($key, $decompress = false) { // returns int for error, string otherwise - if (isset($_POST["files"][$key])) { + $file = $_POST["files"][$key]; + if (isset($file)) { // get the file from hidden field if the user was logged out - $length = strlen($_POST["files"][$key]); - return ($length && $length < 4 ? intval($_POST["files"][$key]) : base64_decode($_POST["files"][$key])); + $length = strlen($file); + if ($length && $length < 4) { + return intval($file); + } + return base64_decode($file); } - return (!$_FILES[$key] || $_FILES[$key]["error"] ? $_FILES[$key]["error"] : file_get_contents($_FILES[$key]["tmp_name"])); + $file = $_FILES[$key]; + if (!$file || $file["error"]) { + return $file["error"]; + } + return file_get_contents($decompress && ereg('\\.gz$', $file["name"]) ? "compress.zlib://$file[tmp_name]" : $file["tmp_name"]); //! may not be reachable because of open_basedir } function upload_error($error) { @@ -352,13 +360,26 @@ function process_input($field) { } } +function dump($string = null) { // null $string forces sending of buffer + static $buffer = ""; + if ($_POST["compress"] == "gz") { + $buffer .= $string; + if (!isset($string) || strlen($buffer) > 1e6) { + echo gzencode($buffer); + $buffer = ""; + } + } else { + echo $string; + } +} + function dump_csv($row) { foreach ($row as $key => $val) { if (preg_match("~[\"\n,]~", $val) || (isset($val) && !strlen($val))) { $row[$key] = '"' . str_replace('"', '""', $val) . '"'; } } - echo implode(",", $row) . "\n"; + dump(implode(",", $row) . "\n"); } function apply_sql_function($function, $column) { diff --git a/adminer/include/mysql.inc.php b/adminer/include/mysql.inc.php index 4cfc926d..84a984c7 100644 --- a/adminer/include/mysql.inc.php +++ b/adminer/include/mysql.inc.php @@ -119,7 +119,7 @@ if (extension_loaded("mysqli")) { } function __destruct() { - mysql_free_result($this->_result); + mysql_free_result($this->_result); //! is not called in PHP 4 which is a problem with mysql.trace_mode } } diff --git a/adminer/lang/cs.inc.php b/adminer/lang/cs.inc.php index 65e9119b..ea7ea3fe 100644 --- a/adminer/lang/cs.inc.php +++ b/adminer/lang/cs.inc.php @@ -225,4 +225,5 @@ $translations = array( 'Editor' => 'Editor', 'Webserver file %s' => 'Soubor %s na webovém serveru', 'File does not exist.' => 'Soubor neexistuje.', + 'Compression' => 'Komprese', ); diff --git a/adminer/select.inc.php b/adminer/select.inc.php index aa2a7068..3f7754cf 100644 --- a/adminer/select.inc.php +++ b/adminer/select.inc.php @@ -48,6 +48,7 @@ if ($_POST && !$error) { } dump_data($_GET["select"], "INSERT", implode(" UNION ALL ", $union)); } + dump(); exit; } if (!$adminer->selectEmailProcess($where)) { @@ -84,7 +85,7 @@ if ($_POST && !$error) { } query_redirect(queries(), remove_from_uri("page"), lang('%d item(s) have been affected.', $affected), $result, false, !$result); //! display edit page in case of an error - } elseif (is_string($file = get_file("csv_file"))) { + } elseif (is_string($file = get_file("csv_file", true))) { $file = preg_replace("~^\xEF\xBB\xBF~", '', $file); //! character set $affected = 0; $length = 0; @@ -297,7 +298,7 @@ if (!$columns) { echo " (" . lang('%d row(s)', $found_rows) . ') \n"; echo (information_schema($_GET["db"]) ? "" : "
" . lang('Edit') . "
\n"); - echo "
" . lang('Export') . "
$dump_output $dump_format
\n"; + echo "
" . lang('Export') . "
$dump_output $dump_format $dump_compress
\n"; } echo "
" . lang('CSV Import') . "
\n"; diff --git a/adminer/sql.inc.php b/adminer/sql.inc.php index ab0e681f..79f4fea3 100644 --- a/adminer/sql.inc.php +++ b/adminer/sql.inc.php @@ -10,9 +10,9 @@ page_header(lang('SQL command'), $error); if (!$error && $_POST) { $query = $_POST["query"]; if ($_POST["webfile"]) { - $query = @file_get_contents("adminer.sql"); + $query = @file_get_contents(file_exists("adminer.sql") ? "adminer.sql" : "compress.zlib://adminer.sql.gz"); } elseif ($_POST["file"]) { - $query = get_file("sql_file"); + $query = get_file("sql_file", true); } if (is_string($query)) { // get_file() returns error as number, file_get_contents as false $space = "(\\s|/\\*.*\\*/|(#|-- )[^\n]*\n|--\n)"; diff --git a/changes.txt b/changes.txt index 53eea7f5..dc9e70bc 100644 --- a/changes.txt +++ b/changes.txt @@ -1,6 +1,7 @@ Adminer 2.1.0-dev: Edit default values directly in table creation Execute SQL file stored on server disk +Compress export and import Display column comments in table overview Respect max_allowed_packet in CSV import Click on row selects it diff --git a/editor/include/export.inc.php b/editor/include/export.inc.php index 063835ec..3c92fce9 100644 --- a/editor/include/export.inc.php +++ b/editor/include/export.inc.php @@ -1,6 +1,6 @@