From 64ba92421bdb5a9a5360ca0857e7b282051c9172 Mon Sep 17 00:00:00 2001 From: jakubvrana Date: Sun, 21 Jun 2009 23:20:32 +0000 Subject: [PATCH] Comments git-svn-id: https://adminer.svn.sourceforge.net/svnroot/adminer/trunk@729 7c3ca157-0c34-0410-bff1-cbf682f78f5c --- adminer/create.inc.php | 1 + adminer/createv.inc.php | 2 +- adminer/database.inc.php | 42 ++++++++++++++++--------------- adminer/db.inc.php | 2 +- adminer/dump.inc.php | 1 + adminer/edit.inc.php | 2 +- adminer/foreign.inc.php | 2 +- adminer/include/auth.inc.php | 6 ++--- adminer/include/connect.inc.php | 2 +- adminer/include/design.inc.php | 3 ++- adminer/include/editing.inc.php | 4 ++- adminer/include/export.inc.php | 7 +++--- adminer/include/functions.inc.php | 24 ++++++++++++------ adminer/include/lang.inc.php | 6 +++-- adminer/include/mysql.inc.php | 12 ++++++--- adminer/include/pdo.inc.php | 4 ++- adminer/index.php | 8 ++++++ adminer/privileges.inc.php | 4 ++- adminer/procedure.inc.php | 2 +- adminer/schema.inc.php | 8 +++--- adminer/select.inc.php | 27 ++++++++++++-------- adminer/sql.inc.php | 16 ++++++------ adminer/table.inc.php | 6 ++--- adminer/trigger.inc.php | 1 + adminer/user.inc.php | 8 +++--- compile.php | 31 ++++++++++++++--------- coverage.php | 3 +++ lang.php | 11 +++++--- todo.txt | 1 - 29 files changed, 153 insertions(+), 93 deletions(-) diff --git a/adminer/create.inc.php b/adminer/create.inc.php index 09c1a800..a335f3bf 100644 --- a/adminer/create.inc.php +++ b/adminer/create.inc.php @@ -10,6 +10,7 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"] && !$_POST["up"] query_redirect("DROP TABLE " . idf_escape($_GET["create"]), substr($SELF, 0, -1), lang('Table has been dropped.')); } else { $auto_increment_index = " PRIMARY KEY"; + // don't overwrite primary key by auto_increment if (strlen($_GET["create"]) && strlen($_POST["fields"][$_POST["auto_increment_col"]]["orig"])) { foreach (indexes($_GET["create"]) as $index) { foreach ($index["columns"] as $column) { diff --git a/adminer/createv.inc.php b/adminer/createv.inc.php index 4113df84..6222016d 100644 --- a/adminer/createv.inc.php +++ b/adminer/createv.inc.php @@ -24,7 +24,7 @@ if ($_POST) {

- + : " maxlength="64" /> /> diff --git a/adminer/database.inc.php b/adminer/database.inc.php index f15f09f7..ca968472 100644 --- a/adminer/database.inc.php +++ b/adminer/database.inc.php @@ -1,14 +1,15 @@ escape_string($_POST["collation"]) . "'" : ""))) { $failed = true; } @@ -29,6 +30,7 @@ if ($_POST && !$error && !$_POST["add_x"]) { query_redirect(queries(), preg_replace('~db=[^&]*&~', '', $SELF) . "db=" . urlencode($_POST["name"]), lang('Database has been renamed.'), !$row, false, $row); } } else { + // alter database if (!$_POST["collation"]) { redirect(substr($SELF, 0, -1)); } @@ -43,25 +45,25 @@ $collate = array(); if ($_POST) { $name = $_POST["name"]; $collate = $_POST["collation"]; -} else { - if (!strlen($_GET["db"])) { - $result = $dbh->query("SHOW GRANTS"); - while ($row = $result->fetch_row()) { - if (preg_match('~ ON (`(([^\\\\`]+|``|\\\\.)*)%`\\.\\*)?~', $row[0], $match) && $match[1]) { - $name = stripcslashes(idf_unescape($match[2])); - break; - } +} elseif (!strlen($_GET["db"])) { + // propose database name with limited privileges + $result = $dbh->query("SHOW GRANTS"); + while ($row = $result->fetch_row()) { + if (preg_match('~ ON (`(([^\\\\`]+|``|\\\\.)*)%`\\.\\*)?~', $row[0], $match) && $match[1]) { + $name = stripcslashes(idf_unescape($match[2])); + break; } - $result->free(); - } elseif (($result = $dbh->query("SHOW CREATE DATABASE " . idf_escape($_GET["db"])))) { - $create = $dbh->result($result, 1); - if (preg_match('~ COLLATE ([^ ]+)~', $create, $match)) { - $collate = $match[1]; - } elseif (preg_match('~ CHARACTER SET ([^ ]+)~', $create, $match)) { - $collate = $collations[$match[1]][0]; - } - $result->free(); } + $result->free(); +} elseif (($result = $dbh->query("SHOW CREATE DATABASE " . idf_escape($_GET["db"])))) { + $create = $dbh->result($result, 1); + if (preg_match('~ COLLATE ([^ ]+)~', $create, $match)) { + $collate = $match[1]; + } elseif (preg_match('~ CHARACTER SET ([^ ]+)~', $create, $match)) { + // default collation + $collate = $collations[$match[1]][0]; + } + $result->free(); } ?> diff --git a/adminer/db.inc.php b/adminer/db.inc.php index 818b6ff4..24f72f74 100644 --- a/adminer/db.inc.php +++ b/adminer/db.inc.php @@ -4,7 +4,7 @@ $tables_views = array_merge((array) $_POST["tables"], (array) $_POST["views"]); if ($tables_views && !$error) { $result = true; $message = ""; - $dbh->query("SET foreign_key_checks = 0"); + $dbh->query("SET foreign_key_checks = 0"); // allows to truncate or drop several tables at once if (isset($_POST["truncate"])) { if ($_POST["tables"]) { foreach ($_POST["tables"] as $table) { diff --git a/adminer/dump.inc.php b/adminer/dump.inc.php index c94af665..195ade11 100644 --- a/adminer/dump.inc.php +++ b/adminer/dump.inc.php @@ -104,6 +104,7 @@ if ($_POST) { } if ($style == "CREATE+ALTER" && $_POST["format"] != "csv") { + // drop old tables $query = "SELECT TABLE_NAME, ENGINE, TABLE_COLLATION, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()"; ?> DELIMITER ;; diff --git a/adminer/edit.inc.php b/adminer/edit.inc.php index 9cba7773..138bae04 100644 --- a/adminer/edit.inc.php +++ b/adminer/edit.inc.php @@ -8,7 +8,7 @@ foreach ($fields as $name => $field) { } } if ($_POST && !$error && !isset($_GET["select"])) { - $location = ($_POST["insert"] ? $_SERVER["REQUEST_URI"] : $SELF . (isset($_GET["default"]) ? "table=" : "select=") . urlencode($_GET["edit"])); + $location = ($_POST["insert"] ? $_SERVER["REQUEST_URI"] : $SELF . (isset($_GET["default"]) ? "table=" : "select=") . urlencode($_GET["edit"])); // "insert" to continue edit or insert if (isset($_POST["delete"])) { query_redirect("DELETE FROM " . idf_escape($_GET["edit"]) . " WHERE " . implode(" AND ", $where) . " LIMIT 1", $location, lang('Item has been deleted.')); } else { diff --git a/adminer/foreign.inc.php b/adminer/foreign.inc.php index 28cfc26b..35f508b2 100644 --- a/adminer/foreign.inc.php +++ b/adminer/foreign.inc.php @@ -4,7 +4,7 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["change"] && !$_POST["change- query_redirect("ALTER TABLE " . idf_escape($_GET["foreign"]) . "\nDROP FOREIGN KEY " . idf_escape($_GET["name"]), $SELF . "table=" . urlencode($_GET["foreign"]), lang('Foreign key has been dropped.')); } else { $source = array_filter($_POST["source"], 'strlen'); - ksort($source); + ksort($source); // enforce input order $target = array(); foreach ($source as $key => $val) { $target[$key] = $_POST["target"][$key]; diff --git a/adminer/include/auth.inc.php b/adminer/include/auth.inc.php index 85f70d5b..5faee0c5 100644 --- a/adminer/include/auth.inc.php +++ b/adminer/include/auth.inc.php @@ -6,10 +6,10 @@ if (ini_get("session.use_trans_sid") && isset($_POST[$session_name])) { } if (isset($_POST["server"])) { if (isset($_COOKIE[$session_name]) || isset($_POST[$session_name])) { - session_regenerate_id(); + session_regenerate_id(); // defense against session fixation $_SESSION["usernames"][$_POST["server"]] = $_POST["username"]; $_SESSION["passwords"][$_POST["server"]] = $_POST["password"]; - $_SESSION["tokens"][$_POST["server"]] = rand(1, 1e6); + $_SESSION["tokens"][$_POST["server"]] = rand(1, 1e6); // defense against cross-site request forgery if (count($_POST) == count($ignore)) { $location = ((string) $_GET["server"] === $_POST["server"] ? remove_from_uri() : preg_replace('~^[^?]*/([^?]*).*~', '\\1', $_SERVER["REQUEST_URI"]) . (strlen($_POST["server"]) ? '?server=' . urlencode($_POST["server"]) : '')); if (!isset($_COOKIE[$session_name])) { @@ -66,7 +66,7 @@ function auth_error($exception = null) { $username = &$_SESSION["usernames"][$_GET["server"]]; if (!isset($username)) { - $username = $_GET["username"]; + $username = $_GET["username"]; // default username can be passed in URL } $dbh = (isset($username) ? connect() : ''); unset($username); diff --git a/adminer/include/connect.inc.php b/adminer/include/connect.inc.php index ef17bc87..7f406348 100644 --- a/adminer/include/connect.inc.php +++ b/adminer/include/connect.inc.php @@ -20,7 +20,7 @@ if (!(strlen($_GET["db"]) ? $dbh->select_db($_GET["db"]) : isset($_GET["sql"]) | if (strlen($_GET["db"])) { unset($_SESSION["databases"][$_GET["server"]]); } - connect_error(); + connect_error(); // separate function to catch SQLite error exit; } $dbh->query("SET CHARACTER SET utf8"); diff --git a/adminer/include/design.inc.php b/adminer/include/design.inc.php index 42e272b3..41f6a6ff 100644 --- a/adminer/include/design.inc.php +++ b/adminer/include/design.inc.php @@ -47,6 +47,7 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") { $databases = null; } if (isset($databases) && !isset($_GET["sql"]) && !isset($_SESSION["coverage"])) { + // improves concurrency if a user opens several pages at once session_write_close(); } if ($error) { @@ -55,7 +56,7 @@ function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") { } function page_footer($missing = false) { - global $SELF, $dbh, $VERSION; + global $SELF, $VERSION, $dbh; ?> diff --git a/adminer/include/editing.inc.php b/adminer/include/editing.inc.php index fe5f50ac..72e4268b 100644 --- a/adminer/include/editing.inc.php +++ b/adminer/include/editing.inc.php @@ -26,6 +26,7 @@ function input($name, $field, $value, $separator = "") { //! pass empty $options = (preg_match('~char~', $field["type"]) ? array("", "md5", "sha1", "password", "uuid") : array("", "now")); } if (!isset($_GET["call"]) && (isset($_GET["select"]) || where($_GET))) { + // relative functions if (preg_match('~int|float|double|decimal~', $field["type"])) { $options = array("", "+", "-"); } @@ -55,6 +56,7 @@ function input($name, $field, $value, $separator = "") { //! pass empty } elseif (preg_match('~binary|blob~', $field["type"])) { echo (ini_get("file_uploads") ? '' : lang('File uploads are disabled.') . ' '); } else { + // int(3) is only a display hint $maxlength = (!ereg('int', $field["type"]) && preg_match('~^([0-9]+)(,([0-9]+))?$~', $field["length"], $match) ? ($match[1] + ($match[3] ? 1 : 0) + ($match[2] && !$field["unsigned"] ? 1 : 0)) : ($types[$field["type"]] ? $types[$field["type"]] + ($field["unsigned"] ? 0 : 1) : 0)); echo ''; } @@ -87,7 +89,7 @@ function process_input($name, $field) { } elseif (preg_match('~^[+-]$~', $function)) { return idf_escape($name) . " $function '" . $dbh->escape_string($value) . "'"; } elseif (preg_match('~^[+-] interval$~', $function)) { - return idf_escape($name) . " $function " . (preg_match("~^([0-9]+|'[0-9.: -]') [A-Z_]+$~i", $value) ? $value : "'" . $dbh->escape_string($value) . "'") . ""; + return idf_escape($name) . " $function " . (preg_match("~^([0-9]+|'[0-9.: -]') [A-Z_]+$~i", $value) ? $value : "'" . $dbh->escape_string($value) . "'"); } elseif (preg_match('~^(addtime|subtime)$~', $function)) { return "$function(" . idf_escape($name) . ", '" . $dbh->escape_string($value) . "')"; } elseif (preg_match('~^(md5|sha1|password)$~', $function)) { diff --git a/adminer/include/export.inc.php b/adminer/include/export.inc.php index 4b166698..b747dabb 100644 --- a/adminer/include/export.inc.php +++ b/adminer/include/export.inc.php @@ -11,7 +11,7 @@ function dump_csv($row) { function dump_table($table, $style, $is_view = false) { global $dbh; if ($_POST["format"] == "csv") { - echo "\xef\xbb\xbf"; + echo "\xef\xbb\xbf"; // UTF-8 byte order mark if ($style) { dump_csv(array_keys(fields($table))); } @@ -26,6 +26,7 @@ function dump_table($table, $style, $is_view = false) { echo ($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->escape_string($table) . "' ORDER BY ORDINAL_POSITION"; ?> DELIMITER ;; @@ -131,7 +132,7 @@ function dump_data($table, $style, $select = "") { } else { $s = "\n(" . implode(", ", $row2) . ")"; if (!$length) { - echo $insert, $s; + echo $insert, $s; // comma used to save memory $length = strlen($insert) + strlen($s); } else { $length += 2 + strlen($s); @@ -155,7 +156,7 @@ 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")); + $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"); diff --git a/adminer/include/functions.inc.php b/adminer/include/functions.inc.php index 974b187e..262e3228 100644 --- a/adminer/include/functions.inc.php +++ b/adminer/include/functions.inc.php @@ -8,6 +8,7 @@ function idf_unescape($idf) { } function bracket_escape($idf, $back = false) { + // escape brackets inside name="x[]" static $trans = array(':' => ':1', ']' => ':2', '[' => ':3'); return strtr($idf, ($back ? array_flip($trans) : $trans)); } @@ -46,7 +47,7 @@ function unique_idf($row, $indexes) { if ($index["type"] == "PRIMARY" || $index["type"] == "UNIQUE") { $return = array(); foreach ($index["columns"] as $key) { - if (!isset($row[$key])) { + if (!isset($row[$key])) { // NULL is ambiguous continue 2; } $return[] = urlencode("where[" . bracket_escape($key) . "]") . "=" . urlencode($row[$key]); @@ -90,6 +91,7 @@ function redirect($location, $message = null) { $_SESSION["messages"][] = $message; } if (strlen(SID)) { + // append SID if session cookies are disabled $location .= (strpos($location, "?") === false ? "?" : "&") . SID; } header("Location: " . (strlen($location) ? $location : ".")); @@ -121,6 +123,7 @@ function queries($query = null) { global $dbh; static $queries = array(); if (!isset($query)) { + // return executed queries without parameter return implode(";\n", $queries); } $queries[] = $query; @@ -137,7 +140,9 @@ function print_page($page) { } function get_file($key) { + // returns int for error, string otherwise if (isset($_POST["files"][$key])) { + // 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])); } @@ -158,12 +163,12 @@ function select($result, $dbh2 = null) { echo "

" . lang('No rows.') . "

\n"; } else { echo "\n"; - $links = array(); - $indexes = array(); - $columns = array(); - $blobs = array(); - $types = array(); - odd(''); + $links = array(); // colno => orgtable - create links from these columns + $indexes = array(); // orgtable => array(column => colno) - primary keys + $columns = array(); // orgtable => array(column => ) - not selected columns in primary key + $blobs = array(); // colno => bool - display bytes for blobs + $types = array(); // colno => type - display char in + odd(''); // reset odd for each result for ($i=0; $row = $result->fetch_row(); $i++) { if (!$i) { echo ""; @@ -171,6 +176,7 @@ function select($result, $dbh2 = null) { $field = $result->fetch_field(); if (strlen($field->orgtable)) { if (!isset($indexes[$field->orgtable])) { + // find primary key in each table $indexes[$field->orgtable] = array(); foreach (indexes($field->orgtable, $dbh2) as $index) { if ($index["type"] == "PRIMARY") { @@ -202,7 +208,7 @@ function select($result, $dbh2 = null) { if ($blobs[$key] && !is_utf8($val)) { $val = "" . lang('%d byte(s)', strlen($val)) . ""; //! link to download } elseif (!strlen(trim($val))) { - $val = " "; + $val = " "; // some content to print a border } else { $val = nl2br(htmlspecialchars($val)); if ($types[$key] == 254) { @@ -227,6 +233,7 @@ function select($result, $dbh2 = null) { } function is_utf8($val) { + // don't print control chars except \t\r\n return (preg_match('~~u', $val) && !preg_match('~[\\0-\\x8\\xB\\xC\\xE-\\x1F]~', $val)); } @@ -236,6 +243,7 @@ function shorten_utf8($string, $length = 80, $suffix = "") { } function friendly_url($val) { + // used for blobs and export return preg_replace('~[^a-z0-9_]~i', '-', $val); } diff --git a/adminer/include/lang.inc.php b/adminer/include/lang.inc.php index 36a58277..b62c1cda 100644 --- a/adminer/include/lang.inc.php +++ b/adminer/include/lang.inc.php @@ -1,4 +1,6 @@ 'English', // Jakub Vrána - http://php.vrana.cz 'cs' => 'Čeština', // Jakub Vrána - http://php.vrana.cz @@ -17,7 +19,7 @@ function lang($idf, $number = null) { global $LANG, $translations; $translation = $translations[$idf]; if (is_array($translation) && $translation) { - $pos = ($number == 1 ? 0 : ((!$number || $number >= 5) && ereg('cs|sk|ru', $LANG) ? 2 : 1)); + $pos = ($number == 1 ? 0 : ((!$number || $number >= 5) && ereg('cs|sk|ru', $LANG) ? 2 : 1)); // Slavic languages use different form for 2, 3, 4 $translation = $translation[$pos]; } $args = func_get_args(); @@ -38,7 +40,7 @@ function switch_lang() { if (isset($_GET["lang"])) { $_COOKIE["lang"] = $_GET["lang"]; - $_SESSION["lang"] = $_GET["lang"]; + $_SESSION["lang"] = $_GET["lang"]; // cookies may be disabled } $LANG = "en"; diff --git a/adminer/include/mysql.inc.php b/adminer/include/mysql.inc.php index 1cf6f9fa..e51417af 100644 --- a/adminer/include/mysql.inc.php +++ b/adminer/include/mysql.inc.php @@ -1,4 +1,5 @@ real_connect( (strlen($server) ? $host : ini_get("mysqli.default_host")), (strlen("$server$username") ? $username : ini_get("mysqli.default_user")), @@ -33,6 +34,7 @@ if (extension_loaded("mysqli")) { } function query($query) { + // result is packed in envelope object to allow minification $result = parent::query($query); return (is_object($result) ? new Min_Result($result) : $result); } @@ -126,6 +128,7 @@ if (extension_loaded("mysqli")) { } function next_result() { + // MySQL extension doesn't support multiple results return false; } @@ -187,6 +190,7 @@ if (extension_loaded("mysqli")) { exit; } +// value means maximum unsigned length $types = array( "tinyint" => 3, "smallint" => 5, "mediumint" => 8, "int" => 10, "bigint" => 20, "float" => 12, "double" => 21, "decimal" => 66, @@ -205,6 +209,7 @@ function connect() { } function get_databases() { + // SHOW DATABASES can take very long so it is cached $return = &$_SESSION["databases"][$_GET["server"]]; if (!isset($return)) { flush(); @@ -216,7 +221,7 @@ function get_databases() { function table_status($table) { global $dbh; $result = $dbh->query("SHOW TABLE STATUS LIKE '" . $dbh->escape_string(addcslashes($table, "%_")) . "'"); - $return = $result->fetch_assoc(); + $return = $result->fetch_assoc(); // ()-> is not supported in PHP 4 $result->free(); return $return; } @@ -250,7 +255,7 @@ function fields($table) { function indexes($table, $dbh2 = null) { global $dbh; - if (!is_object($dbh2)) { + if (!is_object($dbh2)) { // use the main connection if the separate connection is unavailable $dbh2 = $dbh; } $return = array(); @@ -313,6 +318,7 @@ function collations() { function table_comment(&$row) { if ($row["Engine"] == "InnoDB") { + // ignore internal comment, unnecessary since MySQL 5.1.21 $row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["Comment"]); } } diff --git a/adminer/include/pdo.inc.php b/adminer/include/pdo.inc.php index e7962d22..c3ae935a 100644 --- a/adminer/include/pdo.inc.php +++ b/adminer/include/pdo.inc.php @@ -1,4 +1,5 @@ query("USE " . idf_escape($database)); } @@ -29,7 +31,7 @@ if (extension_loaded('pdo')) { $this->affected_rows = $result->rowCount(); return true; } - $result->num_rows = $result->rowCount(); + $result->num_rows = $result->rowCount(); // is not guaranteed to work with all drivers return $result; } diff --git a/adminer/index.php b/adminer/index.php index 46c39b8e..547bc7ed 100644 --- a/adminer/index.php +++ b/adminer/index.php @@ -8,11 +8,13 @@ error_reporting(E_ALL & ~E_NOTICE); if (!ini_get("session.auto_start")) { + // use specific session name to get own namespace session_name("adminer_sid"); session_set_cookie_params(0, preg_replace('~\\?.*~', '', $_SERVER["REQUEST_URI"])); session_start(); } if (isset($_SESSION["coverage"])) { + // coverage is used in tests and removed in compilation function save_coverage() { foreach (xdebug_get_code_coverage() as $filename => $lines) { foreach ($lines as $l => $val) { @@ -25,9 +27,11 @@ if (isset($_SESSION["coverage"])) { xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); register_shutdown_function('save_coverage'); if ($_GET["start"]) { + // included from ../coverage.php return; } } +// disable magic quotes to be able to use database escaping function if (get_magic_quotes_gpc()) { $process = array(&$_GET, &$_POST, &$_COOKIE); while (list($key, $val) = each($process)) { @@ -83,12 +87,15 @@ if (isset($_GET["download"])) { $error = lang('Invalid CSRF token. Send the form again.'); } } elseif ($_SERVER["REQUEST_METHOD"] == "POST") { + // posted form with no data means exceeded post_max_size because Adminer always sends token at least $error = lang('Too big POST data. Reduce the data or increase the "post_max_size" configuration directive.'); } if (isset($_GET["default"])) { + // edit form is used for default values and distinguished by checking isset($_GET["default"]) in edit.inc.php $_GET["edit"] = $_GET["default"]; } if (isset($_GET["select"]) && $_POST && (!$_POST["delete"] && !$_POST["export"] && !$_POST["import"] && !$_POST["save"])) { + // POST form on select page is used to edit or clone data $_GET["edit"] = $_GET["select"]; } if (isset($_GET["callf"])) { @@ -131,4 +138,5 @@ if (isset($_GET["download"])) { include "./db.inc.php"; } } +// each page calls its own page_header(), if the footer should not be called then the page exits page_footer(); diff --git a/adminer/privileges.inc.php b/adminer/privileges.inc.php index c026b378..9506aa5f 100644 --- a/adminer/privileges.inc.php +++ b/adminer/privileges.inc.php @@ -3,6 +3,7 @@ page_header(lang('Privileges')); echo '

' . lang('Create user') . "

"; $result = $dbh->query("SELECT User, Host FROM mysql.user ORDER BY Host, User"); if (!$result) { + //! utilize information_schema.USER_PRIVILEGES in MySQL 5 ?>

" /> @@ -12,12 +13,13 @@ if (!$result) {

query("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', 1) AS User, SUBSTRING_INDEX(CURRENT_USER, '@', -1) AS Host"); } echo "
\n"; echo "\n"; while ($row = $result->fetch_assoc()) { - echo '\n"; + echo '\n"; } echo "
 " . lang('Username') . "" . lang('Server') . "
' . lang('edit') . '' . htmlspecialchars($row["User"]) . "" . htmlspecialchars($row["Host"]) . "
' . lang('edit') . '' . htmlspecialchars($row["User"]) . "" . htmlspecialchars($row["Host"]) . "
\n"; $result->free(); diff --git a/adminer/procedure.inc.php b/adminer/procedure.inc.php index 2b9d198b..8029cb98 100644 --- a/adminer/procedure.inc.php +++ b/adminer/procedure.inc.php @@ -9,7 +9,7 @@ if ($_POST && !$error && !$_POST["add"] && !$_POST["drop_col"] && !$_POST["up"] if (!$_POST["drop"]) { $set = array(); $fields = array_filter((array) $_POST["fields"], 'strlen'); - ksort($fields); + ksort($fields); // enforce fields order foreach ($fields as $field) { if (strlen($field["field"])) { $set[] = (in_array($field["inout"], $inout) ? "$field[inout] " : "") . idf_escape($field["field"]) . process_type($field, "CHARACTER SET"); diff --git a/adminer/schema.inc.php b/adminer/schema.inc.php index 2728ae99..89fd50ce 100644 --- a/adminer/schema.inc.php +++ b/adminer/schema.inc.php @@ -3,6 +3,7 @@ page_header(lang('Database schema'), "", array(), $_GET["db"]); $table_pos = array(); $table_pos_js = array(); +// saved in one cookie because there is a limit of 20 cookies per domain preg_match_all('~([^:]+):([-0-9.]+)x([-0-9.]+)(_|$)~', $_COOKIE["schema"], $matches, PREG_SET_ORDER); //! ':' in table name foreach ($matches as $i => $match) { $table_pos[$match[1]] = array($match[2], $match[3]); @@ -11,9 +12,9 @@ foreach ($matches as $i => $match) { $top = 0; $base_left = -1; -$schema = array(); -$referenced = array(); -$lefts = array(); +$schema = array(); // table => array("fields" => array(name => field), "pos" => array(top, left), "references" => array(table => array(left => array(source, target)))) +$referenced = array(); // target_table => array(table => array(left => target_column)) +$lefts = array(); // float => bool $result = $dbh->query("SHOW TABLE STATUS"); while ($row = $result->fetch_assoc()) { if (!isset($row["Engine"])) { // view @@ -37,6 +38,7 @@ while ($row = $result->fetch_assoc()) { $base_left -= .1; } while ($lefts[(string) $left]) { + // find free $left $left -= .0001; } $schema[$row["Name"]]["references"][$val["table"]][(string) $left] = array($val["source"], $val["target"]); diff --git a/adminer/select.inc.php b/adminer/select.inc.php index b9c2374a..60a22949 100644 --- a/adminer/select.inc.php +++ b/adminer/select.inc.php @@ -1,6 +1,6 @@ ", "<=", ">=", "!=", "LIKE", "REGEXP", "IN", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL"); @@ -8,8 +8,8 @@ if (eregi('^(MyISAM|Maria)$', $table_status["Engine"])) { $operators[] = "AGAINST"; } $fields = fields($_GET["select"]); -$rights = array(); -$columns = array(); +$rights = array(); // privilege => 0 +$columns = array(); // selectable columns unset($text_length); foreach ($fields as $key => $field) { if (isset($field["privileges"]["select"])) { @@ -21,8 +21,8 @@ foreach ($fields as $key => $field) { $rights += $field["privileges"]; } -$select = array(); -$group = array(); +$select = array(); // select expressions, empty for * +$group = array(); // expressions without aggregation - will be used for GROUP BY if an aggregation function is used foreach ((array) $_GET["columns"] as $key => $val) { if ($val["fun"] == "count" || (in_array($val["col"], $columns, true) && (!$val["fun"] || in_array($val["fun"], $functions) || in_array($val["fun"], $grouping)))) { $select[$key] = (in_array($val["col"], $columns, true) ? (!$val["fun"] ? idf_escape($val["col"]) : ($val["fun"] == "distinct" ? "COUNT(DISTINCT " : strtoupper("$val[fun](")) . idf_escape($val["col"]) . ")") : "COUNT(*)"); @@ -31,7 +31,7 @@ foreach ((array) $_GET["columns"] as $key => $val) { } } } -$where = array(); +$where = array(); // where expressions - will be joined by AND foreach ($indexes as $i => $index) { if ($index["type"] == "FULLTEXT" && strlen($_GET["fulltext"][$i])) { $where[] = "MATCH (" . implode(", ", array_map('idf_escape', $index["columns"])) . ") AGAINST ('" . $dbh->escape_string($_GET["fulltext"][$i]) . "'" . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")"; @@ -48,6 +48,7 @@ foreach ((array) $_GET["where"] as $val) { if (strlen($val["col"])) { $where[] = idf_escape($val["col"]) . $cond; } else { + // find anywhere $cols = array(); foreach ($fields as $name => $field) { if (is_numeric($val["val"]) || !ereg('int|float|double|decimal', $field["type"])) { @@ -59,7 +60,7 @@ foreach ((array) $_GET["where"] as $val) { } } } -$order = array(); +$order = array(); // order expressions - will be joined by comma foreach ((array) $_GET["order"] as $key => $val) { if (in_array($val, $columns, true) || in_array($val, $select, true)) { $order[] = idf_escape($val) . (isset($_GET["desc"][$key]) ? " DESC" : ""); @@ -76,6 +77,7 @@ if ($_POST && !$error) { if (is_array($_POST["check"])) { $union = array(); foreach ($_POST["check"] as $val) { + // where may not be unique so OR can't be used $union[] = "($query WHERE " . implode(" AND ", where_check($val)) . " LIMIT 1)"; } dump_data($_GET["select"], "INSERT", implode(" UNION ALL ", $union)); @@ -108,6 +110,7 @@ if ($_POST && !$error) { } else { foreach ((array) $_POST["check"] as $val) { parse_str($val, $check); + // where may not be unique so OR can't be used $result = queries($command . " WHERE " . implode(" AND ", where($check)) . " LIMIT 1"); if (!$result) { break; @@ -126,15 +129,16 @@ if ($_POST && !$error) { $row = array(); preg_match_all('~(("[^"]*")+|[^,]*),~', "$val,", $matches2); if (!$key && !array_diff($matches2[1], array_keys($fields))) { //! doesn't work with column names containing ",\n + // first row corresponds to column names - use it for table structure $cols = " (" . implode(", ", array_map('idf_escape', $matches2[1])) . ")"; } else { foreach ($matches2[1] as $col) { $row[] = (!strlen($col) ? "NULL" : "'" . $dbh->escape_string(str_replace('""', '"', preg_replace('~^".*"$~s', '', $col))) . "'"); } - $rows[] = "(" . implode(", ", $row) . ")"; + $rows[] = "\n(" . implode(", ", $row) . ")"; } } - $result = queries("INSERT INTO " . idf_escape($_GET["select"]) . "$cols VALUES " . implode(", ", $rows)); + $result = queries("INSERT INTO " . idf_escape($_GET["select"]) . "$cols VALUES" . implode(",", $rows)); query_redirect(queries(), remove_from_uri("page"), lang('%d row(s) has been imported.', $dbh->affected_rows), $result, false, !$result); } else { $error = lang('Unable to upload a file.'); @@ -209,7 +213,7 @@ if (!$columns) { echo "\n"; echo "\n"; - echo "
" . lang('Limit') . "
"; + echo "
" . lang('Limit') . "
"; //
for easy styling echo ""; echo "
\n"; @@ -271,6 +275,7 @@ if (!$columns) { } foreach ((array) $foreign_keys[$key] as $foreign_key) { if (count($foreign_keys[$key]) == 1 || count($foreign_key["source"]) == 1) { + // link related items $val = "\">$val"; foreach ($foreign_key["source"] as $i => $source) { $val = "&where%5B$i%5D%5Bcol%5D=" . urlencode($foreign_key["target"][$i]) . "&where%5B$i%5D%5Bop%5D=%3D&where%5B$i%5D%5Bval%5D=" . urlencode($row[$source]) . $val; @@ -287,11 +292,13 @@ if (!$columns) { echo "\n"; echo "

"; + // use num_rows without LIMIT, COUNT(*) without grouping, FOUND_ROWS otherwise (slowest) $found_rows = (intval($limit) ? $dbh->result($dbh->query(count($group) < count($select) ? " SELECT FOUND_ROWS()" // space to allow mysql.trace_mode : "SELECT COUNT(*) FROM " . idf_escape($_GET["select"]) . ($where ? " WHERE " . implode(" AND ", $where) : "") )) : $result->num_rows); if (intval($limit) && $found_rows > $limit) { + // display first, previous 3, next 3 and last page $max_page = floor(($found_rows - 1) / $limit); echo lang('Page') . ":"; print_page(0); diff --git a/adminer/sql.inc.php b/adminer/sql.inc.php index 50dd417c..b103f7b4 100644 --- a/adminer/sql.inc.php +++ b/adminer/sql.inc.php @@ -3,11 +3,11 @@ page_header(lang('SQL command'), $error); $history = &$_SESSION["history"][$_GET["server"]][$_GET["db"]]; if (!$error && $_POST) { - if (is_string($query = (isset($_POST["file"]) ? get_file("sql_file") : $_POST["query"]))) { - @set_time_limit(0); - $query = str_replace("\r", "", $query); + if (is_string($query = (isset($_POST["file"]) ? get_file("sql_file") : $_POST["query"]))) { // get_file() returns error as number + @set_time_limit(0); // set_time_limit() can be disabled + $query = str_replace("\r", "", $query); // parser looks for \n $query = rtrim($query); - if (strlen($query) && $history[count($history) - 1] != $query) { + if (strlen($query) && $history[count($history)-1] != $query) { // don't add repeated $history[] = $query; } $delimiter = ";"; @@ -24,14 +24,15 @@ if (!$error && $_POST) { $query = substr($query, strlen($match[0])); } elseif (preg_match('(' . preg_quote($delimiter) . '|[\'`"]|/\\*|-- |#|$)', $query, $match, PREG_OFFSET_CAPTURE, $offset)) { if ($match[0][0] && $match[0][0] != $delimiter) { + // is not end of a query - find closing part $pattern = ($match[0][0] == "-- " || $match[0][0] == "#" ? '~.*~' : ($match[0][0] == "/*" ? '~.*\\*/~sU' : '~\\G([^\\\\' . $match[0][0] . ']+|\\\\.)*(' . $match[0][0] . '|$)~s')); preg_match($pattern, $query, $match, PREG_OFFSET_CAPTURE, $match[0][1] + 1); $offset = $match[0][1] + strlen($match[0][0]); } else { $empty = false; echo "

" . shorten_utf8(trim(substr($query, 0, $match[0][1]))) . "
\n"; - flush(); - $start = explode(" ", microtime()); + flush(); // can take a long time - show the running query + $start = explode(" ", microtime()); // microtime(true) is available since PHP 5 //! don't allow changing of character_set_results, convert encoding of displayed query if (!$dbh->multi_query(substr($query, 0, $match[0][1]))) { echo "

" . lang('Error in query') . ": " . htmlspecialchars($dbh->error) . "

\n"; @@ -47,7 +48,7 @@ if (!$error && $_POST) { select($result, $dbh2); } else { if (preg_match("~^$space*(CREATE|DROP)$space+(DATABASE|SCHEMA)\\b~isU", $query)) { - unset($_SESSION["databases"][$_GET["server"]]); + unset($_SESSION["databases"][$_GET["server"]]); // clear cache } echo "

" . lang('Query executed OK, %d row(s) affected.', $dbh->affected_rows) . "

\n"; } @@ -89,6 +90,7 @@ if (!ini_get("file_uploads")) { if ($history) { echo "
" . lang('History') . "\n"; foreach ($history as $key => $val) { + //! save and display timestamp echo '' . lang('Edit') . ' ' . shorten_utf8(str_replace("\n", " ", $val), 80, "") . "
\n"; } echo "
\n"; diff --git a/adminer/table.inc.php b/adminer/table.inc.php index 682730bd..fcd05d82 100644 --- a/adminer/table.inc.php +++ b/adminer/table.inc.php @@ -30,7 +30,7 @@ if ($result) { if ($indexes) { echo "\n"; foreach ($indexes as $index) { - ksort($index["columns"]); + ksort($index["columns"]); // enforce correct columns order $print = array(); foreach ($index["columns"] as $key => $val) { $print[] = "" . htmlspecialchars($val) . "" . ($index["lengths"][$key] ? "(" . $index["lengths"][$key] . ")" : ""); @@ -47,12 +47,12 @@ if ($result) { if ($foreign_keys) { echo "
\n"; foreach ($foreign_keys as $name => $foreign_key) { + $link = (strlen($foreign_key["db"]) ? "" . htmlspecialchars($foreign_key["db"]) . "." : "") . htmlspecialchars($foreign_key["table"]); echo ""; echo ""; - $link = (strlen($foreign_key["db"]) ? "" . htmlspecialchars($foreign_key["db"]) . "." : "") . htmlspecialchars($foreign_key["table"]); echo '"; - echo ''; + echo ""; echo "\n"; } echo "
" . implode(", ", array_map('htmlspecialchars', $foreign_key["source"])) . "$link"; echo "(" . implode(", ", array_map('htmlspecialchars', $foreign_key["target"])) . ")' . (!strlen($foreign_key["db"]) ? '' . lang('Alter') . '' : ' ') . '" . (!strlen($foreign_key["db"]) ? '' . lang('Alter') . '' : ' ') . "
\n"; diff --git a/adminer/trigger.inc.php b/adminer/trigger.inc.php index 9a86fdf9..abb30ff8 100644 --- a/adminer/trigger.inc.php +++ b/adminer/trigger.inc.php @@ -21,6 +21,7 @@ if ($_POST) { } elseif (strlen($_GET["name"])) { $result = $dbh->query("SHOW TRIGGERS LIKE '" . $dbh->escape_string(addcslashes($_GET["trigger"], "%_")) . "'"); while ($row = $result->fetch_assoc()) { + // LIKE is used to compare the table name if ($row["Trigger"] === $_GET["name"]) { break; } diff --git a/adminer/user.inc.php b/adminer/user.inc.php index 59fa922c..77d20d15 100644 --- a/adminer/user.inc.php +++ b/adminer/user.inc.php @@ -12,13 +12,13 @@ while ($row = $result->fetch_assoc()) { } $result->free(); $privileges["Server Admin"] += $privileges["File access on server"]; -$privileges["Databases"]["Create routine"] = $privileges["Procedures"]["Create routine"]; +$privileges["Databases"]["Create routine"] = $privileges["Procedures"]["Create routine"]; // MySQL bug #30305 +unset($privileges["Procedures"]["Create routine"]); $privileges["Columns"] = array(); foreach (array("Select", "Insert", "Update", "References") as $val) { $privileges["Columns"][$val] = $privileges["Tables"][$val]; } unset($privileges["Server Admin"]["Usage"]); -unset($privileges["Procedures"]["Create routine"]); foreach ($privileges["Tables"] as $key => $val) { unset($privileges["Databases"][$key]); } @@ -72,6 +72,7 @@ if ($_POST && !$error) { } $grant = array_keys($grant); if (isset($_GET["grant"])) { + // no rights to mysql.user table $revoke = array_diff(array_keys(array_filter($new_grants[$object], 'strlen')), $grant); } elseif ($old_user == $new_user) { $old_grant = array_keys((array) $grants[$object]); @@ -111,7 +112,7 @@ if ($_POST) { $row = $_POST; $grants = $new_grants; } else { - $row = $_GET + array("host" => "localhost"); + $row = $_GET + array("host" => "localhost"); // create user on localhost by default $row["pass"] = $old_pass; if (strlen($old_pass)) { $row["hashed"] = true; @@ -134,7 +135,6 @@ echo "" . lang('Privileges') . ""; $i = 0; foreach ($grants as $object => $grant) { echo '' . ($object != "*.*" ? '' : '*.*') . ''; //! separate db, table, columns, PROCEDURE|FUNCTION, routine - //! JS checkbox for all $i++; } echo "\n"; diff --git a/compile.php b/compile.php index 237d74e8..fde6bee7 100644 --- a/compile.php +++ b/compile.php @@ -10,13 +10,13 @@ function remove_lang($match) { global $translations; $idf = strtr($match[2], array("\\'" => "'", "\\\\" => "\\")); $s = ($translations[$idf] ? $translations[$idf] : $idf); - if ($match[3] == ",") { + if ($match[3] == ",") { // lang() has parameters return "$match[1]" . (is_array($s) ? "lang(array('" . implode("', '", array_map('add_apo_slashes', $s)) . "')," : "sprintf('" . add_apo_slashes($s) . "',"); } return ($match[1] && $match[4] ? $s : "$match[1]'" . add_apo_slashes($s) . "'$match[4]"); } -$lang_ids = array(); +$lang_ids = array(); // global variable simplifies usage in a callback function function lang_ids($match) { global $lang_ids; return 'lang(' . $lang_ids[stripslashes($match[1])] . $match[2]; @@ -30,6 +30,7 @@ function put_file($match) { } $return = ""; foreach (glob(dirname(__FILE__) . "/adminer/lang/*.inc.php") as $filename) { + // assign translation numbers include $filename; foreach ($translations as $key => $val) { if (!isset($lang_ids[$key])) { @@ -38,7 +39,7 @@ function put_file($match) { } } foreach (glob(dirname(__FILE__) . "/adminer/lang/*.inc.php") as $filename) { - include $filename; + include $filename; // reassign $translations $translation_ids = array_flip($lang_ids); foreach ($translations as $key => $val) { $translation_ids[$lang_ids[$key]] = $val; @@ -53,9 +54,10 @@ function put_file($match) { } $return = file_get_contents(dirname(__FILE__) . "/adminer/$match[2]"); if ($match[2] != "./include/lang.inc.php" || !$_COOKIE["lang"]) { - $tokens = token_get_all($return); + $tokens = token_get_all($return); // to find out the last token return "?>\n$return" . (in_array($tokens[count($tokens) - 1][0], array(T_CLOSE_TAG, T_INLINE_HTML), true) ? " $token) { @@ -101,9 +103,9 @@ function php_shrink($input) { foreach ($short_functions as $key => $val) { if (isset($defined_functions[$key])) { do { - $short_functions[$key] = short_identifier($number, implode("", range('a', 'z'))); + $short_functions[$key] = short_identifier($number, implode("", range('a', 'z'))); // _ not used to not collide with gettext() $number++; - } while (isset($short_functions[$short_functions[$key]])); + } while (isset($short_functions[$short_functions[$key]])); // don't overwrite existing functions } } @@ -129,6 +131,7 @@ function php_shrink($input) { } elseif ($token[1] == ';' && $in_echo) { $in_echo = false; if ($tokens[$i+1][0] === T_WHITESPACE && $tokens[$i+2][0] === T_ECHO) { + // join two consecutive echos next($tokens); next($tokens); $token[1] = '.'; //! join ''.'' and ""."" @@ -136,10 +139,13 @@ function php_shrink($input) { } elseif ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) { $token[1] = '$' . $short_variables[$token[1]]; } elseif ($token[0] === T_STRING && $tokens[$i+1] === '(' && isset($defined_functions[$token[1]]) - && $tokens[$i-1][0] !== T_DOUBLE_COLON && $tokens[$i-2][0] !== T_NEW && $tokens[$i-2][1] !== '_result' + && $tokens[$i-1][0] !== T_DOUBLE_COLON && $tokens[$i-2][0] !== T_NEW && $tokens[$i-2][1] !== '_result' // don't substitute parent methods - used to link PHP methods only ) { $token[1] = $short_functions[$token[1]]; - } elseif ($token[0] == T_CONSTANT_ENCAPSED_STRING && (($tokens[$i-1] === '(' && in_array($tokens[$i-2][1], array('array_map', 'set_exception_handler'), true)) || $token[1] == "'normalize_enum'") && isset($defined_functions[substr($token[1], 1, -1)])) { + } elseif ($token[0] == T_CONSTANT_ENCAPSED_STRING + && (($tokens[$i-1] === '(' && in_array($tokens[$i-2][1], array('array_map', 'set_exception_handler'), true)) || $token[1] == "'normalize_enum'") + && isset($defined_functions[substr($token[1], 1, -1)]) + ) { // minify callback functions too $token[1] = "'" . $short_functions[substr($token[1], 1, -1)] . "'"; } if (isset($set[substr($output, -1)]) || isset($set[$token[1]{0}])) { @@ -154,7 +160,7 @@ function php_shrink($input) { error_reporting(E_ALL & ~E_NOTICE); if ($_SERVER["argc"] > 1) { - $_COOKIE["lang"] = $_SERVER["argv"][1]; + $_COOKIE["lang"] = $_SERVER["argv"][1]; // Adminer functions read language from cookie include dirname(__FILE__) . "/adminer/include/lang.inc.php"; if ($_SERVER["argc"] != 2 || !isset($langs[$_COOKIE["lang"]])) { echo "Usage: php compile.php [lang]\nPurpose: Compile adminer[-lang].php from index.php.\n"; @@ -168,6 +174,7 @@ $file = file_get_contents(dirname(__FILE__) . "/adminer/index.php"); $file = preg_replace_callback('~\\b(include|require) "([^"]*)";~', 'put_file', $file); $file = preg_replace("~if \\(isset\\(\\\$_SESSION\\[\"coverage.*\n}\n| && !isset\\(\\\$_SESSION\\[\"coverage\"\\]\\)~sU", '', $file); if ($_COOKIE["lang"]) { + // single language version $file = preg_replace_callback("~(<\\?php\\s*echo )?lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])(;\\s*\\?>)?~s", 'remove_lang', $file); $file = str_replace("\n", "", $file); $file = str_replace('', $_COOKIE["lang"], $file); @@ -200,9 +207,9 @@ if (isset($_GET["file"])) { } } exit; -}', $file); +}', $file); // integrate static files $file = str_replace("../externals/jush/", "http://jush.sourceforge.net/", $file); $file = preg_replace("~<\\?php\\s*\\?>\n?|\\?>\n?<\\?php~", '', $file); $file = php_shrink($file); -fwrite(fopen($filename, "w"), $file); +fwrite(fopen($filename, "w"), $file); // file_put_contents() since PHP 5 echo "$filename created.\n"; diff --git a/coverage.php b/coverage.php index 249db92c..055261f3 100644 --- a/coverage.php +++ b/coverage.php @@ -7,6 +7,7 @@ if (!ini_get("session.auto_start")) { } function xhtml_open_tags($s) { + // returns array of opened tags in $s $return = array(); preg_match_all('~<([^>]+)~', $s, $matches); foreach ($matches[1] as $val) { @@ -32,6 +33,7 @@ if ($_GET["start"]) { exit; } if (preg_match('~^(include/)?[-_.a-z0-9]+$~i', $_GET["filename"])) { + // highlight single file $filename = "adminer/$_GET[filename]"; $cov = $_SESSION["coverage"][realpath($filename)]; $file = explode("
", highlight_file($filename, true)); @@ -61,6 +63,7 @@ if (preg_match('~^(include/)?[-_.a-z0-9]+$~i', $_GET["filename"])) { $s .= "$line
\n"; } } else { + // display list of files echo "\n"; foreach (array_merge(glob("adminer/*.php"), glob("adminer/include/*.php")) as $filename) { $cov = $_SESSION["coverage"][realpath($filename)]; diff --git a/lang.php b/lang.php index f9de597b..b82ad83d 100644 --- a/lang.php +++ b/lang.php @@ -1,10 +1,10 @@ 1) { - $_COOKIE["lang"] = $_SERVER["argv"][1]; + $_COOKIE["lang"] = $_SERVER["argv"][1]; // Adminer functions read language from cookie include dirname(__FILE__) . "/adminer/include/lang.inc.php"; if ($_SERVER["argc"] != 2 || !isset($langs[$_COOKIE["lang"]])) { - echo "Usage: php lang.php [lang]\nPurpose: Update lang/*.inc.php from source code messages.\n"; + echo "Usage: php lang.php [lang]\nPurpose: Update adminer/lang/*.inc.php from source code messages.\n"; exit(1); } } @@ -12,7 +12,7 @@ if ($_SERVER["argc"] > 1) { $messages_all = array(); foreach (array_merge(glob(dirname(__FILE__) . "/adminer/*.php"), glob(dirname(__FILE__) . "/adminer/include/*.php")) as $filename) { $file = file_get_contents($filename); - if (preg_match_all("~lang\\(('(?:[^\\\\']+|\\\\.)*')([),])~", $file, $matches)) { + if (preg_match_all("~lang\\(('(?:[^\\\\']+|\\\\.)*')([),])~", $file, $matches)) { // lang() always uses apostrophes $messages_all += array_combine($matches[1], $matches[2]); } } @@ -23,19 +23,22 @@ foreach (glob(dirname(__FILE__) . "/adminer/lang/" . ($_COOKIE["lang"] ? $_COOKI $s = ""; foreach ($matches as $match) { if (isset($messages[$match[3]])) { + // keep current messages $s .= "$match[1]$match[2],\n"; unset($messages[$match[3]]); } else { + // comment deprecated messages $s .= "$match[1]// $match[2],\n"; } } foreach($messages as $idf => $val) { + // add new messages if ($val == "," && strpos($idf, "%d")) { $s .= "\t$idf => array(),\n"; } elseif (basename($filename) != "en.inc.php") { $s .= "\t$idf => null,\n"; } } - fwrite(fopen($filename, "w"), "