}
$call[] = (isset($out[$key]) ? "@" . idf_escape($field["field"]) : $val);
}
- if (!$connection->multi_query((isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . idf_escape($PROCEDURE) . "(" . implode(", ", $call) . ")")) {
+ $query = (isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . idf_escape($PROCEDURE) . "(" . implode(", ", $call) . ")";
+ echo "<p><code class='jush-$driver'>" . h($query) . "</code> <a href='" . h(ME) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>\n";
+ if (!$connection->multi_query($query)) {
echo "<p class='error'>" . error() . "\n";
} else {
do {
echo "<table cellspacing='0'>\n";
foreach ($in as $key) {
$field = $routine["fields"][$key];
- echo "<tr><th>" . h($field["field"]);
- $value = $_POST["fields"][$key];
+ $name = $field["field"];
+ echo "<tr><th>" . h($name);
+ $value = $_POST["fields"][$name];
if ($value != "" && ereg("enum|set", $field["type"])) {
$value = intval($value);
}
if ($_POST["drop"]) {
query_redirect("DROP TABLE " . idf_escape($_GET["create"]), substr(ME, 0, -1), lang('Table has been dropped.'));
} else {
- $auto_increment_index = " PRIMARY KEY";
- // don't overwrite primary key by auto_increment
- if ($TABLE != "" && $_POST["auto_increment_col"]) {
- foreach (indexes($TABLE) as $index) {
- if (in_array($_POST["fields"][$_POST["auto_increment_col"]]["orig"], $index["columns"], true)) {
- $auto_increment_index = "";
- break;
- }
- if ($index["type"] == "PRIMARY") {
- $auto_increment_index = " UNIQUE";
- }
- }
- }
- $fields = "";
+ $fields = array();
+ $foreign = array();
ksort($_POST["fields"]);
$orig_field = reset($orig_fields);
$after = "FIRST";
$field["on_update"] = "CURRENT_TIMESTAMP";
$field["default"] = $default;
}
+ if ($key == $_POST["auto_increment_col"]) {
+ $field["auto_increment"] = true;
+ }
$process_field = process_field($field, $type_field);
- $auto_increment = ($key == $_POST["auto_increment_col"]);
- if ($process_field != process_field($orig_field, $orig_field) || $orig_field["auto_increment"] != $auto_increment) {
- $fields .= "\n" . ($TABLE != "" ? ($field["orig"] != "" ? "CHANGE " . idf_escape($field["orig"]) : "ADD") : " ")
- . " $process_field"
- . ($auto_increment ? " AUTO_INCREMENT$auto_increment_index" : "")
- . ($TABLE != "" ? " $after" : "") . ","
- ;
+ if ($process_field != process_field($orig_field, $orig_field)) {
+ $fields[] = array($field["orig"], $process_field, $after);
}
if (!isset($types[$field["type"]])) {
- $fields .= ($TABLE != "" ? "\nADD" : "") . " FOREIGN KEY (" . idf_escape($field["field"]) . ") REFERENCES " . idf_escape($foreign_keys[$field["type"]]) . " (" . idf_escape($type_field["field"]) . "),";
+ $foreign[] = ($TABLE != "" ? "ADD " : " ") . "FOREIGN KEY (" . idf_escape($field["field"]) . ") REFERENCES " . idf_escape($foreign_keys[$field["type"]]) . " (" . idf_escape($type_field["field"]) . ")";
}
}
$after = "AFTER " . idf_escape($field["field"]);
- //! drop and create foreign keys with renamed columns
} elseif ($field["orig"] != "") {
- $fields .= "\nDROP " . idf_escape($field["orig"]) . ",";
+ $fields[] = array($field["orig"]);
}
if ($field["orig"] != "") {
$orig_field = next($orig_fields);
}
}
- $status = "COMMENT=" . $connection->quote($_POST["Comment"])
- . ($_POST["Engine"] && $_POST["Engine"] != $orig_status["Engine"] ? " ENGINE=" . $connection->quote($_POST["Engine"]) : "")
- . ($_POST["Collation"] && $_POST["Collation"] != $orig_status["Collation"] ? " COLLATE " . $connection->quote($_POST["Collation"]) : "")
- . ($_POST["Auto_increment"] != "" ? " AUTO_INCREMENT=" . preg_replace('~[^0-9]+~', '', $_POST["Auto_increment"]) : "")
- ;
+ $partitioning = "";
if (in_array($_POST["partition_by"], $partition_by)) {
$partitions = array();
if ($_POST["partition_by"] == 'RANGE' || $_POST["partition_by"] == 'LIST') {
$partitions[] = "\nPARTITION " . idf_escape($val) . " VALUES " . ($_POST["partition_by"] == 'RANGE' ? "LESS THAN" : "IN") . ($value != "" ? " ($value)" : " MAXVALUE"); //! SQL injection
}
}
- $status .= "\nPARTITION BY $_POST[partition_by]($_POST[partition])" . ($partitions // $_POST["partition"] can be expression, not only column
+ $partitioning .= "\nPARTITION BY $_POST[partition_by]($_POST[partition])" . ($partitions // $_POST["partition"] can be expression, not only column
? " (" . implode(",", $partitions) . "\n)"
: ($_POST["partitions"] ? " PARTITIONS " . intval($_POST["partitions"]) : "")
);
- } elseif ($connection->server_info >= 5.1 && $TABLE != "") {
- $status .= "\nREMOVE PARTITIONING";
+ } elseif ($TABLE != "") {
+ $partitioning .= "\nREMOVE PARTITIONING";
}
- $location = ME . "table=" . urlencode($_POST["name"]);
- if ($TABLE != "") {
- query_redirect("ALTER TABLE " . idf_escape($TABLE) . "$fields\nRENAME TO " . idf_escape($_POST["name"]) . ",\n$status", $location, lang('Table has been altered.'));
- } else {
+ $message = lang('Table has been altered.');
+ if ($TABLE == "") {
cookie("adminer_engine", $_POST["Engine"]);
- query_redirect("CREATE TABLE " . idf_escape($_POST["name"]) . " (" . substr($fields, 0, -1) . "\n) $status", $location, lang('Table has been created.'));
+ $message = lang('Table has been created.');
}
+ queries_redirect(ME . "table=" . urlencode($_POST["name"]), $message, alter_table(
+ $TABLE,
+ $_POST["name"],
+ $fields,
+ $foreign,
+ $_POST["Comment"],
+ ($_POST["Engine"] && $_POST["Engine"] != $orig_status["Engine"] ? $_POST["Engine"] : ""),
+ ($_POST["Collation"] && $_POST["Collation"] != $orig_status["Collation"] ? $_POST["Collation"] : ""),
+ ($_POST["Auto_increment"] != "" ? preg_replace('~[^0-9]+~', '', $_POST["Auto_increment"]) : ""),
+ $partitioning
+ ));
}
}
}
$row["fields"][] = $field;
}
- if ($connection->server_info >= 5.1) {
+ if (support("partitioning")) {
$from = "FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = " . $connection->quote(DB) . " AND TABLE_NAME = " . $connection->quote($TABLE);
- $result = $connection->query("SELECT PARTITION_METHOD, PARTITION_ORDINAL_POSITION, PARTITION_EXPRESSION $from ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1");
+ $result = $connection->query("SELECT" . limit("PARTITION_METHOD, PARTITION_ORDINAL_POSITION, PARTITION_EXPRESSION $from ORDER BY PARTITION_ORDINAL_POSITION", 1));
list($row["partition_by"], $row["partitions"], $row["partition"]) = $result->fetch_row();
$row["partition_names"] = array();
$row["partition_values"] = array();
<p>
<?php echo lang('Table name'); ?>: <input name="name" maxlength="64" value="<?php echo h($row["name"]); ?>">
<?php echo ($engines ? html_select("Engine", array("" => "(" . lang('engine') . ")") + $engines, $row["Engine"]) : ""); ?>
- <?php echo html_select("Collation", array("" => "(" . lang('collation') . ")") + $collations, $row["Collation"]); ?>
+ <?php echo ($collations ? html_select("Collation", array("" => "(" . lang('collation') . ")") + $collations, $row["Collation"]) : ""); ?>
<input type="submit" value="<?php echo lang('Save'); ?>">
<table cellspacing="0" id="edit-fields" class="nowrap">
-<?php $column_comments = edit_fields($row["fields"], $collations, "TABLE", $suhosin, $foreign_keys); ?>
+<?php $comments = edit_fields($row["fields"], $collations, "TABLE", $suhosin, $foreign_keys, $row["Comment"] != ""); ?>
</table>
<p>
<?php echo lang('Auto Increment'); ?>: <input name="Auto_increment" size="6" value="<?php echo h($row["Auto_increment"]); ?>">
-<?php echo lang('Comment'); ?>: <input name="Comment" value="<?php echo h($row["Comment"]); ?>" maxlength="60">
<script type="text/javascript">
document.write('<label><input type="checkbox" onclick="columnShow(this.checked, 5);"><?php echo lang('Default values'); ?><\/label>');
-document.write('<label><input type="checkbox"<?php if ($column_comments) { ?> checked<?php } ?> onclick="columnShow(this.checked, 6);"><?php echo lang('Show column comments'); ?><\/label>');
</script>
+<?php echo (support("comment") ? checkbox("", "", $comments, lang('Comment'), "columnShow(this.checked, 6); toggle('Comment');") . ' <input id="Comment" name="Comment" value="' . h($row["Comment"]) . '" maxlength="60"' . ($comments ? '' : ' class="hidden"') . '>' : ''); ?>
<p>
<input type="hidden" name="token" value="<?php echo $token; ?>">
<input type="submit" value="<?php echo lang('Save'); ?>">
<?php if (strlen($_GET["create"])) { ?><input type="submit" name="drop" value="<?php echo lang('Drop'); ?>"<?php echo $confirm; ?>><?php } ?>
<?php
-if ($connection->server_info >= 5.1) {
+if (support("partitioning")) {
$partition_table = ereg('RANGE|LIST', $row["partition_by"]);
print_fieldset("partition", lang('Partition by'), $row["partition_by"]);
?>
if ($_POST && !$error && !isset($_POST["add_x"])) { // add is an image and PHP changes add.x to add_x
restart_session();
if ($_POST["drop"]) {
- unset($_SESSION["databases"][$_GET["server"]]);
+ set_session("databases", null);
query_redirect("DROP DATABASE " . idf_escape(DB), remove_from_uri("db|database"), lang('Database has been dropped.'));
} elseif (DB !== $_POST["name"]) {
// create or rename database
- unset($_SESSION["databases"][$_GET["server"]]); // clear cache
- $dbs = explode("\n", str_replace("\r", "", $_POST["name"]));
- $failed = false;
- $last = "";
- foreach ($dbs as $db) {
- if (count($dbs) == 1 || $db != "") { // ignore empty lines but always try to create single database
- if (!queries("CREATE DATABASE " . idf_escape($db) . ($_POST["collation"] ? " COLLATE " . $connection->quote($_POST["collation"]) : ""))) {
- $failed = true;
+ set_session("databases", null); // clear cache
+ if (DB != "") {
+ queries_redirect(preg_replace('~db=[^&]*&~', '', ME) . "db=" . urlencode($_POST["name"]), lang('Database has been renamed.'), rename_database($_POST["name"], $_POST["collation"]));
+ } else {
+ $dbs = explode("\n", str_replace("\r", "", $_POST["name"]));
+ $success = true;
+ $last = "";
+ foreach ($dbs as $db) {
+ if (count($dbs) == 1 || $db != "") { // ignore empty lines but always try to create single database
+ if (!queries("CREATE DATABASE " . idf_escape($db) . ($_POST["collation"] ? " COLLATE " . $connection->quote($_POST["collation"]) : ""))) {
+ $success = false;
+ }
+ $last = $db;
}
- $last = $db;
}
- }
- if (query_redirect(queries(), ME . "db=" . urlencode($last), lang('Database has been created.'), DB == "", false, $failed)) {
- //! move triggers
- $result = $connection->query("SHOW TABLES");
- while ($row = $result->fetch_row()) {
- if (!queries("RENAME TABLE " . idf_escape($row[0]) . " TO " . idf_escape($_POST["name"]) . "." . idf_escape($row[0]))) {
- break;
- }
- }
- if (!$row) {
- queries("DROP DATABASE " . idf_escape(DB));
- //! saved to history of removed database
- }
- queries_redirect(preg_replace('~db=[^&]*&~', '', ME) . "db=" . urlencode($_POST["name"]), lang('Database has been renamed.'), !$row);
+ queries_redirect(ME . "db=" . urlencode($last), lang('Database has been created.'), $success);
}
} else {
// alter database
if ($_POST) {
$name = $_POST["name"];
$collate = $_POST["collation"];
-} elseif (DB == "") {
+} elseif (DB != "") {
+ $collate = db_collation(DB, $collations);
+} elseif ($driver == "sql") {
// propose database name with limited privileges
- $result = $connection->query("SHOW GRANTS");
- while ($row = $result->fetch_row()) {
- if (preg_match('~ ON (`(([^\\\\`]|``|\\\\.)*)%`\\.\\*)?~', $row[0], $match) && $match[1]) {
- $name = stripcslashes(idf_unescape($match[2]));
+ foreach (get_vals("SHOW GRANTS") as $grant) {
+ if (preg_match('~ ON (`(([^\\\\`]|``|\\\\.)*)%`\\.\\*)?~', $grant, $match) && $match[1]) {
+ $name = stripcslashes(idf_unescape("`$match[2]`"));
break;
}
}
-} else {
- $collate = db_collation(DB, $collations);
}
?>
if ($tables_views && !$error && !$_POST["search"]) {
$result = true;
$message = "";
- if (count($_POST["tables"]) > 1 && ($_POST["drop"] || $_POST["truncate"])) {
+ if ($driver == "sql" && count($_POST["tables"]) > 1 && ($_POST["drop"] || $_POST["truncate"])) {
queries("SET foreign_key_checks = 0"); // allows to truncate or drop several tables at once
}
- if (isset($_POST["truncate"])) {
- foreach ((array) $_POST["tables"] as $table) {
- if (!queries("TRUNCATE " . idf_escape($table))) {
- $result = false;
- break;
- }
+ if ($_POST["truncate"]) {
+ if ($_POST["tables"]) {
+ $result = truncate_tables($_POST["tables"]);
}
$message = lang('Tables have been truncated.');
- } elseif (isset($_POST["move"])) {
+ } elseif ($_POST["move"]) {
$rename = array();
foreach ($tables_views as $table) {
$rename[] = idf_escape($table) . " TO " . idf_escape($_POST["target"]) . "." . idf_escape($table);
$result = queries("RENAME TABLE " . implode(", ", $rename));
//! move triggers
$message = lang('Tables have been moved.');
- } elseif ((!isset($_POST["drop"]) || !$_POST["views"] || queries("DROP VIEW " . implode(", ", array_map('idf_escape', $_POST["views"]))))
- && (!$_POST["tables"] || ($result = queries((isset($_POST["optimize"]) ? "OPTIMIZE" : (isset($_POST["check"]) ? "CHECK" : (isset($_POST["repair"]) ? "REPAIR" : (isset($_POST["drop"]) ? "DROP" : "ANALYZE")))) . " TABLE " . implode(", ", array_map('idf_escape', $_POST["tables"])))))
- ) {
- if (isset($_POST["drop"])) {
- $message = lang('Tables have been dropped.');
- } else {
- while ($row = $result->fetch_assoc()) {
- $message .= h("$row[Table]: $row[Msg_text]") . "<br>";
- }
+ } elseif ($_POST["drop"]) {
+ if ($_POST["views"]) {
+ $result = drop_views($_POST["views"]);
+ }
+ if ($result && $_POST["tables"]) {
+ $result = drop_tables($_POST["tables"]);
+ }
+ $message = lang('Tables have been dropped.');
+ } elseif ($_POST["tables"] && ($result = queries(($_POST["optimize"] ? "OPTIMIZE" : ($_POST["check"] ? "CHECK" : ($_POST["repair"] ? "REPAIR" : "ANALYZE"))) . " TABLE " . implode(", ", array_map('idf_escape', $_POST["tables"]))))) {
+ while ($row = $result->fetch_assoc()) {
+ $message .= h("$row[Table]: $row[Msg_text]") . "<br>";
}
}
queries_redirect(substr(ME, 0, -1), $message, $result);
}
-page_header(lang('Database') . ": " . h(DB), $error, false);
+page_header(lang('Database') . ": " . h(DB), $error, true);
echo '<p><a href="' . h(ME) . 'database=">' . lang('Alter database') . "</a>\n";
echo '<a href="' . h(ME) . 'schema=">' . lang('Database schema') . "</a>\n";
+$sums = array("Data_length" => 0, "Index_length" => 0, "Data_free" => 0);
echo "<h3>" . lang('Tables and views') . "</h3>\n";
-$table_status = table_status();
-if (!$table_status) {
+$tables_list = tables_list();
+if (!$tables_list) {
echo "<p class='message'>" . lang('No tables.') . "\n";
} else {
echo "<form action='' method='post'>\n";
echo "<p><input name='query' value='" . h($_POST["query"]) . "'> <input type='submit' name='search' value='" . lang('Search') . "'>\n";
if ($_POST["search"] && $_POST["query"] != "") {
- $_GET["where"][0]["op"] = "LIKE";
- $_GET["where"][0]["val"] = "%$_POST[query]%";
+ $_GET["where"][0]["op"] = "LIKE %%";
+ $_GET["where"][0]["val"] = $_POST["query"];
search_tables();
}
echo "<table cellspacing='0' class='nowrap' onclick='tableClick(event);'>\n";
- echo '<thead><tr class="wrap"><td><input id="check-all" type="checkbox" onclick="formCheck(this, /^(tables|views)\[/);"><th>' . lang('Table') . '<td>' . lang('Engine') . '<td>' . lang('Collation') . '<td>' . lang('Data Length') . '<td>' . lang('Index Length') . '<td>' . lang('Data Free') . '<td>' . lang('Auto Increment') . '<td>' . lang('Rows') . '<td>' . lang('Comment') . "</thead>\n";
- $sums = array();
- foreach ($table_status as $row) {
- $name = $row["Name"];
- echo '<tr' . odd() . '><td>' . checkbox((isset($row["Rows"]) ? "tables[]" : "views[]"), $name, in_array($name, $tables_views, true), "", "formUncheck('check-all');");
+ echo '<thead><tr class="wrap"><td><input id="check-all" type="checkbox" onclick="formCheck(this, /^(tables|views)\[/);"><th>' . lang('Table') . '<td>' . lang('Engine') . '<td>' . lang('Collation') . '<td>' . lang('Data Length') . '<td>' . lang('Index Length') . '<td>' . lang('Data Free') . '<td>' . lang('Auto Increment') . '<td>' . lang('Rows') . (support("comment") ? '<td>' . lang('Comment') : '') . "</thead>\n";
+ foreach ($tables_list as $name => $type) {
+ $view = (isset($type) && !eregi("table", $type));
+ echo '<tr' . odd() . '><td>' . checkbox(($view ? "views[]" : "tables[]"), $name, in_array($name, $tables_views, true), "", "formUncheck('check-all');");
echo '<th><a href="' . h(ME) . 'table=' . urlencode($name) . '">' . h($name) . '</a>';
- if (isset($row["Rows"])) {
- echo "<td>$row[Engine]<td>$row[Collation]";
- foreach (array("Data_length" => "create", "Index_length" => "indexes", "Data_free" => "edit", "Auto_increment" => "auto_increment=1&create", "Rows" => "select") as $key => $link) {
- $val = number_format($row[$key], 0, '.', lang(','));
- echo '<td align="right">' . ($row[$key] != "" ? '<a href="' . h(ME . "$link=") . urlencode($name) . '">' . str_replace(" ", " ", ($key == "Rows" && $row["Engine"] == "InnoDB" && $val ? lang('~ %s', $val) : $val)) . '</a>' : ' ');
- $sums[$link] += ($row["Engine"] != "InnoDB" || $link != "edit" ? $row[$key] : 0);
- }
- echo "<td>" . nbsp($row["Comment"]);
- } else {
+ if ($view) {
echo '<td colspan="6"><a href="' . h(ME) . "view=" . urlencode($name) . '">' . lang('View') . '</a>';
echo '<td align="right"><a href="' . h(ME) . "select=" . urlencode($name) . '">?</a>';
- echo '<td> ';
+ } else {
+ echo "<td id='Engine-" . h($name) . "'> <td id='Collation-" . h($name) . "'> ";
+ foreach (array("Data_length" => "create", "Index_length" => "indexes", "Data_free" => "edit", "Auto_increment" => "auto_increment=1&create", "Rows" => "select") as $key => $link) {
+ echo "<td align='right'><a href='" . h(ME . "$link=") . urlencode($name) . "' id='$key-" . h($name) . "'>?</a>";
+ }
}
+ echo (support("comment") ? "<td id='Comment-" . h($name) . "'> " : "");
}
- echo "<tr><td> <th>" . lang('%d in total', count($table_status));
- echo "<td>" . $connection->result($connection->query("SELECT @@storage_engine"));
+ echo "<tr><td> <th>" . lang('%d in total', count($tables_list));
+ echo "<td>" . $connection->result("SELECT @@storage_engine");
echo "<td>" . db_collation(DB, collations());
- foreach (array("create", "indexes", "edit") as $val) {
- echo "<td align='right'>" . number_format($sums[$val], 0, '.', lang(','));
+ foreach ($sums as $key => $val) {
+ echo "<td align='right' id='sum-$key'> ";
}
echo "</table>\n";
if (!information_schema(DB)) {
- echo "<p><input type='hidden' name='token' value='$token'><input type='submit' value='" . lang('Analyze') . "'> <input type='submit' name='optimize' value='" . lang('Optimize') . "'> <input type='submit' name='check' value='" . lang('Check') . "'> <input type='submit' name='repair' value='" . lang('Repair') . "'> <input type='submit' name='truncate' value='" . lang('Truncate') . "' onclick=\"return confirm('" . lang('Are you sure?') . " (' + formChecked(this, /tables/) + ')');\"> <input type='submit' name='drop' value='" . lang('Drop') . "' onclick=\"return confirm('" . lang('Are you sure?') . " (' + formChecked(this, /tables|views/) + ')');\">\n";
+ echo "<p><input type='hidden' name='token' value='$token'>" . ($driver == "sql" ? "<input type='submit' value='" . lang('Analyze') . "'> <input type='submit' name='optimize' value='" . lang('Optimize') . "'> <input type='submit' name='check' value='" . lang('Check') . "'> <input type='submit' name='repair' value='" . lang('Repair') . "'> " : "") . "<input type='submit' name='truncate' value='" . lang('Truncate') . "' onclick=\"return confirm('" . lang('Are you sure?') . " (' + formChecked(this, /tables/) + ')');\"> <input type='submit' name='drop' value='" . lang('Drop') . "' onclick=\"return confirm('" . lang('Are you sure?') . " (' + formChecked(this, /tables|views/) + ')');\">\n";
$dbs = get_databases();
if (count($dbs) != 1) {
$db = (isset($_POST["target"]) ? $_POST["target"] : DB);
}
echo '<p><a href="' . h(ME) . 'create=">' . lang('Create table') . "</a>\n";
-if ($connection->server_info >= 5) {
+if (support("view")) {
echo '<a href="' . h(ME) . 'view=">' . lang('Create view') . "</a>\n";
+}
+if (support("routine")) {
echo "<h3>" . lang('Routines') . "</h3>\n";
$result = $connection->query("SELECT * FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = " . $connection->quote(DB));
if ($result->num_rows) {
echo '<p><a href="' . h(ME) . 'procedure=">' . lang('Create procedure') . '</a> <a href="' . h(ME) . 'function=">' . lang('Create function') . "</a>\n";
}
-if ($connection->server_info >= 5.1 && ($result = $connection->query("SHOW EVENTS"))) {
+if (support("event")) {
echo "<h3>" . lang('Events') . "</h3>\n";
- if ($result->num_rows) {
+ $result = $connection->query("SHOW EVENTS");
+ if ($result && $result->num_rows) {
echo "<table cellspacing='0'>\n";
echo "<thead><tr><th>" . lang('Name') . "<td>" . lang('Schedule') . "<td>" . lang('Start') . "<td>" . lang('End') . "</thead>\n";
while ($row = $result->fetch_assoc()) {
}
echo '<p><a href="' . h(ME) . 'event=">' . lang('Create event') . "</a>\n";
}
+
+page_footer();
+$table_status = table_status();
+if ($table_status) {
+ echo "<script type='text/javascript'>\n";
+ foreach ($table_status as $row) {
+ $id = addcslashes($row["Name"], "\\'/");
+ echo "setHtml('Comment-$id', '" . nbsp($row["Comment"]) . "');\n";
+ if (!eregi("view", $row["Engine"])) {
+ foreach (array("Engine", "Collation") as $key) {
+ echo "setHtml('$key-$id', '" . nbsp($row[$key]) . "');\n";
+ }
+ foreach ($sums + array("Auto_increment" => 0, "Rows" => 0) as $key => $val) {
+ if ($row[$key] != "") {
+ $val = number_format($row[$key], 0, '.', lang(','));
+ echo "setHtml('$key-$id', '" . ($key == "Rows" && $row["Engine"] == "InnoDB" && $val ? "~ $val" : $val) . "');\n";
+ if (isset($sums[$key])) {
+ $sums[$key] += ($row["Engine"] != "InnoDB" || $key != "Data_free" ? $row[$key] : 0);
+ }
+ } elseif (array_key_exists($key, $row)) {
+ echo "setHtml('$key-$id');\n";
+ }
+ }
+ }
+ }
+ foreach ($sums as $key => $val) {
+ echo "setHtml('sum-$key', '" . number_format($val, 0, '.', lang(',')) . "');\n";
+ }
+ echo "</script>\n";
+}
+exit; // page_footer() already called
$TABLE = $_GET["download"];
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=" . friendly_url("$TABLE-" . implode("_", $_GET["where"])) . "." . friendly_url($_GET["field"]));
-echo $connection->result($connection->query("SELECT " . idf_escape($_GET["field"]) . " FROM " . idf_escape($TABLE) . " WHERE " . where($_GET) . " LIMIT 1"));
+echo $connection->result("SELECT" . limit(idf_escape($_GET["field"]) . " FROM " . idf_escape($TABLE) . " WHERE " . where($_GET), 1));
exit; // don't output footer
--- /dev/null
+<?php
+/**
+* @author Jakub Cernohuby
+* @author Vladimir Stastka
+* @author Jakub Vrana
+*/
+
+$possible_drivers[] = "SQLSRV";
+$possible_drivers[] = "MSSQL";
+if (extension_loaded("sqlsrv") || extension_loaded("mssql")) {
+ $drivers["mssql"] = "MS SQL";
+}
+
+if (isset($_GET["mssql"])) {
+ define("DRIVER", "mssql");
+ if (extension_loaded("sqlsrv")) {
+ class Min_DB {
+ var $extension = "sqlsrv", $_link, $_result, $server_info, $affected_rows, $error;
+
+ function _get_error() {
+ $this->error = "";
+ foreach (sqlsrv_errors() as $error) {
+ $this->error .= "$error[message]\n";
+ }
+ $this->error = rtrim($this->error);
+ }
+
+ function connect($server, $username, $password) {
+ $this->_link = @sqlsrv_connect($server, array("UID" => $username, "PWD" => $password));
+ if ($this->_link) {
+ $info = sqlsrv_server_info($this->_link);
+ $this->server_info = $info['SQLServerVersion'];
+ } else {
+ $this->_get_error();
+ }
+ return (bool) $this->_link;
+ }
+
+ function quote($string) {
+ return "'" . str_replace("'", "''", $string) . "'";
+ }
+
+ function select_db($database) {
+ return $this->query("USE $database");
+ }
+
+
+ function query($query, $unbuffered = false) {
+ $result = sqlsrv_query($this->_link, $query); //! , array(), ($unbuffered ? array() : array("Scrollable" => "keyset"))
+ if (!$result) {
+ $this->_get_error();
+ return false;
+ }
+ return $this->store_result($result);
+ }
+
+ function multi_query($query) {
+ $this->_result = sqlsrv_query($this->_link, $query);
+ if (!$this->_result) {
+ $this->_get_error();
+ return false;
+ }
+ return true;
+ }
+
+ function store_result($result = null) {
+ if (!$result) {
+ $result = $this->_result;
+ }
+ if (sqlsrv_field_metadata($result)) {
+ return new Min_Result($result);
+ }
+ $this->affected_rows = sqlsrv_rows_affected($result);
+ return true;
+ }
+
+ function next_result() {
+ return sqlsrv_next_result($this->_result);
+ }
+
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!is_object($result)) {
+ return false;
+ }
+ $row = $result->fetch_row();
+ return $row[$field];
+ }
+ }
+
+ class Min_Result {
+ var $_result, $_offset = 0, $_fields, $num_rows;
+
+ function Min_Result($result) {
+ $this->_result = $result;
+ $this->num_rows = sqlsrv_has_rows($result); //! sqlsrv_num_rows($result)
+ }
+
+ function _convert($row) {
+ foreach ((array) $row as $key => $val) {
+ if (is_a($val, 'DateTime')) {
+ $row[$key] = $val->format("Y-m-d H:i:s");
+ }
+ //! stream
+ }
+ return $row;
+ }
+
+ function fetch_assoc() {
+ return $this->_convert(sqlsrv_fetch_array($this->_result, SQLSRV_FETCH_ASSOC, SQLSRV_SCROLL_NEXT));
+ }
+
+ function fetch_row() {
+ return $this->_convert(sqlsrv_fetch_array($this->_result, SQLSRV_FETCH_NUMERIC, SQLSRV_SCROLL_NEXT));
+ }
+
+ function fetch_field() {
+ if (!$this->_fields) {
+ $this->_fields = sqlsrv_field_metadata($this->_result);
+ }
+ $field = $this->_fields[$this->_offset++];
+ $return = new stdClass;
+ $return->name = $field["Name"];
+ $return->orgname = $field["Name"];
+ $return->type = ($field["Type"] == 1 ? 254 : 0);
+ return $return;
+ }
+
+ function __destruct() {
+ sqlsrv_free_stmt($this->_result);
+ }
+ }
+
+ } elseif (extension_loaded("mssql")) {
+ class Min_DB {
+ var $extension = "MSSQL", $_link, $_result, $server_info, $affected_rows, $error;
+
+ function connect($server, $username, $password) {
+ $this->_link = @mssql_connect($server, $username, $password);
+ if ($this->_link) {
+ $result = $this->query("SELECT SERVERPROPERTY('ProductLevel'), SERVERPROPERTY('Edition')");
+ $row = $result->fetch_row();
+ $this->server_info = $this->result("sp_server_info 2", 2)." [$row[0]] $row[1]";
+ } else {
+ $this->error = mssql_get_last_message();
+ }
+ return (bool) $this->_link;
+ }
+
+ function quote($string) {
+ return "'" . str_replace("'", "''", $string) . "'";
+ }
+
+ function select_db($database) {
+ return mssql_select_db($database);
+ }
+
+ function query($query, $unbuffered = false) {
+ $result = mssql_query($query, $this->_link); //! $unbuffered
+ if (!$result) {
+ $this->error = mssql_get_last_message();
+ return false;
+ }
+ if ($result === true) {
+ $this->affected_rows = mssql_rows_affected($this->_link);
+ return true;
+ }
+ return new Min_Result($result);
+ }
+
+ function multi_query($query) {
+ return $this->_result = $this->query($query);
+ }
+
+ function store_result() {
+ return $this->_result;
+ }
+
+ function next_result() {
+ return mssql_next_result($this->_result);
+ }
+
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!is_object($result)) {
+ return false;
+ }
+ return mssql_result($result->_result, 0, $field);
+ }
+ }
+
+ class Min_Result {
+ var $_result, $_offset = 0, $_fields, $num_rows;
+
+ function Min_Result($result) {
+ $this->_result = $result;
+ $this->num_rows = mssql_num_rows($result);
+ }
+
+ function fetch_assoc() {
+ return mssql_fetch_assoc($this->_result);
+ }
+
+ function fetch_row() {
+ return mssql_fetch_row($this->_result);
+ }
+
+ function num_rows() {
+ return mssql_num_rows($this->_result);
+ }
+
+ function fetch_field() {
+ $return = mssql_fetch_field($this->_result);
+ $return->orgtable = $return->table;
+ $return->orgname = $return->name;
+ return $return;
+ }
+
+ function __destruct() {
+ mssql_free_result($this->_result);
+ }
+ }
+
+ }
+
+ function idf_escape($idf) {
+ return "[" . str_replace("]", "]]", $idf) . "]";
+ }
+
+ function connect() {
+ global $adminer;
+ $connection = new Min_DB;
+ $credentials = $adminer->credentials();
+ if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
+ return $connection;
+ }
+ return $connection->error;
+ }
+
+ function get_databases() {
+ return get_vals("EXEC sp_databases");
+ }
+
+ function limit($query, $limit, $offset = 0) {
+ return (isset($limit) ? " TOP ($limit)" : "") . " $query"; //! offset
+ }
+
+ function limit1($query, $limit, $offset = 0) {
+ return limit($query, 1);
+ }
+
+ function db_collation($db, $collations) {
+ global $connection;
+ return $connection->result("SELECT collation_name FROM sys.databases WHERE name = " . $connection->quote($db));
+ }
+
+ function engines() {
+ return array();
+ }
+
+ function logged_user() {
+ global $connection;
+ return $connection->result("SELECT SUSER_NAME()");
+ }
+
+ function tables_list() {
+ return get_key_vals("SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES");
+ }
+
+ function count_tables($databases) {
+ global $connection;
+ $return = array();
+ foreach ($databases as $db) {
+ $connection->select_db($db);
+ $return[$db] = $connection->result("SELECT COUNT(*) FROM information_schema.TABLES");
+ }
+ return $return;
+ }
+
+ function table_status($name = "") {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SELECT TABLE_NAME AS Name, TABLE_TYPE AS Engine FROM information_schema.TABLES" . ($name != "" ? " WHERE TABLE_NAME = " . $connection->quote($name) : ""));
+ while ($row = $result->fetch_assoc()) {
+ if ($name != "") {
+ return $row;
+ }
+ $return[$row["Name"]] = $row;
+ }
+ return $return;
+ }
+
+ function fk_support($table_status) {
+ return true;
+ }
+
+ function fields($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = " . $connection->quote($table));
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["COLUMN_NAME"]] = array(
+ "field" => $row["COLUMN_NAME"],
+ "full_type" => $row["DATA_TYPE"],
+ "type" => $row["DATA_TYPE"],
+ "length" => $row["CHARACTER_MAXIMUM_LENGTH"], //! NUMERIC_, DATETIME_?
+ "default" => $row["COLUMN_DEFAULT"],
+ "null" => ($row["IS_NULLABLE"] == "YES"),
+ "collation" => $row["COLLATION_NAME"],
+ "privileges" => array("insert" => 1, "select" => 1, "update" => 1),
+ //! primary - is_identity in sys.columns
+ );
+ }
+ return $return;
+ }
+
+ function indexes($table, $connection2 = null) {
+ global $connection;
+ if (!is_object($connection2)) {
+ $connection2 = $connection;
+ }
+ $return = array();
+ // sp_statistics doesn't return information about primary key
+ $result = $connection2->query("SELECT indexes.name, key_ordinal, is_unique, is_primary_key, columns.name AS column_name
+FROM sys.indexes
+INNER JOIN sys.index_columns ON indexes.object_id = index_columns.object_id AND indexes.index_id = index_columns.index_id
+INNER JOIN sys.columns ON index_columns.object_id = columns.object_id AND index_columns.column_id = columns.column_id
+WHERE OBJECT_NAME(indexes.object_id) = " . $connection2->quote($table));
+ if ($result) {
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["name"]]["type"] = ($row["is_primary_key"] ? "PRIMARY" : ($row["is_unique"] ? "UNIQUE" : "INDEX"));
+ $return[$row["name"]]["columns"][$row["key_ordinal"]] = $row["column_name"];
+ }
+ }
+ return $return;
+ }
+
+ function collations() {
+ $return = array();
+ foreach (get_vals("SELECT name FROM fn_helpcollations()") as $collation) {
+ $return[ereg_replace("_.*", "", $collation)][] = $collation;
+ }
+ return $return;
+ }
+
+ function information_schema($db) {
+ return false;
+ }
+
+ function error() {
+ global $connection;
+ return nl_br(h(ereg_replace("^(\\[[^]]*])+", "", $connection->error)));
+ }
+
+ function exact_value($val) {
+ global $connection;
+ return $connection->quote($val);
+ }
+
+ function rename_database($name, $collation) {
+ if ($collation) {
+ queries("ALTER DATABASE " . idf_escape(DB) . " COLLATE " . idf_escape($collation));
+ }
+ return queries("ALTER DATABASE " . idf_escape(DB) . " MODIFY NAME = " . idf_escape($name)); //! false negative "The database name 'test2' has been set."
+ }
+
+ function auto_increment() {
+ return " IDENTITY";
+ }
+
+ function explain($connection, $query) {
+ $connection->query("SET SHOWPLAN_ALL ON");
+ $return = $connection->query($query);
+ $connection->query("SET SHOWPLAN_ALL OFF"); // connection is used also for indexes
+ return $return;
+ }
+
+ function support($feature) {
+ return ereg('^(view|routine|trigger)$', $feature);
+ }
+
+ $driver = "mssql";
+ $types = array();
+ $structured_types = array();
+ foreach (array(
+ lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "int" => 10, "bigint" => 20, "bit" => 1, "decimal" => 0, "real" => 12, "float" => 53, "smallmoney" => 10, "money" => 20),
+ lang('Date and time') => array("date" => 10, "smalldatetime" => 19, "datetime" => 19, "datetime2" => 19, "time" => 8, "datetimeoffset" => 10),
+ lang('Strings') => array("char" => 8000, "varchar" => 8000, "text" => 2147483647, "nchar" => 4000, "nvarchar" => 4000, "ntext" => 1073741823),
+ lang('Binary') => array("binary" => 8000, "varbinary" => 8000, "image" => 2147483647),
+ ) as $key => $val) {
+ $types += $val;
+ $structured_types[$key] = array_keys($val);
+ }
+ $unsigned = array();
+ $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL");
+ $functions = array("len", "lower", "round", "upper");
+ $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
+ $edit_functions = array(
+ array(
+ "date|time" => "getdate",
+ ), array(
+ "int|decimal|real|float|money|datetime" => "+/-",
+ "char|text" => "+",
+ )
+ );
+}
--- /dev/null
+<?php
+$possible_drivers[] = "MySQLi";
+$possible_drivers[] = "MySQL";
+$possible_drivers[] = "PDO_MySQL";
+if (extension_loaded("mysqli") || extension_loaded("mysql") || extension_loaded("pdo_mysql")) {
+ $drivers = array("server" => "MySQL") + $drivers;
+}
+
+if (!defined("DRIVER")) {
+ define("DRIVER", "server"); // server - backwards compatibility
+ // MySQLi supports everything, MySQL doesn't support multiple result sets, PDO_MySQL doesn't support orgtable
+ if (extension_loaded("mysqli")) {
+ class Min_DB extends MySQLi {
+ var $extension = "MySQLi";
+
+ function Min_DB() {
+ parent::init();
+ }
+
+ function connect($server, $username, $password) {
+ list($host, $port) = explode(":", $server, 2); // part after : is used for port or socket
+ return @$this->real_connect(
+ ($server != "" ? $host : ini_get("mysqli.default_host")),
+ ("$server$username" != "" ? $username : ini_get("mysqli.default_user")),
+ ("$server$username$password" != "" ? $password : ini_get("mysqli.default_pw")),
+ null,
+ (is_numeric($port) ? $port : ini_get("mysqli.default_port")),
+ (!is_numeric($port) ? $port : null)
+ );
+ }
+
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!$result) {
+ return false;
+ }
+ $row = $result->fetch_array();
+ return $row[$field];
+ }
+
+ function quote($string) {
+ return "'" . $this->escape_string($string) . "'";
+ }
+ }
+
+ } elseif (extension_loaded("mysql")) {
+ class Min_DB {
+ var
+ $extension = "MySQL", ///< @var string extension name
+ $server_info, ///< @var string server version
+ $affected_rows, ///< @var int number of affected rows
+ $error, ///< @var string last error message
+ $_link, $_result ///< @access private
+ ;
+
+ /** Connect to server
+ * @param string
+ * @param string
+ * @param string
+ * @return bool
+ */
+ function connect($server, $username, $password) {
+ $this->_link = @mysql_connect(
+ ($server != "" ? $server : ini_get("mysql.default_host")),
+ ("$server$username" != "" ? $username : ini_get("mysql.default_user")),
+ ("$server$username$password" != "" ? $password : ini_get("mysql.default_password")),
+ true,
+ 131072 // CLIENT_MULTI_RESULTS for CALL
+ );
+ if ($this->_link) {
+ $this->server_info = mysql_get_server_info($this->_link);
+ } else {
+ $this->error = mysql_error();
+ }
+ return (bool) $this->_link;
+ }
+
+ /** Quote string to use in SQL
+ * @param string
+ * @return string escaped string enclosed in '
+ */
+ function quote($string) {
+ return "'" . mysql_real_escape_string($string, $this->_link) . "'";
+ }
+
+ /** Select database
+ * @param string
+ * @return bool
+ */
+ function select_db($database) {
+ return mysql_select_db($database, $this->_link);
+ }
+
+ /** Send query
+ * @param string
+ * @param bool
+ * @return mixed bool or Min_Result
+ */
+ function query($query, $unbuffered = false) {
+ $result = @($unbuffered ? mysql_unbuffered_query($query, $this->_link) : mysql_query($query, $this->_link)); // @ - mute mysql.trace_mode
+ if (!$result) {
+ $this->error = mysql_error($this->_link);
+ return false;
+ }
+ if ($result === true) {
+ $this->affected_rows = mysql_affected_rows($this->_link);
+ $this->info = mysql_info($this->_link);
+ return true;
+ }
+ return new Min_Result($result);
+ }
+
+ /** Send query with more resultsets
+ * @param string
+ * @return bool
+ */
+ function multi_query($query) {
+ return $this->_result = $this->query($query);
+ }
+
+ /** Get current resultset
+ * @return Min_Result
+ */
+ function store_result() {
+ return $this->_result;
+ }
+
+ /** Fetch next resultset
+ * @return bool
+ */
+ function next_result() {
+ // MySQL extension doesn't support multiple results
+ return false;
+ }
+
+ /** Get single field from result
+ * @param string
+ * @param int
+ * @return string
+ */
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!$result) {
+ return false;
+ }
+ return mysql_result($result->_result, 0, $field);
+ }
+ }
+
+ class Min_Result {
+ var
+ $num_rows, ///< @var int number of rows in the result
+ $_result ///< @access private
+ ;
+
+ /** Constructor
+ * @param resource
+ */
+ function Min_Result($result) {
+ $this->_result = $result;
+ $this->num_rows = mysql_num_rows($result);
+ }
+
+ /** Fetch next row as associative array
+ * @return array
+ */
+ function fetch_assoc() {
+ return mysql_fetch_assoc($this->_result);
+ }
+
+ /** Fetch next row as numbered array
+ * @return array
+ */
+ function fetch_row() {
+ return mysql_fetch_row($this->_result);
+ }
+
+ /** Fetch next field
+ * @return object properties: name, type, orgtable, orgname, charsetnr
+ */
+ function fetch_field() {
+ $return = mysql_fetch_field($this->_result);
+ $return->orgtable = $return->table;
+ $return->orgname = $return->name;
+ $return->charsetnr = ($return->blob ? 63 : 0);
+ return $return;
+ }
+
+ /** Free result set
+ */
+ function __destruct() {
+ mysql_free_result($this->_result); //! not called in PHP 4 which is a problem with mysql.trace_mode
+ }
+ }
+
+ } elseif (extension_loaded("pdo_mysql")) {
+ class Min_DB extends Min_PDO {
+ var $extension = "PDO_MySQL";
+
+ function connect($server, $username, $password) {
+ $this->dsn("mysql:host=" . str_replace(":", ";unix_socket=", preg_replace('~:([0-9])~', ';port=\\1', $server)), $username, $password);
+ return true;
+ }
+
+ function select_db($database) {
+ // database selection is separated from the connection so dbname in DSN can't be used
+ return $this->query("USE " . idf_escape($database));
+ }
+
+ function query($query, $unbuffered = false) {
+ $this->setAttribute(1000, !$unbuffered); // 1000 - PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
+ return parent::query($query, $unbuffered);
+ }
+ }
+
+ }
+
+ /** Escape database identifier
+ * @param string
+ * @return string
+ */
+ function idf_escape($idf) {
+ return "`" . str_replace("`", "``", $idf) . "`";
+ }
+
+ /** Connect to the database
+ * @return mixed Min_DB or string for error
+ */
+ function connect() {
+ global $adminer;
+ $connection = new Min_DB;
+ $credentials = $adminer->credentials();
+ if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
+ $connection->query("SET SQL_QUOTE_SHOW_CREATE=1");
+ $connection->query("SET NAMES utf8");
+ return $connection;
+ }
+ return $connection->error;
+ }
+
+ /** Get cached list of databases
+ * @param bool
+ * @return array
+ */
+ function get_databases($flush = true) {
+ // SHOW DATABASES can take a very long time so it is cached
+ $return = &get_session("databases");
+ if (!isset($return)) {
+ if ($flush) {
+ restart_session();
+ ob_flush();
+ flush();
+ }
+ $return = get_vals("SHOW DATABASES");
+ }
+ return $return;
+ }
+
+ /** Formulate SQL query with limit
+ * @param string everything after SELECT
+ * @param int
+ * @param int
+ * @return string
+ */
+ function limit($query, $limit, $offset = 0) {
+ return " $query" . (isset($limit) ? "\nLIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
+ }
+
+ /** Formulate SQL modification query with limit 1
+ * @param string everything after UPDATE or DELETE
+ * @return string
+ */
+ function limit1($query) {
+ return limit($query, 1);
+ }
+
+ /** Get database collation
+ * @param string
+ * @param array result of collations()
+ * @return string
+ */
+ function db_collation($db, $collations) {
+ global $connection;
+ $return = null;
+ $create = $connection->result("SHOW CREATE DATABASE " . idf_escape($db), 1);
+ if (preg_match('~ COLLATE ([^ ]+)~', $create, $match)) {
+ $return = $match[1];
+ } elseif (preg_match('~ CHARACTER SET ([^ ]+)~', $create, $match)) {
+ // default collation
+ $return = $collations[$match[1]][0];
+ }
+ return $return;
+ }
+
+ /** Get supported engines
+ * @return array
+ */
+ function engines() {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SHOW ENGINES");
+ while ($row = $result->fetch_assoc()) {
+ if (ereg("YES|DEFAULT", $row["Support"])) {
+ $return[] = $row["Engine"];
+ }
+ }
+ return $return;
+ }
+
+ /** Get logged user
+ * @return string
+ */
+ function logged_user() {
+ global $connection;
+ return $connection->result("SELECT USER()");
+ }
+
+ /** Get tables list
+ * @return array
+ */
+ function tables_list() {
+ global $connection;
+ return get_key_vals("SHOW" . ($connection->server_info >= 5 ? " FULL" : "") . " TABLES");
+ }
+
+ /** Count tables in all databases
+ * @param array
+ * @return array array($db => $tables)
+ */
+ function count_tables($databases) {
+ $return = array();
+ foreach ($databases as $db) {
+ $return[$db] = count(get_vals("SHOW TABLES IN " . idf_escape($db)));
+ }
+ return $return;
+ }
+
+ /** Get table status
+ * @param string
+ * @return array
+ */
+ function table_status($name = "") {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SHOW TABLE STATUS" . ($name != "" ? " LIKE " . $connection->quote(addcslashes($name, "%_")) : ""));
+ while ($row = $result->fetch_assoc()) {
+ if ($row["Engine"] == "InnoDB") {
+ // ignore internal comment, unnecessary since MySQL 5.1.21
+ $row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["Comment"]);
+ }
+ if (!isset($row["Rows"])) {
+ $row["Engine"] = "VIEW";
+ $row["Comment"] = "";
+ }
+ if ($name != "") {
+ return $row;
+ }
+ $return[$row["Name"]] = $row;
+ }
+ return $return;
+ }
+
+ /** Check if table supports foreign keys
+ * @param array result of table_status
+ * @return bool
+ */
+ function fk_support($table_status) {
+ return ($table_status["Engine"] == "InnoDB");
+ }
+
+ /** Get information about fields
+ * @param string
+ * @return array array($name => array("field" => , "full_type" => , "type" => , "length" => , "unsigned" => , "default" => , "null" => , "auto_increment" => , "on_update" => , "collation" => , "privileges" => , "comment" => , "primary" => ))
+ */
+ function fields($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SHOW FULL COLUMNS FROM " . idf_escape($table));
+ if ($result) {
+ while ($row = $result->fetch_assoc()) {
+ preg_match('~^([^( ]+)(?:\\((.+)\\))?( unsigned)?( zerofill)?$~', $row["Type"], $match);
+ $return[$row["Field"]] = array(
+ "field" => $row["Field"],
+ "full_type" => $row["Type"],
+ "type" => $match[1],
+ "length" => $match[2],
+ "unsigned" => ltrim($match[3] . $match[4]),
+ "default" => ($row["Default"] != "" || ereg("char", $match[1]) ? $row["Default"] : null),
+ "null" => ($row["Null"] == "YES"),
+ "auto_increment" => ($row["Extra"] == "auto_increment"),
+ "on_update" => (eregi('^on update (.+)', $row["Extra"], $match) ? $match[1] : ""), //! available since MySQL 5.1.23
+ "collation" => $row["Collation"],
+ "privileges" => array_flip(explode(",", $row["Privileges"])),
+ "comment" => $row["Comment"],
+ "primary" => ($row["Key"] == "PRI"),
+ );
+ }
+ }
+ return $return;
+ }
+
+ /** Get table indexes
+ * @param string
+ * @param string Min_DB to use
+ * @return array array($key_name => array("type" => , "columns" => array(), "lengths" => array()))
+ */
+ function indexes($table, $connection2 = null) {
+ global $connection;
+ if (!is_object($connection2)) { // use the main connection if the separate connection is unavailable
+ $connection2 = $connection;
+ }
+ $return = array();
+ $result = $connection2->query("SHOW INDEX FROM " . idf_escape($table));
+ if ($result) {
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["Key_name"]]["type"] = ($row["Key_name"] == "PRIMARY" ? "PRIMARY" : ($row["Index_type"] == "FULLTEXT" ? "FULLTEXT" : ($row["Non_unique"] ? "INDEX" : "UNIQUE")));
+ $return[$row["Key_name"]]["columns"][] = $row["Column_name"];
+ $return[$row["Key_name"]]["lengths"][] = $row["Sub_part"];
+ }
+ }
+ return $return;
+ }
+
+ /** Get foreign keys in table
+ * @param string
+ * @return array array($name => array("db" => , "table" => , "source" => array(), "target" => array(), "on_delete" => , "on_update" => ))
+ */
+ function foreign_keys($table) {
+ global $connection, $on_actions;
+ static $pattern = '`(?:[^`]|``)+`';
+ $return = array();
+ $create_table = $connection->result("SHOW CREATE TABLE " . idf_escape($table), 1);
+ if ($create_table) {
+ preg_match_all("~CONSTRAINT ($pattern) FOREIGN KEY \\(((?:$pattern,? ?)+)\\) REFERENCES ($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE (" . implode("|", $on_actions) . "))?(?: ON UPDATE (" . implode("|", $on_actions) . "))?~", $create_table, $matches, PREG_SET_ORDER);
+ foreach ($matches as $match) {
+ preg_match_all("~$pattern~", $match[2], $source);
+ preg_match_all("~$pattern~", $match[5], $target);
+ $return[idf_unescape($match[1])] = array(
+ "db" => idf_unescape($match[4] != "" ? $match[3] : $match[4]),
+ "table" => idf_unescape($match[4] != "" ? $match[4] : $match[3]),
+ "source" => array_map('idf_unescape', $source[0]),
+ "target" => array_map('idf_unescape', $target[0]),
+ "on_delete" => $match[6],
+ "on_update" => $match[7],
+ );
+ }
+ }
+ return $return;
+ }
+
+ /** Get view SELECT
+ * @param string
+ * @return array array("select" => )
+ */
+ function view($name) {
+ global $connection;
+ return array("select" => preg_replace('~^(?:[^`]|`[^`]*`)* AS ~U', '', $connection->result("SHOW CREATE VIEW " . idf_escape($name), 1)));
+ }
+
+ /** Get sorted grouped list of collations
+ * @return array
+ */
+ function collations() {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SHOW COLLATION");
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["Charset"]][] = $row["Collation"];
+ }
+ ksort($return);
+ foreach ($return as $key => $val) {
+ sort($return[$key]);
+ }
+ return $return;
+ }
+
+ /** Find out if database is information_schema
+ * @param string
+ * @return bool
+ */
+ function information_schema($db) {
+ global $connection;
+ return ($connection->server_info >= 5 && $db == "information_schema");
+ }
+
+ /** Get escaped error message
+ * @return string
+ */
+ function error() {
+ global $connection;
+ return h(preg_replace('~^You have an error.*syntax to use~U', "Syntax error", $connection->error));
+ }
+
+ /** Return expression for binary comparison
+ * @param string
+ * @return string
+ */
+ function exact_value($val) {
+ global $connection;
+ return "BINARY " . $connection->quote($val);
+ }
+
+ /** Rename database from DB
+ * @param string new name
+ * @return string
+ * @return bool
+ */
+ function rename_database($name, $collation) {
+ global $connection;
+ $return = false;
+ if (queries("CREATE DATABASE " . idf_escape($name) . ($collation ? " COLLATE " . $connection->quote($collation) : ""))) {
+ //! move triggers
+ $return = true; // table list may by empty
+ foreach (tables_list() as $table) {
+ if (!queries("RENAME TABLE " . idf_escape($table) . " TO " . idf_escape($name) . "." . idf_escape($table))) {
+ $return = false;
+ break;
+ }
+ }
+ if ($return) {
+ queries("DROP DATABASE " . idf_escape(DB));
+ //! saved to history of removed database
+ }
+ }
+ return $return;
+ }
+
+ /** Generate modifier for auto increment column
+ * @return string
+ */
+ function auto_increment() {
+ $auto_increment_index = " PRIMARY KEY";
+ // don't overwrite primary key by auto_increment
+ if ($_GET["create"] != "" && $_POST["auto_increment_col"]) {
+ foreach (indexes($_GET["create"]) as $index) {
+ if (in_array($_POST["fields"][$_POST["auto_increment_col"]]["orig"], $index["columns"], true)) {
+ $auto_increment_index = "";
+ break;
+ }
+ if ($index["type"] == "PRIMARY") {
+ $auto_increment_index = " UNIQUE";
+ }
+ }
+ }
+ return " AUTO_INCREMENT$auto_increment_index";
+ }
+
+ /** Run commands to create or alter table
+ * @param string "" to create
+ * @param string new name
+ * @param array of array($orig, $process_field, $after)
+ * @param array of strings
+ * @param string
+ * @param string
+ * @param string
+ * @param int
+ * @param string
+ * @return bool
+ */
+ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
+ global $connection;
+ $alter = array();
+ foreach ($fields as $field) {
+ $alter[] = ($field[1]
+ ? ($table != "" ? ($field[0] != "" ? "CHANGE " . idf_escape($field[0]) : "ADD") : " ") . " " . implode("", $field[1]) . ($table != "" ? " $field[2]" : "")
+ : "DROP " . idf_escape($field[0])
+ );
+ }
+ $alter = array_merge($alter, $foreign);
+ $status = "COMMENT=" . $connection->quote($comment)
+ . ($engine ? " ENGINE=" . $connection->quote($engine) : "")
+ . ($collation ? " COLLATE " . $connection->quote($collation) : "")
+ . ($auto_increment != "" ? " AUTO_INCREMENT=$auto_increment" : "")
+ . $partitioning
+ ;
+ if ($table == "") {
+ return queries("CREATE TABLE " . idf_escape($name) . " (\n" . implode(",\n", $alter) . "\n) $status");
+ }
+ if ($table != $name) {
+ $alter[] = "RENAME TO " . idf_escape($name);
+ }
+ $alter[] = $status;
+ return queries("ALTER TABLE " . idf_escape($table) . "\n" . implode(",\n", $alter));
+ }
+
+ /** Run commands to alter indexes
+ * @param string escaped table name
+ * @param array of array("index type", "(columns definition)") or array("index type", "escaped name", "DROP")
+ * @return bool
+ */
+ function alter_indexes($table, $alter) {
+ foreach ($alter as $key => $val) {
+ $alter[$key] = ($val[2] ? "\nDROP INDEX " : "\nADD $val[0] " . ($val[0] == "PRIMARY" ? "KEY " : "")) . $val[1];
+ }
+ return queries("ALTER TABLE " . idf_escape($table) . implode(",", $alter));
+ }
+
+ /** Run commands to truncate tables
+ * @param array
+ * @return bool
+ */
+ function truncate_tables($tables) {
+ foreach ($tables as $table) {
+ if (!queries("TRUNCATE TABLE " . idf_escape($table))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Drop views
+ * @param array
+ * @return bool
+ */
+ function drop_views($views) {
+ return queries("DROP VIEW " . implode(", ", array_map('idf_escape', $views)));
+ }
+
+ /** Drop tables
+ * @param array
+ * @return bool
+ */
+ function drop_tables($tables) {
+ return queries("DROP TABLE " . implode(", ", array_map('idf_escape', $tables)));
+ }
+
+ /** Get information about trigger
+ * @param string trigger name
+ * @return array array("Trigger" => , "Timing" => , "Event" => , "Statement" => )
+ */
+ function trigger($name) {
+ global $connection;
+ $result = $connection->query("SHOW TRIGGERS WHERE `Trigger` = " . $connection->quote($name));
+ return $result->fetch_assoc();
+ }
+
+ /** Get defined triggers
+ * @param string
+ * @return array array($name => array($timing, $event))
+ */
+ function triggers($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SHOW TRIGGERS LIKE " . $connection->quote(addcslashes($table, "%_")));
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["Trigger"]] = array($row["Timing"], $row["Event"]);
+ }
+ return $return;
+ }
+
+ /** Explain select
+ * @param Min_DB
+ * @param string
+ * @return Min_Result
+ */
+ function explain($connection, $query) {
+ return $connection->query("EXPLAIN $query");
+ }
+
+ /** Get SQL command to create table
+ * @param string
+ * @return string
+ */
+ function create_sql($table) {
+ global $connection;
+ return $connection->result("SHOW CREATE TABLE " . idf_escape($table), 1);
+ }
+
+ /** Check whether a feature is supported
+ * @param string
+ * @return bool
+ */
+ function support($feature) {
+ global $connection;
+ $features = array(
+ "view" => ($connection->server_info >= 5),
+ "routine" => ($connection->server_info >= 5),
+ "trigger" => ($connection->server_info >= 5),
+ "event" => ($connection->server_info >= 5.1),
+ "partitioning" => ($connection->server_info >= 5.1),
+ );
+ return (isset($features[$feature]) ? $features[$feature] : true);
+ }
+
+ $driver = "sql"; ///< @var string JUSH identifier
+ $types = array(); ///< @var array ($type => $maximum_unsigned_length, ...)
+ $structured_types = array(); ///< @var array ($description => array($type, ...), ...)
+ foreach (array(
+ lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "mediumint" => 8, "int" => 10, "bigint" => 20, "decimal" => 66, "float" => 12, "double" => 21),
+ lang('Date and time') => array("date" => 10, "datetime" => 19, "timestamp" => 19, "time" => 10, "year" => 4),
+ lang('Strings') => array("char" => 255, "varchar" => 65535, "tinytext" => 255, "text" => 65535, "mediumtext" => 16777215, "longtext" => 4294967295),
+ lang('Binary') => array("binary" => 255, "varbinary" => 65535, "tinyblob" => 255, "blob" => 65535, "mediumblob" => 16777215, "longblob" => 4294967295),
+ lang('Lists') => array("enum" => 65535, "set" => 64),
+ ) as $key => $val) {
+ $types += $val;
+ $structured_types[$key] = array_keys($val);
+ }
+ $unsigned = array("unsigned", "zerofill", "unsigned zerofill"); ///< @var array number variants
+ $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL"); ///< @var array operators used in select
+ $functions = array("char_length", "from_unixtime", "hex", "lower", "round", "sec_to_time", "time_to_sec", "upper"); ///< @var array functions used in select
+ $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"); ///< @var array grouping functions used in select
+ $edit_functions = array( ///< @var array of array("$type|$type2" => "$function/$function2") functions used in editing, [0] - edit and insert, [1] - edit only
+ array(
+ "char" => "md5/sha1/password/encrypt/uuid", //! JavaScript for disabling maxlength
+ "date|time" => "now",
+ ), array(
+ "int|float|double|decimal" => "+/-",
+ "date" => "+ interval/- interval",
+ "time" => "addtime/subtime",
+ "char|text" => "concat",
+ )
+ );
+}
--- /dev/null
+<?php
+$possible_drivers[] = "PgSQL";
+$possible_drivers[] = "PDO_PgSQL";
+if (extension_loaded("pgsql") || extension_loaded("pdo_pgsql")) {
+ $drivers["pgsql"] = "PostgreSQL";
+}
+
+if (isset($_GET["pgsql"])) {
+ define("DRIVER", "pgsql");
+ if (extension_loaded("pgsql")) {
+ class Min_DB {
+ var $extension = "PgSQL", $_link, $_result, $_string, $_database = true, $server_info, $affected_rows, $error;
+
+ function _error($errno, $error) {
+ if (ini_bool("html_errors")) {
+ $error = html_entity_decode(strip_tags($error));
+ }
+ $error = ereg_replace('^[^:]*: ', '', $error);
+ $this->error = $error;
+ }
+
+ function connect($server, $username, $password) {
+ set_error_handler(array($this, '_error'));
+ $this->_string = "host='" . str_replace(":", "' port='", addcslashes($server, "'\\")) . "' user='" . addcslashes($username, "'\\") . "' password='" . addcslashes($password, "'\\") . "'";
+ $this->_link = @pg_connect($this->_string . (DB != "" ? " dbname='" . addcslashes(DB, "'\\") . "'" : ""), PGSQL_CONNECT_FORCE_NEW);
+ if (!$this->_link && DB != "") {
+ // try to connect directly with database for performance
+ $this->_database = false;
+ $this->_link = @pg_connect($this->_string, PGSQL_CONNECT_FORCE_NEW);
+ }
+ restore_error_handler();
+ if ($this->_link) {
+ $version = pg_version($this->_link);
+ $this->server_info = $version["server"];
+ pg_set_client_encoding($this->_link, "UTF8");
+ }
+ return (bool) $this->_link;
+ }
+
+ function quote($string) {
+ return "'" . pg_escape_string($this->_link, $string) . "'"; //! bytea
+ }
+
+ function select_db($database) {
+ if ($database == DB) {
+ return $this->_database;
+ }
+ $link = @pg_connect($this->_connection . " dbname='" . addcslashes($database, "'\\") . "'", PGSQL_CONNECT_FORCE_NEW);
+ if ($link) {
+ $this->_link = $link;
+ }
+ return $link;
+ }
+
+ function query($query, $unbuffered = false) {
+ $result = @pg_query($this->_link, $query);
+ if (!$result) {
+ $this->error = pg_last_error($this->_link);
+ return false;
+ } elseif (!pg_num_fields($result)) {
+ $this->affected_rows = pg_affected_rows($result);
+ return true;
+ }
+ return new Min_Result($result);
+ }
+
+ function multi_query($query) {
+ return $this->_result = $this->query($query);
+ }
+
+ function store_result() {
+ return $this->_result;
+ }
+
+ function next_result() {
+ // PgSQL extension doesn't support multiple results
+ return false;
+ }
+
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!$result) {
+ return false;
+ }
+ return pg_fetch_result($result->_result, 0, $field);
+ }
+ }
+
+ class Min_Result {
+ var $_result, $_offset = 0, $num_rows;
+
+ function Min_Result($result) {
+ $this->_result = $result;
+ $this->num_rows = pg_num_rows($result);
+ }
+
+ function fetch_assoc() {
+ return pg_fetch_assoc($this->_result);
+ }
+
+ function fetch_row() {
+ return pg_fetch_row($this->_result);
+ }
+
+ function fetch_field() {
+ $column = $this->_offset++;
+ $row = new stdClass;
+ $row->orgtable = pg_field_table($this->_result, $column);
+ $row->name = pg_field_name($this->_result, $column);
+ $row->orgname = $row->name;
+ $row->type = pg_field_type($this->_result, $column);
+ $row->charsetnr = ($row->type == "bytea" ? 63 : 0);
+ return $row;
+ }
+
+ function __destruct() {
+ pg_free_result($this->_result);
+ }
+ }
+
+ } elseif (extension_loaded("pdo_pgsql")) {
+ class Min_DB extends Min_PDO {
+ var $extension = "PDO_PgSQL";
+
+ function connect($server, $username, $password) {
+ $string = "pgsql:host='" . str_replace(":", "' port='", addcslashes($server, "'\\")) . "' options='-c client_encoding=utf8'";
+ $this->dsn($string . (DB != "" ? " dbname='" . addcslashes(DB, "'\\") . "'" : ""), $username, $password);
+ //! connect without DB in case of an error
+ return true;
+ }
+
+ function select_db($database) {
+ return (DB == $database);
+ }
+ }
+
+ }
+
+ function idf_escape($idf) {
+ return '"' . str_replace('"', '""', $idf) . '"';
+ }
+
+ function connect() {
+ global $adminer;
+ $connection = new Min_DB;
+ $credentials = $adminer->credentials();
+ if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
+ return $connection;
+ }
+ return $connection->error;
+ }
+
+ function get_databases() {
+ return get_vals("SELECT datname FROM pg_database");
+ }
+
+ function limit($query, $limit, $offset = 0) {
+ return " $query" . (isset($limit) ? "\nLIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
+ }
+
+ function limit1($query) {
+ return " $query";
+ }
+
+ function db_collation($db, $collations) {
+ global $connection;
+ return $connection->result("SHOW LC_COLLATE"); //! respect $db
+ }
+
+ function engines() {
+ return array();
+ }
+
+ function logged_user() {
+ global $connection;
+ return $connection->result("SELECT user");
+ }
+
+ function tables_list() {
+ global $connection;
+ return get_key_vals("SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name");
+ }
+
+ function count_tables($databases) {
+ return array(); // would require reconnect
+ }
+
+ function table_status($name = "") {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SELECT relname AS \"Name\", CASE relkind WHEN 'r' THEN '' ELSE 'view' END AS \"Engine\", pg_relation_size(oid) AS \"Data_length\", pg_catalog.obj_description(oid, 'pg_class') AS \"Comment\" FROM pg_catalog.pg_class WHERE relkind IN ('r','v') AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public')" . ($name != "" ? " AND relname = " . $connection->quote($name) : "")); //! Index_length, Auto_increment
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["Name"]] = $row;
+ }
+ return ($name != "" ? $return[$name] : $return);
+ }
+
+ function fk_support($table_status) {
+ return true;
+ }
+
+ function fields($table) {
+ global $connection;
+ $return = array();
+ $table_oid = $connection->result("SELECT oid FROM pg_class WHERE relname = " . $connection->quote($table));
+ $result = $connection->query("SELECT *, col_description($table_oid, ordinal_position) AS comment FROM information_schema.columns WHERE table_name = " . $connection->quote($table) . " ORDER BY ordinal_position");
+ if ($result) {
+ while ($row = $result->fetch_assoc()) {
+ $length = $row["character_maximum_length"];
+ $return[$row["column_name"]] = array(
+ "field" => $row["column_name"],
+ "full_type" => $row["data_type"] . ($length ? "($length)" : ""),
+ "type" => $row["data_type"],
+ "length" => $length,
+ "default" => $row["column_default"],
+ "null" => ($row["is_nullable"] == "YES"),
+ "auto_increment" => eregi("^nextval\\(", $row["column_default"]),
+ "on_update" => "", //!
+ "collation" => $row["collation_name"],
+ "privileges" => array("insert" => 1, "select" => 1, "update" => 1), //! is_updatable
+ "primary" => false, //!
+ "comment" => $row["comment"],
+ );
+ }
+ }
+ return $return;
+ }
+
+ function indexes($table, $connection2 = null) {
+ global $connection;
+ if (!is_object($connection2)) {
+ $connection2 = $connection;
+ }
+ $return = array();
+ $table_oid = $connection2->result("SELECT oid FROM pg_class WHERE relname = " . $connection2->quote($table));
+ $columns = get_key_vals("SELECT attnum, attname FROM pg_attribute WHERE attrelid = $table_oid AND attnum > 0", $connection2);
+ $result = $connection2->query("SELECT relname, indisunique, indisprimary, indkey FROM pg_index i, pg_class ci WHERE i.indrelid = $table_oid AND ci.oid = i.indexrelid");
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["relname"]]["type"] = ($row["indisprimary"] == "t" ? "PRIMARY" : ($row["indisunique"] == "t" ? "UNIQUE" : "INDEX"));
+ $return[$row["relname"]]["columns"] = array();
+ foreach (explode(" ", $row["indkey"]) as $indkey) {
+ $return[$row["relname"]]["columns"][] = $columns[$indkey];
+ }
+ $return[$row["relname"]]["lengths"] = array();
+ }
+ return $return;
+ }
+
+ function foreign_keys($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SELECT tc.constraint_name, kcu.column_name, rc.update_rule AS on_update, rc.delete_rule AS on_delete, ccu.table_name AS table, ccu.column_name AS ref
+FROM information_schema.table_constraints tc
+LEFT JOIN information_schema.key_column_usage kcu USING (constraint_catalog, constraint_schema, constraint_name)
+LEFT JOIN information_schema.referential_constraints rc USING (constraint_catalog, constraint_schema, constraint_name)
+LEFT JOIN information_schema.constraint_column_usage ccu ON rc.unique_constraint_catalog = ccu.constraint_catalog AND rc.unique_constraint_schema = ccu.constraint_schema AND rc.unique_constraint_name = ccu.constraint_name
+WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name = " . $connection->quote($table)); //! there can be more unique_constraint_name
+ while ($row = $result->fetch_assoc()) {
+ $foreign_key = &$return[$row["constraint_name"]];
+ if (!$foreign_key) {
+ $foreign_key = $row;
+ }
+ $foreign_key["source"][] = $row["column_name"];
+ $foreign_key["target"][] = $row["ref"];
+ }
+ return $return;
+ }
+
+ function view($name) {
+ global $connection;
+ return array("select" => $connection->result("SELECT pg_get_viewdef(" . $connection->quote($name) . ")"));
+ }
+
+ function collations() {
+ //! supported in CREATE DATABASE
+ return array();
+ }
+
+ function information_schema($db) {
+ return ($db == "information_schema");
+ }
+
+ function error() {
+ global $connection;
+ $return = h($connection->error);
+ if (preg_match('~^(.*\\n)?([^\\n]*)\\n( *)\\^(\\n.*)?$~s', $return, $match)) {
+ $return = $match[1] . preg_replace('~((?:[^&]|&[^;]*;){' . strlen($match[3]) . '})(.*)~', '\\1<b>\\2</b>', $match[2]) . $match[4];
+ }
+ return nl_br($return);
+ }
+
+ function exact_value($val) {
+ global $connection;
+ return $connection->quote($val);
+ }
+
+ function rename_database($name, $collation) {
+ //! current database cannot be renamed
+ return queries("ALTER DATABASE " . idf_escape(DB) . " RENAME TO " . idf_escape($name));
+ }
+
+ function auto_increment() {
+ return true;
+ }
+
+ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
+ global $connection;
+ $alter = array();
+ $queries = array();
+ foreach ($fields as $field) {
+ $column = idf_escape($field[0]);
+ $val = $field[1];
+ if (!$val) {
+ $alter[] = "DROP $column";
+ } else {
+ $val5 = $val[5];
+ unset($val[5]);
+ if ($val[6]) { // auto_increment
+ $val = array($val[0], ($val[1] == "bigint" ? "big" : "") . "serial");
+ }
+ if ($field[0] == "") {
+ $alter[] = ($table != "" ? "ADD " : " ") . implode("", $val);
+ } else {
+ if ($column != $val[0]) {
+ $queries[] = "ALTER TABLE " . idf_escape($table) . " RENAME $column TO $val[0]";
+ }
+ $alter[] = "ALTER $column TYPE $val[1]";
+ if (!$val[6]) {
+ $alter[] = "ALTER $column" . ($val[3] ? " SET$val[3]" : " DROP DEFAULT"); //! quoting
+ $alter[] = "ALTER $column " . ($val[2] == " NULL" ? "DROP NOT" : "SET") . $val[2];
+ }
+ }
+ if ($table != "" || $val5 != "") {
+ $queries[] = "COMMENT ON COLUMN " . idf_escape($table) . ".$val[0] IS " . substr($val5, 9);
+ }
+ }
+ }
+ $alter = array_merge($alter, $foreign);
+ if ($table == "") {
+ array_unshift($queries, "CREATE TABLE " . idf_escape($name) . " (\n" . implode(",\n", $alter) . "\n)");
+ } elseif ($alter) {
+ array_unshift($queries, "ALTER TABLE " . idf_escape($table) . "\n" . implode(",\n", $alter));
+ }
+ if ($table != "" && $table != $name) {
+ $queries[] = "ALTER TABLE " . idf_escape($table) . " RENAME TO " . idf_escape($name);
+ }
+ if ($table != "" || $comment != "") {
+ $queries[] = "COMMENT ON TABLE " . idf_escape($name) . " IS " . $connection->quote($comment);
+ }
+ if ($auto_increment != "") {
+ //! $queries[] = "SELECT setval(pg_get_serial_sequence(" . $connection->quote($name) . ", ), $auto_increment)";
+ }
+ foreach ($queries as $query) {
+ if (!queries($query)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function alter_indexes($table, $alter) {
+ $create = array();
+ $drop = array();
+ foreach ($alter as $val) {
+ if ($val[0] != "INDEX") {
+ $create[] = ($val[2] ? "\nDROP CONSTRAINT " : "\nADD $val[0] " . ($val[0] == "PRIMARY" ? "KEY " : "")) . $val[1];
+ } elseif ($val[2]) {
+ $drop[] = $val[1];
+ } elseif (!queries("CREATE INDEX " . idf_escape(uniqid($table . "_")) . " ON " . idf_escape($table) . " $val[1]")) {
+ return false;
+ }
+ }
+ return ((!$create || queries("ALTER TABLE " . idf_escape($table) . implode(",", $create)))
+ && (!$drop || queries("DROP INDEX " . implode(", ", $drop)))
+ );
+ }
+
+ function truncate_tables($tables) {
+ return queries("TRUNCATE " . implode(", ", array_map('idf_escape', $tables)));
+ return true;
+ }
+
+ function drop_views($views) {
+ return queries("DROP VIEW " . implode(", ", array_map('idf_escape', $views)));
+ }
+
+ function drop_tables($tables) {
+ return queries("DROP TABLE " . implode(", ", array_map('idf_escape', $tables)));
+ }
+
+ function trigger($name) {
+ global $connection;
+ $result = $connection->query('SELECT trigger_name AS "Trigger", condition_timing AS "Timing", event_manipulation AS "Event", action_statement AS "Statement" FROM information_schema.triggers WHERE event_object_table = ' . $connection->quote($_GET["trigger"]) . ' AND trigger_name = ' . $connection->quote($name));
+ return $result->fetch_assoc();
+ }
+
+ function triggers($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SELECT * FROM information_schema.triggers WHERE event_object_table = " . $connection->quote($table));
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["trigger_name"]] = array($row["condition_timing"], $row["event_manipulation"]);
+ }
+ return $return;
+ }
+
+ function explain($connection, $query) {
+ return $connection->query("EXPLAIN $query");
+ }
+
+ function support($feature) {
+ return ereg('^(comment|view|routine|trigger)$', $feature);
+ }
+
+ $driver = "pgsql";
+ $types = array();
+ $structured_types = array();
+ foreach (array( //! arrays
+ lang('Numbers') => array("smallint" => 5, "integer" => 10, "bigint" => 19, "boolean" => 1, "numeric" => 0, "real" => 7, "double precision" => 16, "money" => 20),
+ lang('Date and time') => array("date" => 13, "time" => 17, "timestamp" => 20, "interval" => 0),
+ lang('Strings') => array("character" => 0, "character varying" => 0, "text" => 0, "tsquery" => 0, "tsvector" => 0, "uuid" => 0, "xml" => 0),
+ lang('Binary') => array("bit" => 0, "bit varying" => 0, "bytea" => 0),
+ lang('Network') => array("cidr" => 43, "inet" => 43, "macaddr" => 17, "txid_snapshot" => 0),
+ lang('Geometry') => array("box" => 0, "circle" => 0, "line" => 0, "lseg" => 0, "path" => 0, "point" => 0, "polygon" => 0),
+ ) as $key => $val) {
+ $types += $val;
+ $structured_types[$key] = array_keys($val);
+ }
+ $unsigned = array();
+ $operators = array("=", "<", ">", "<=", ">=", "!=", "~", "!~", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL");
+ $functions = array("char_length", "lower", "round", "to_hex", "to_timestamp", "upper");
+ $grouping = array("avg", "count", "count distinct", "max", "min", "sum");
+ $edit_functions = array(
+ array(
+ "char" => "md5",
+ "date|time" => "now",
+ ), array(
+ "int|numeric|real|money" => "+/-",
+ "date|time" => "+ interval/- interval", //! escape
+ "char|text" => "||",
+ )
+ );
+}
--- /dev/null
+<?php
+$possible_drivers[] = "SQLite";
+$possible_drivers[] = "SQLite3";
+$possible_drivers[] = "PDO_SQLite";
+if (extension_loaded("sqlite3") || extension_loaded("pdo_sqlite")) {
+ $drivers["sqlite"] = "SQLite 3";
+}
+if (extension_loaded("sqlite") || extension_loaded("pdo_sqlite")) {
+ $drivers["sqlite2"] = "SQLite 2";
+}
+
+if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
+ define("DRIVER", (isset($_GET["sqlite"]) ? "sqlite" : "sqlite2"));
+ if (extension_loaded(isset($_GET["sqlite2"]) ? "sqlite" : "sqlite3")) {
+ if (isset($_GET["sqlite2"])) {
+
+ class Min_SQLite {
+ var $extension = "SQLite", $server_info, $affected_rows, $error, $_connection;
+
+ function __construct() {
+ $this->server_info = sqlite_libversion();
+ }
+
+ function open($filename) {
+ $this->_connection = new SQLiteDatabase($filename);
+ }
+
+ function query($query, $unbuffered = false) {
+ $method = ($unbuffered ? "unbufferedQuery" : "query");
+ $result = @$this->_connection->$method($query, SQLITE_BOTH, $error);
+ if (!$result) {
+ $this->error = $error;
+ return false;
+ } elseif ($result === true) {
+ $this->affected_rows = $this->changes();
+ return true;
+ }
+ return new Min_Result($result);
+ }
+
+ function quote($string) {
+ return "'" . sqlite_escape_string($string) . "'";
+ }
+
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!$result) {
+ return false;
+ }
+ $row = $result->_result->fetch();
+ return $row[$field];
+ }
+ }
+
+ class Min_Result {
+ var $_result, $_offset = 0, $num_rows;
+
+ function __construct($result) {
+ $this->_result = $result;
+ if (method_exists($result, 'numRows')) { // not available in unbuffered query
+ $this->num_rows = $result->numRows();
+ }
+ }
+
+ function fetch_assoc() {
+ $row = $this->_result->fetch(SQLITE_ASSOC);
+ if (!$row) {
+ return false;
+ }
+ $return = array();
+ foreach ($row as $key => $val) {
+ $return[($key[0] == '"' ? idf_unescape($key) : $key)] = $val;
+ }
+ return $return;
+ }
+
+ function fetch_row() {
+ return $this->_result->fetch(SQLITE_NUM);
+ }
+
+ function fetch_field() {
+ return (object) array(
+ "name" => $this->_result->fieldName($this->_offset++),
+ //! type, orgtable, charsetnr
+ );
+ }
+
+ }
+
+ } else {
+
+ class Min_SQLite extends SQLite3 {
+ var $extension = "SQLite3", $server_info, $affected_rows, $error;
+
+ function __construct() {
+ $version = $this->version();
+ $this->server_info = $version["versionString"];
+ }
+
+ function open($filename) {
+ parent::__construct($filename);
+ }
+
+ function query($query) {
+ $result = @parent::query($query);
+ if (!$result) {
+ $this->error = $this->lastErrorMsg();
+ return false;
+ } elseif ($result->numColumns()) {
+ return new Min_Result($result);
+ }
+ $this->affected_rows = $this->changes();
+ return true;
+ }
+
+ function quote($string) {
+ return "'" . $this->escapeString($string) . "'";
+ }
+
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!$result) {
+ return false;
+ }
+ $row = $result->_result->fetchArray();
+ return $row[$field];
+ }
+ }
+
+ class Min_Result {
+ var $_result, $_offset = 0, $num_rows;
+
+ function __construct($result) {
+ $this->_result = $result;
+ $this->num_rows = 1; //!
+ }
+
+ function fetch_assoc() {
+ return $this->_result->fetchArray(SQLITE3_ASSOC);
+ }
+
+ function fetch_row() {
+ return $this->_result->fetchArray(SQLITE3_NUM);
+ }
+
+ function fetch_field() {
+ $column = $this->_offset++;
+ return (object) array(
+ "name" => $this->_result->columnName($column),
+ "type" => $this->_result->columnType($column),
+ //! orgtable, charsetnr
+ );
+ }
+
+ function __desctruct() {
+ return $this->_result->finalize();
+ }
+ }
+
+ }
+
+ class Min_DB extends Min_SQLite {
+
+ function select_db($filename) {
+ static $connected = false;
+ if ($connected) {
+ return true;
+ }
+ set_exception_handler('connect_error'); // try/catch is not compatible with PHP 4
+ $this->open($filename);
+ $connected = true;
+ restore_exception_handler();
+ return true;
+ }
+
+ function multi_query($query) {
+ return $this->_result = $this->query($query);
+ }
+
+ function store_result() {
+ return $this->_result;
+ }
+
+ function next_result() {
+ return false;
+ }
+ }
+
+ } elseif (extension_loaded("pdo_sqlite")) {
+ class Min_DB extends Min_PDO {
+ var $extension = "PDO_SQLite";
+
+ function select_db($filename) {
+ static $connected = false;
+ if ($connected) {
+ return true;
+ }
+ $connected = true;
+ $this->dsn(DRIVER . ":$filename", "", "", "connect_error");
+ //! $this->server_info needs to be filled in __construct()
+ return true;
+ }
+ }
+
+ }
+
+ function idf_escape($idf) {
+ return '"' . str_replace('"', '""', $idf) . '"';
+ }
+
+ function connect() {
+ global $connection;
+ if ($connection) {
+ return $connection; // can connect only once, function to get number of rows doesn't exist anyway
+ }
+ return new Min_DB;
+ }
+
+ function get_databases() {
+ return array();
+ }
+
+ function limit($query, $limit, $offset = 0) {
+ return " $query" . (isset($limit) ? "\nLIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
+ }
+
+ function limit1($query) {
+ global $connection;
+ return ($connection->result("SELECT sqlite_compileoption_used('ENABLE_UPDATE_DELETE_LIMIT')") ? limit($query, 1) : " $query");
+ }
+
+ function db_collation($db, $collations) {
+ return null;
+ }
+
+ function engines() {
+ return array();
+ }
+
+ function logged_user() {
+ return ""; //! OS user
+ }
+
+ function tables_list() {
+ return get_key_vals("SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view')", 1);
+ }
+
+ function count_tables($databases) {
+ return array();
+ }
+
+ function table_status($name = "") {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SELECT name AS Name, type AS Engine FROM sqlite_master WHERE type IN ('table', 'view')" . ($name != "" ? " AND name = " . $connection->quote($name) : ""));
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["Name"]] = $row;
+ }
+ $result = $connection->query("SELECT * FROM sqlite_sequence");
+ if ($result) {
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["name"]]["Auto_increment"] = $row["seq"];
+ }
+ }
+ return ($name != "" ? $return[$name] : $return);
+ }
+
+ function fk_support($table_status) {
+ global $connection;
+ return !$connection->result("SELECT sqlite_compileoption_used('OMIT_FOREIGN_KEY')");
+ }
+
+ function fields($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("PRAGMA table_info(" . idf_escape($table) . ")");
+ if (is_object($result)) {
+ while ($row = $result->fetch_assoc()) {
+ $type = strtolower($row["type"]);
+ $return[$row["name"]] = array(
+ "field" => $row["name"],
+ "type" => (eregi("int", $type) ? "integer" : (eregi("char|clob|text", $type) ? "text" : (eregi("blob", $type) ? "blob" : (eregi("real|floa|doub", $type) ? "real" : "numeric")))),
+ "full_type" => $type,
+ "default" => $row["dflt_value"],
+ "null" => !$row["notnull"],
+ "auto_increment" => eregi('^integer$', $type) && $row["pk"], //! possible false positive
+ "collation" => null, //!
+ "privileges" => array("select" => 1, "insert" => 1, "update" => 1),
+ "primary" => $row["pk"],
+ );
+ }
+ }
+ return $return;
+ }
+
+ function indexes($table, $connection2 = null) {
+ global $connection;
+ $return = array();
+ $primary = array();
+ foreach (fields($table) as $field) {
+ if ($field["primary"]) {
+ $primary[] = $field["field"];
+ }
+ }
+ if ($primary) {
+ $return[""] = array("type" => "PRIMARY", "columns" => $primary, "lengths" => array());
+ }
+ $result = $connection->query("PRAGMA index_list(" . idf_escape($table) . ")");
+ if (is_object($result)) {
+ while ($row = $result->fetch_assoc()) {
+ $return[$row["name"]]["type"] = ($row["unique"] ? "UNIQUE" : "INDEX");
+ $return[$row["name"]]["lengths"] = array();
+ $result1 = $connection->query("PRAGMA index_info(" . idf_escape($row["name"]) . ")");
+ while ($row1 = $result1->fetch_assoc()) {
+ $return[$row["name"]]["columns"][] = $row1["name"];
+ }
+ }
+ }
+ return $return;
+ }
+
+ function foreign_keys($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("PRAGMA foreign_key_list(" . idf_escape($table) . ")");
+ if (is_object($result)) {
+ while ($row = $result->fetch_assoc()) {
+ $foreign_key = &$return[$row["id"]];
+ if (!$foreign_key) {
+ $foreign_key = $row;
+ }
+ $foreign_key["source"][] = $row["from"];
+ $foreign_key["target"][] = $row["to"];
+ }
+ }
+ return $return;
+ }
+
+ function view($name) {
+ global $connection;
+ return array("select" => preg_replace('~^(?:[^`"[]+|`[^`]*`|"[^"]*")* AS\\s+~iU', '', $connection->result("SELECT sql FROM sqlite_master WHERE name = " . $connection->quote($name)))); //! identifiers may be inside []
+ }
+
+ function collations() {
+ return get_vals("PRAGMA collation_list", 1);
+ }
+
+ function information_schema($db) {
+ return false;
+ }
+
+ function error() {
+ global $connection;
+ return h($connection->error);
+ }
+
+ function exact_value($val) {
+ global $connection;
+ return $connection->quote($val);
+ }
+
+ function rename_database($name, $collation) {
+ global $connection;
+ $connection->close(); //! not available with all extensions
+ return rename(DB, $name);
+ }
+
+ function auto_increment() {
+ return " PRIMARY KEY" . (DRIVER == "sqlite" ? " AUTOINCREMENT" : "");
+ }
+
+ function alter_table($table, $name, $fields, $foreign, $comment, $engine, $collation, $auto_increment, $partitioning) {
+ global $connection;
+ $alter = array();
+ foreach ($fields as $field) {
+ $alter[] = ($table != "" && $field[0] == "" ? "ADD " : " ") . implode("", $field[1]);
+ }
+ $alter = array_merge($alter, $foreign);
+ if ($table != "") {
+ foreach ($alter as $val) {
+ if (!queries("ALTER TABLE " . idf_escape($table) . " $val")) {
+ return false;
+ }
+ }
+ if ($table != $name && !queries("ALTER TABLE " . idf_escape($table) . " RENAME TO " . idf_escape($name))) {
+ return false;
+ }
+ } elseif (!queries("CREATE TABLE " . idf_escape($name) . " (\n" . implode(",\n", $alter) . "\n)")) {
+ return false;
+ }
+ if ($auto_increment) {
+ return queries("UPDATE sqlite_sequence SET seq = $auto_increment WHERE name = " . $connection->quote($name) . "");
+ }
+ return true;
+ }
+
+ function alter_indexes($table, $alter) {
+ foreach ($alter as $val) {
+ if (!queries(($val[2] ? "DROP INDEX" : "CREATE" . ($val[0] != "INDEX" ? " UNIQUE" : "") . " INDEX " . idf_escape(uniqid($table . "_")) . " ON " . idf_escape($table)) . " $val[1]")) { //! primary key must be created in CREATE TABLE
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function truncate_tables($tables) {
+ foreach ($tables as $table) {
+ if (!queries("DELETE FROM " . idf_escape($table))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function drop_views($views) {
+ foreach ($views as $view) {
+ if (!queries("DROP VIEW " . idf_escape($view))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function drop_tables($tables) {
+ foreach ($tables as $table) {
+ if (!queries("DROP TABLE " . idf_escape($table))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function trigger($name) {
+ global $connection;
+ preg_match('~^CREATE\\s+TRIGGER\\s*(?:[^`"\\s]+|`[^`]*`|"[^"]*")+\\s*([a-z]+)\\s+([a-z]+)\\s+ON\\s*(?:[^`"\\s]+|`[^`]*`|"[^"]*")+\\s*(?:FOR\\s*EACH\\s*ROW\\s)?(.*)~is', $connection->result("SELECT sql FROM sqlite_master WHERE name = " . $connection->quote($name)), $match);
+ return array("Timing" => strtoupper($match[1]), "Event" => strtoupper($match[2]), "Trigger" => $name, "Statement" => $match[3]);
+ }
+
+ function triggers($table) {
+ global $connection;
+ $return = array();
+ $result = $connection->query("SELECT * FROM sqlite_master WHERE type = 'trigger' AND tbl_name = " . $connection->quote($table));
+ while ($row = $result->fetch_assoc()) {
+ preg_match('~^CREATE\\s+TRIGGER\\s*(?:[^`"\\s]+|`[^`]*`|"[^"]*")+\\s*([a-z]+)\\s*([a-z]+)~i', $row["sql"], $match);
+ $return[$row["name"]] = array($match[1], $match[2]);
+ }
+ return $return;
+ }
+
+ function explain($connection, $query) {
+ return $connection->query("EXPLAIN $query");
+ }
+
+ function create_sql($table) {
+ global $connection;
+ return $connection->result("SELECT sql FROM sqlite_master WHERE name = " . $connection->quote($table));
+ }
+
+ function support($feature) {
+ return ereg('^(view|trigger)$', $feature);
+ }
+
+ $driver = "sqlite";
+ $types = array("integer" => 0, "real" => 0, "numeric" => 0, "text" => 0, "blob" => 0);
+ $structured_types = array_keys($types);
+ $unsigned = array();
+ $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "IN", "IS NULL", "NOT LIKE", "NOT IN", "IS NOT NULL"); // REGEXP can be user defined function
+ $functions = array("hex", "length", "lower", "round", "unixepoch", "upper");
+ $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
+ $edit_functions = array(
+ array(
+ // "text" => "date('now')/time('now')/datetime('now')",
+ ), array(
+ "integer|real|numeric" => "+/-",
+ // "text" => "date/time/datetime",
+ "text" => "||",
+ )
+ );
+}
$TABLE = $_GET["dump"];
if ($_POST) {
+ $cookie = "";
+ foreach (array("output", "format", "db_style", "table_style", "data_style") as $key) {
+ $cookie .= "&$key=" . urlencode($_POST[$key]);
+ }
+ cookie("adminer_export", substr($cookie, 1));
$ext = dump_headers(($TABLE != "" ? $TABLE : DB), (DB == "" || count((array) $_POST["tables"] + (array) $_POST["data"]) > 1));
if ($_POST["format"] == "sql") {
- echo "-- Adminer $VERSION dump
-SET NAMES utf8;
+ echo "-- Adminer $VERSION " . $drivers[DRIVER] . " dump
+
+" . ($driver != "sql" ? "" : "SET NAMES utf8;
SET foreign_key_checks = 0;
-SET time_zone = " . $connection->quote($connection->result($connection->query("SELECT @@time_zone"))) . ";
+SET time_zone = " . $connection->quote($connection->result("SELECT @@time_zone")) . ";
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
-";
+");
}
$style = $_POST["db_style"];
- foreach ((DB != "" ? array(DB) : (array) $_POST["databases"]) as $db) {
+ $databases = array(DB);
+ if (DB == "") {
+ $databases = $_POST["databases"];
+ if (is_string($databases)) {
+ $databases = explode("\n", rtrim(str_replace("\r", "", $databases), "\n"));
+ }
+ }
+ foreach ((array) $databases as $db) {
if ($connection->select_db($db)) {
- if ($_POST["format"] == "sql" && ereg('CREATE', $style) && ($result = $connection->query("SHOW CREATE DATABASE " . idf_escape($db)))) {
+ if ($_POST["format"] == "sql" && ereg('CREATE', $style) && ($create = $connection->result("SHOW CREATE DATABASE " . idf_escape($db), 1))) {
if ($style == "DROP+CREATE") {
echo "DROP DATABASE IF EXISTS " . idf_escape($db) . ";\n";
}
- $create = $connection->result($result, 1);
echo ($style == "CREATE+ALTER" ? preg_replace('~^CREATE DATABASE ~', '\\0IF NOT EXISTS ', $create) : $create) . ";\n";
}
if ($_POST["format"] == "sql") {
$result = $connection->query("SHOW $routine STATUS WHERE Db = " . $connection->quote($db));
while ($row = $result->fetch_assoc()) {
$out .= ($style != 'DROP+CREATE' ? "DROP $routine IF EXISTS " . idf_escape($row["Name"]) . ";;\n" : "")
- . $connection->result($connection->query("SHOW CREATE $routine " . idf_escape($row["Name"])), 2) . ";;\n\n";
+ . $connection->result("SHOW CREATE $routine " . idf_escape($row["Name"]), 2) . ";;\n\n";
}
}
}
if ($result) {
while ($row = $result->fetch_assoc()) {
$out .= ($style != 'DROP+CREATE' ? "DROP EVENT IF EXISTS " . idf_escape($row["Name"]) . ";;\n" : "")
- . $connection->result($connection->query("SHOW CREATE EVENT " . idf_escape($row["Name"])), 3) . ";;\n\n";
+ . $connection->result("SHOW CREATE EVENT " . idf_escape($row["Name"]), 3) . ";;\n\n";
}
}
}
if ($_POST["table_style"] || $_POST["data_style"]) {
$views = array();
+ //! defer number of rows to JavaScript
foreach (table_status() as $row) {
$table = (DB == "" || in_array($row["Name"], (array) $_POST["tables"]));
$data = (DB == "" || in_array($row["Name"], (array) $_POST["data"]));
$db_style = array('', 'USE', 'DROP+CREATE', 'CREATE');
$table_style = array('', 'DROP+CREATE', 'CREATE');
$data_style = array('', 'TRUNCATE+INSERT', 'INSERT', 'INSERT+UPDATE');
-if ($connection->server_info >= 5) {
+if (support("routine")) {
$db_style[] = 'CREATE+ALTER';
$table_style[] = 'CREATE+ALTER';
}
-echo "<tr><th>" . lang('Output') . "<td><input type='hidden' name='token' value='$token'>" . $adminer->dumpOutput(0) . "\n"; // token is not needed but checked in bootstrap for all POST data //! read from cookie
-echo "<tr><th>" . lang('Format') . "<td>" . $adminer->dumpFormat(0) . "\n";
-echo "<tr><th>" . lang('Database') . "<td>" . html_select('db_style', $db_style, (DB != "" ? '' : 'CREATE'));
-if ($connection->server_info >= 5) {
- $checked = $_GET["dump"] == "";
+parse_str($_COOKIE["adminer_export"], $row);
+if (!$row) {
+ $row = array("output" => "text", "format" => "sql", "db_style" => (DB != "" ? "" : "CREATE"), "table_style" => "DROP+CREATE", "data_style" => "INSERT");
+}
+echo "<tr><th>" . lang('Output') . "<td>" . $adminer->dumpOutput(0, $row["output"]) . "\n";
+echo "<tr><th>" . lang('Format') . "<td>" . $adminer->dumpFormat(0, $row["format"]) . "\n";
+echo "<tr><th>" . lang('Database') . "<td>" . html_select('db_style', $db_style, $row["db_style"]);
+$checked = ($_GET["dump"] == "");
+if (support("routine")) {
echo checkbox("routines", 1, $checked, lang('Routines'));
- if ($connection->server_info >= 5.1) {
- echo checkbox("events", 1, $checked, lang('Events'));
- }
}
-echo "<tr><th>" . lang('Tables') . "<td>" . html_select('table_style', $table_style, 'DROP+CREATE');
-echo "<tr><th>" . lang('Data') . "<td>" . html_select('data_style', $data_style, 'INSERT');
+if (support("event")) {
+ echo checkbox("events", 1, $checked, lang('Events'));
+}
+echo "<tr><th>" . lang('Tables') . "<td>" . html_select('table_style', $table_style, $row["table_style"]);
+echo "<tr><th>" . lang('Data') . "<td>" . html_select('data_style', $data_style, $row["data_style"]);
?>
</table>
<p><input type="submit" value="<?php echo lang('Export'); ?>">
$prefix = ereg_replace("_.*", "", $name);
$checked = ($TABLE == "" || $TABLE == (substr($TABLE, -1) == "%" ? "$prefix%" : $name)); //! % may be part of table name
$print = "<tr><td>" . checkbox("tables[]", $name, $checked, $name, "formUncheck('check-tables');");
- if (!$row["Engine"]) {
+ if (eregi("view", $row["Engine"])) {
$views .= "$print\n";
} else {
- echo "$print<td align='right'><label>" . ($row["Engine"] == "InnoDB" && $row["Rows"] ? lang('~ %s', $row["Rows"]) : $row["Rows"]) . checkbox("data[]", $name, $checked, "", "formUncheck('check-data');") . "</label>\n";
+ echo "$print<td align='right'><label>" . ($row["Engine"] == "InnoDB" && $row["Rows"] ? "~ " : "") . $row["Rows"] . checkbox("data[]", $name, $checked, "", "formUncheck('check-data');") . "</label>\n";
}
$prefixes[$prefix]++;
}
echo $views;
} else {
echo "<thead><tr><th style='text-align: left;'><label><input type='checkbox' id='check-databases'" . ($TABLE == "" ? " checked" : "") . " onclick='formCheck(this, /^databases\\[/);'>" . lang('Database') . "</label></thead>\n";
- foreach (get_databases() as $db) {
- if (!information_schema($db)) {
- $prefix = ereg_replace("_.*", "", $db);
- echo "<tr><td>" . checkbox("databases[]", $db, $TABLE == "" || $TABLE == "$prefix%", $db, "formUncheck('check-databases');") . "</label>\n";
- $prefixes[$prefix]++;
+ $databases = get_databases();
+ if ($databases) {
+ foreach ($databases as $db) {
+ if (!information_schema($db)) {
+ $prefix = ereg_replace("_.*", "", $db);
+ echo "<tr><td>" . checkbox("databases[]", $db, $TABLE == "" || $TABLE == "$prefix%", $db, "formUncheck('check-databases');") . "</label>\n";
+ $prefixes[$prefix]++;
+ }
}
+ } else {
+ echo "<tr><td><textarea name='databases' rows='10' cols='20'></textarea>";
}
}
?>
$location = ($update ? null : $_SERVER["REQUEST_URI"]);
} elseif (!ereg('^.+&select=.+$', $location)) {
$location = ME . "select=" . urlencode($TABLE);
- $i = 0; // append &set converted to &where
- foreach ((array) $_GET["set"] as $key => $val) {
- if ($val == $_POST["fields"][$key]) {
- $location .= where_link($i++, bracket_escape($key, "back"), $val);
- }
- }
}
if (isset($_POST["delete"])) {
- query_redirect("DELETE FROM " . idf_escape($_GET["edit"]) . " WHERE $where LIMIT 1", $location, lang('Item has been deleted.'));
+ query_redirect("DELETE" . limit1("FROM " . idf_escape($_GET["edit"]) . "\nWHERE $where"), $location, lang('Item has been deleted.'));
} else {
$set = array();
foreach ($fields as $name => $field) {
$val = process_input($field);
- if (!$update) {
- $set[idf_escape($name)] = ($val !== false ? $val : "''");
- } elseif ($val !== false) {
- $set[] = "\n" . idf_escape($name) . " = $val";
+ if ($val !== false && $val !== null) {
+ $set[idf_escape($name)] = ($update ? "\n" . idf_escape($name) . " = $val" : $val);
}
}
- if (!$set) {
- redirect($location);
- }
if ($update) {
- query_redirect("UPDATE " . idf_escape($TABLE) . " SET" . implode(",", $set) . "\nWHERE $where\nLIMIT 1", $location, lang('Item has been updated.'));
+ if (!$set) {
+ redirect($location);
+ }
+ query_redirect("UPDATE" . limit1(idf_escape($TABLE) . " SET" . implode(",", $set) . "\nWHERE $where"), $location, lang('Item has been updated.'));
} else {
query_redirect("INSERT INTO " . idf_escape($TABLE) . " (" . implode(", ", array_keys($set)) . ")\nVALUES (" . implode(", ", $set) . ")", $location, lang('Item has been inserted.'));
}
}
$row = array();
if ($select) {
- $result = $connection->query("SELECT " . implode(", ", $select) . " FROM " . idf_escape($TABLE) . " WHERE $where " . (isset($_GET["select"]) ? "HAVING COUNT(*) = 1" : "LIMIT 1"));
+ $result = $connection->query("SELECT" . limit(implode(", ", $select) . " FROM " . idf_escape($TABLE) . " WHERE $where", (isset($_GET["select"]) ? 2 : 1)));
$row = $result->fetch_assoc();
+ if (isset($_GET["select"]) && $result->fetch_assoc()) {
+ $row = false;
+ }
}
}
?>
$default = $_GET["set"][bracket_escape($name)];
$value = (isset($row)
? ($row[$name] != "" && ereg("enum|set", $field["type"]) ? intval($row[$name]) : $row[$name])
- : ($_POST["clone"] && $field["auto_increment"] ? "" : (isset($_GET["select"]) ? false : (isset($default) ? $default : $field["default"])))
+ : (!$update && $field["auto_increment"] ? "" : (isset($_GET["select"]) ? false : (isset($default) ? $default : $field["default"])))
);
if (!$_POST["save"] && is_string($value)) {
$value = $adminer->editVal($value, $field);
$TABLE = $_GET["foreign"];
if ($_POST && !$error && !$_POST["add"] && !$_POST["change"] && !$_POST["change-js"]) {
if ($_POST["drop"]) {
- query_redirect("ALTER TABLE " . idf_escape($TABLE) . "\nDROP FOREIGN KEY " . idf_escape($_GET["name"]), ME . "table=" . urlencode($TABLE), lang('Foreign key has been dropped.'));
+ query_redirect("ALTER TABLE " . idf_escape($TABLE) . "\nDROP " . ($driver == "sql" ? "FOREIGN KEY " : "CONSTRAINT ") . idf_escape($_GET["name"]), ME . "table=" . urlencode($TABLE), lang('Foreign key has been dropped.'));
} else {
$source = array_filter($_POST["source"], 'strlen');
ksort($source); // enforce input order
$source = array_keys(fields($TABLE)); //! no text and blob
$target = ($TABLE === $row["table"] ? $source : array_keys(fields($row["table"])));
+$referencable = array();
+foreach (table_status() as $name => $table_status) {
+ if (fk_support($table_status)) {
+ $referencable[] = $name;
+ }
+}
?>
<form action="" method="post">
<p>
<?php if ($row["db"] == "") { ?>
<?php echo lang('Target table'); ?>:
-<?php echo html_select("table", array_keys(table_status_referencable()), $row["table"], "this.form['change-js'].value = '1'; this.form.submit();"); ?>
+<?php echo html_select("table", $referencable, $row["table"], "this.form['change-js'].value = '1'; this.form.submit();"); ?>
<input type="hidden" name="change-js" value="">
<noscript><p><input type="submit" name="change" value="<?php echo lang('Change'); ?>"></noscript>
<table cellspacing="0">
<?php
class Adminer {
- /** @var array functions used in select */
- var $functions = array("char_length", "from_unixtime", "hex", "lower", "round", "sec_to_time", "time_to_sec", "unix_timestamp", "upper");
-
- /** @var array grouping functions used in select */
- var $grouping = array("avg", "count", "count distinct", "group_concat", "max", "min", "sum");
-
- /** @var array operators used in select */
- var $operators = array("=", "<", ">", "<=", ">=", "!=", "LIKE", "REGEXP", "IN", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL");
+ /** @var array operators used in select, null for all operators */
+ var $operators;
/** Name in title and navigation
* @return string
* @return array ($server, $username, $password)
*/
function credentials() {
- return array($_GET["server"], $_SESSION["usernames"][$_GET["server"]], $_SESSION["passwords"][$_GET["server"]]);
+ return array(SERVER, $_GET["username"], get_session("passwords"));
}
/** Get key used for permanent login
}
/** Print login form
- * @param string
* @return null
*/
- function loginForm($username) {
+ function loginForm() {
+ global $drivers, $possible_drivers;
?>
<table cellspacing="0">
-<tr><th><?php echo lang('Server'); ?><td><input name="server" value="<?php echo h($_GET["server"]); ?>">
-<tr><th><?php echo lang('Username'); ?><td><input name="username" value="<?php echo h($username); ?>">
+<tr><th><?php echo lang('System'); ?><td><?php echo (count($possible_drivers) > 3 ? html_select("driver", $drivers, DRIVER) : "<input type='hidden' name='driver' value='" . key($drivers) . "'>" . reset($drivers)); ?></tr>
+<tr><th><?php echo lang('Server'); ?><td><input name="server" value="<?php echo h(SERVER); ?>">
+<tr><th><?php echo lang('Username'); ?><td><input name="username" value="<?php echo h($_GET["username"]); ?>">
<tr><th><?php echo lang('Password'); ?><td><input type="password" name="password">
</table>
<?php
function selectLinks($tableStatus, $set = "") {
echo '<p class="tabs">';
$links = array("select" => lang('Select data'), "table" => lang('Show structure'));
- if (isset($tableStatus["Rows"])) {
- $links["create"] = lang('Alter table');
- } else {
+ if (eregi("view", $tableStatus["Engine"])) {
$links["view"] = lang('Alter view');
+ } else {
+ $links["create"] = lang('Alter table');
}
if (isset($set)) {
$links["edit"] = lang('New item');
* @return string
*/
function selectQuery($query) {
- return "<p><code class='jush-sql'>" . h(str_replace("\n", " ", $query)) . "</code> <a href='" . h(ME) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>\n";
+ global $driver;
+ return "<p><code class='jush-$driver'>" . h(str_replace("\n", " ", $query)) . "</code> <a href='" . h(ME) . "sql=" . urlencode($query) . "'>" . lang('Edit') . "</a>\n";
}
/** Description of a row in a table
*/
function selectVal($val, $link, $field) {
$return = ($val != "<i>NULL</i>" && $field["type"] == "char" ? "<code>$val</code>" : $val);
- if (ereg('blob|binary', $field["type"]) && !is_utf8($val)) {
+ if (ereg('binary|blob|bytea', $field["type"]) && !is_utf8($val)) {
$return = lang('%d byte(s)', strlen($val));
}
return ($link ? "<a href='$link'>$return</a>" : $return);
* @return null
*/
function selectColumnsPrint($select, $columns) {
+ global $functions, $grouping;
print_fieldset("select", lang('Select'), $select);
$i = 0;
- $fun_group = array(lang('Functions') => $this->functions, lang('Aggregation') => $this->grouping);
+ $fun_group = array(lang('Functions') => $functions, lang('Aggregation') => $grouping);
foreach ($select as $key => $val) {
$val = $_GET["columns"][$key];
echo "<div>" . html_select("columns[$i][fun]", array(-1 => "") + $fun_group, $val["fun"]);
- echo "<select name='columns[$i][col]'><option>" . optionlist($columns, $val["col"], true) . "</select></div>\n";
+ echo "(<select name='columns[$i][col]'><option>" . optionlist($columns, $val["col"], true) . "</select>)</div>\n";
$i++;
}
- echo "<div>" . html_select("columns[$i][fun]", array(-1 => "") + $fun_group, "", "this.nextSibling.onchange();");
- echo "<select name='columns[$i][col]' onchange='selectAddRow(this);'><option>" . optionlist($columns, null, true) . "</select></div>\n";
+ echo "<div>" . html_select("columns[$i][fun]", array(-1 => "") + $fun_group, "", "this.nextSibling.nextSibling.onchange();");
+ echo "(<select name='columns[$i][col]' onchange='selectAddRow(this);'><option>" . optionlist($columns, null, true) . "</select>)</div>\n";
echo "</div></fieldset>\n";
}
$i = 0;
foreach ((array) $_GET["where"] as $val) {
if ("$val[col]$val[val]" != "" && in_array($val["op"], $this->operators)) {
- echo "<div><select name='where[$i][col]'><option value=''>" . lang('(anywhere)') . optionlist($columns, $val["col"], true) . "</select>";
+ echo "<div><select name='where[$i][col]'><option value=''>(" . lang('anywhere') . ")" . optionlist($columns, $val["col"], true) . "</select>";
echo html_select("where[$i][op]", $this->operators, $val["op"]);
echo "<input name='where[$i][val]' value='" . h($val["val"]) . "'></div>\n";
$i++;
}
}
- echo "<div><select name='where[$i][col]' onchange='selectAddRow(this);'><option value=''>" . lang('(anywhere)') . optionlist($columns, null, true) . "</select>";
+ echo "<div><select name='where[$i][col]' onchange='selectAddRow(this);'><option value=''>(" . lang('anywhere') . ")" . optionlist($columns, null, true) . "</select>";
echo html_select("where[$i][op]", $this->operators);
echo "<input name='where[$i][val]'></div>\n";
echo "</div></fieldset>\n";
* @return array (array(select_expressions), array(group_expressions))
*/
function selectColumnsProcess($columns, $indexes) {
+ global $functions, $grouping;
$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" || (isset($columns[$val["col"]]) && (!$val["fun"] || in_array($val["fun"], $this->functions) || in_array($val["fun"], $this->grouping)))) {
+ if ($val["fun"] == "count" || (isset($columns[$val["col"]]) && (!$val["fun"] || in_array($val["fun"], $functions) || in_array($val["fun"], $grouping)))) {
$select[$key] = apply_sql_function($val["fun"], (isset($columns[$val["col"]]) ? idf_escape($val["col"]) : "*"));
- if (!in_array($val["fun"], $this->grouping)) {
+ if (!in_array($val["fun"], $grouping)) {
$group[] = $select[$key];
}
}
}
foreach ((array) $_GET["where"] as $val) {
if ("$val[col]$val[val]" != "" && in_array($val["op"], $this->operators)) {
- $in = process_length($val["val"]);
- $cond = " $val[op]" . (ereg('NULL$', $val["op"]) ? "" : (ereg('IN$', $val["op"]) ? " (" . ($in != "" ? $in : "NULL") . ")" : " " . $this->processInput($fields[$val["col"]], $val["val"])));
+ $cond = " $val[op]";
+ if (ereg('IN$', $val["op"])) {
+ $in = process_length($val["val"]);
+ $cond .= " (" . ($in != "" ? $in : "NULL") . ")";
+ } elseif ($val["op"] == "LIKE %%") {
+ $cond = " LIKE " . $this->processInput($fields[$val["col"]], "%$val[val]%");
+ } elseif (!ereg('NULL$', $val["op"])) {
+ $cond .= " " . $this->processInput($fields[$val["col"]], $val["val"]);
+ }
if ($val["col"] != "") {
$return[] = idf_escape($val["col"]) . $cond;
} else {
function selectOrderProcess($fields, $indexes) {
$return = array();
foreach ((array) $_GET["order"] as $key => $val) {
- if (isset($fields[$val]) || preg_match('~^((COUNT\\(DISTINCT |[A-Z0-9_]+\\()`(?:[^`]|``)+`\\)|COUNT\\(\\*\\))$~', $val)) {
- $return[] = idf_escape($val) . (isset($_GET["desc"][$key]) ? " DESC" : "");
+ if (isset($fields[$val]) || preg_match('~^((COUNT\\(DISTINCT |[A-Z0-9_]+\\()(`(?:[^`]|``)+`|"(?:[^"]|"")+")\\)|COUNT\\(\\*\\))$~', $val)) { //! MS SQL uses []
+ $return[] = (isset($fields[$val]) ? idf_escape($val) : $val) . (isset($_GET["desc"][$key]) ? " DESC" : "");
}
}
return $return;
* @return string
*/
function messageQuery($query) {
+ global $driver;
restart_session();
$id = "sql-" . count($_SESSION["messages"]);
- $_SESSION["history"][$_GET["server"]][DB][] = (strlen($query) > 1e6 ? ereg_replace('[\x80-\xFF]+$', '', substr($query, 0, 1e6)) . "\n..." : $query); // [\x80-\xFF] - valid UTF-8, \n - can end by one-line comment
- return " <a href='#$id' onclick=\"return !toggle('$id');\">" . lang('SQL command') . "</a><div id='$id' class='hidden'><pre class='jush-sql'>" . shorten_utf8($query, 1000) . '</pre><a href="' . h(ME . 'sql=&history=' . (count($_SESSION["history"][$_GET["server"]][DB]) - 1)) . '">' . lang('Edit') . '</a></div>';
+ $history = &get_session("history");
+ $history[DB][] = (strlen($query) > 1e6 ? ereg_replace('[\x80-\xFF]+$', '', substr($query, 0, 1e6)) . "\n..." : $query); // [\x80-\xFF] - valid UTF-8, \n - can end by one-line comment
+ return " <a href='#$id' onclick=\"return !toggle('$id');\">" . lang('SQL command') . "</a><div id='$id' class='hidden'><pre class='jush-$driver'>" . shorten_utf8($query, 1000) . '</pre><p><a href="' . h(ME . 'sql=&history=' . (count($history[DB]) - 1)) . '">' . lang('Edit') . '</a></div>';
}
/** Functions displayed in edit form
* @return array
*/
function editFunctions($field) {
- $return = array("");
- if (ereg('char|date|time', $field["type"])) {
- $return = (ereg('char', $field["type"]) ? array("", "md5", "sha1", "password", "encrypt", "uuid") : array("", "now")); //! JavaScript for disabling maxlength
- }
- if (!isset($_GET["call"]) && (isset($_GET["select"]) || where($_GET))) {
- // relative functions
- if (ereg('int|float|double|decimal', $field["type"])) {
- $return = array("", "+", "-");
- }
- if (ereg('date', $field["type"])) {
- $return[] = "+ interval";
- $return[] = "- interval";
- }
- if (ereg('time', $field["type"])) {
- $return[] = "addtime";
- $return[] = "subtime";
- }
- if (ereg('char|text', $field["type"])) {
- $return[] = "concat";
+ global $edit_functions;
+ $return = ($field["null"] ? "/NULL" : "");
+ foreach ($edit_functions as $key => $functions) {
+ if (!$key || (!isset($_GET["call"]) && (isset($_GET["select"]) || where($_GET)))) { // relative functions
+ foreach ($functions as $pattern => $val) {
+ if (!$pattern || ereg($pattern, $field["type"])) {
+ $return .= "/$val";
+ }
+ }
}
}
- if ($field["null"]) {
- array_unshift($return, "NULL");
- }
- return $return;
+ return explode("/", $return);
}
/** Get options to display edit field
global $connection;
$name = $field["field"];
$return = $connection->quote($value);
- if (ereg('^(now|uuid)$', $function)) {
+ if (ereg('^(now|getdate|uuid)$', $function)) {
$return = "$function()";
- } elseif (ereg('^[+-]$', $function)) {
+ } elseif (ereg('^([+-]|\\|\\|)$', $function)) {
$return = idf_escape($name) . " $function $return";
} elseif (ereg('^[+-] interval$', $function)) {
$return = idf_escape($name) . " $function " . (preg_match("~^([0-9]+|'[0-9.: -]') [A-Z_]+$~i", $value) ? $value : $return);
/** Returns export output options
* @param bool generate select (otherwise radio)
+ * @param string
* @return string
*/
- function dumpOutput($select) {
+ function dumpOutput($select, $value = "") {
$return = array('text' => lang('open'), 'file' => lang('save'));
if (function_exists('gzencode')) {
$return['gz'] = 'gzip';
$return['bz2'] = 'bzip2';
}
// ZipArchive requires temporary file, ZIP can be created by gzcompress - see PEAR File_Archive
- return html_select("output", $return, "text", $select);
+ return html_select("output", $return, $value, $select);
}
/** Returns export format options
* @param bool generate select (otherwise radio)
+ * @param string
* @return string
*/
- function dumpFormat($select) {
- return html_select("format", array('sql' => 'SQL', 'csv' => 'CSV'), "sql", $select);
+ function dumpFormat($select, $value = "") {
+ return html_select("format", array('sql' => 'SQL', 'csv' => 'CSV,', 'csv;' => 'CSV;'), $value, $select);
}
/** Prints navigation after Adminer title
* @return null
*/
function navigation($missing) {
- global $VERSION, $connection;
+ global $VERSION, $connection, $token;
?>
<h1>
<a href="http://www.adminer.org/" id="h1"><?php echo $this->name(); ?></a>
<p class="logout">
<a href="<?php echo h(ME); ?>sql="><?php echo bold(lang('SQL command'), isset($_GET["sql"])); ?></a>
<a href="<?php echo h(ME); ?>dump=<?php echo urlencode(isset($_GET["table"]) ? $_GET["table"] : $_GET["select"]); ?>"><?php echo bold(lang('Dump'), isset($_GET["dump"])); ?></a>
-<input type="hidden" name="token" value="<?php echo $_SESSION["tokens"][$_GET["server"]]; ?>">
+<input type="hidden" name="token" value="<?php echo $token; ?>">
<input type="submit" name="logout" value="<?php echo lang('Logout'); ?>">
</p>
</form>
<form action="">
<p>
-<?php echo SID_FORM; ?>
-<?php if ($_GET["server"] != "") { ?><input type="hidden" name="server" value="<?php echo h($_GET["server"]); ?>"><?php } ?>
+<?php hidden_fields_get(); ?>
<?php echo ($databases ? html_select("db", array("" => "(" . lang('database') . ")") + $databases, DB, "this.form.submit();") : '<input name="db" value="' . h(DB) . '">'); ?>
<?php if (isset($_GET["sql"])) { ?><input type="hidden" name="sql" value=""><?php } ?>
<?php if (isset($_GET["schema"])) { ?><input type="hidden" name="schema" value=""><?php } ?>
<?php if (isset($_GET["dump"])) { ?><input type="hidden" name="dump" value=""><?php } ?>
- <input type="submit" value="<?php echo lang('Use'); ?>"<?php echo ($databases ? " class='hidden'" : ""); ?>>
+<input type="submit" value="<?php echo lang('Use'); ?>"<?php echo ($databases ? " class='hidden'" : ""); ?>>
</p>
</form>
<?php
*/
function tablesPrint($tables) {
echo "<p id='tables'>\n";
- foreach ($tables as $table) {
+ foreach ($tables as $table => $type) {
echo '<a href="' . h(ME) . 'select=' . urlencode($table) . '">' . bold(lang('select'), $_GET["select"] == $table) . '</a> ';
echo '<a href="' . h(ME) . 'table=' . urlencode($table) . '">' . bold($this->tableName(array("Name" => $table)), $_GET["table"] == $table) . "</a><br>\n"; //! Adminer::tableName may work with full table status
}
}
$adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer);
+if (!isset($adminer->operators)) {
+ $adminer->operators = $operators;
+}
<?php
+$connection = '';
+
+if (!$drivers) {
+ page_header(lang('No extension'), lang('None of the supported PHP extensions (%s) are available.', implode(", ", $possible_drivers)), null);
+ page_footer("auth");
+ exit;
+}
+
+$token = $_SESSION["token"];
+if (!$_SESSION["token"]) {
+ $_SESSION["token"] = rand(1, 1e6); // defense against cross-site request forgery
+}
+
if (isset($_POST["server"])) {
session_regenerate_id(); // defense against session fixation
- $_SESSION["usernames"][$_POST["server"]] = $_POST["username"];
- $_SESSION["passwords"][$_POST["server"]] = $_POST["password"];
+ $_SESSION["passwords"][$_POST["driver"]][$_POST["server"]][$_POST["username"]] = $_POST["password"];
if ($_POST["permanent"]) {
- cookie("adminer_permanent",
+ cookie("adminer_permanent", //! store separately for each driver, server and username to allow several permanent logins
base64_encode($_POST["server"])
. ":" . base64_encode($_POST["username"])
. ":" . base64_encode(encrypt_string($_POST["password"], $adminer->permanentLogin()))
+ . ":" . base64_encode($_POST["driver"])
);
}
- if (count($_POST) == ($_POST["permanent"] ? 4 : 3)) { // 3 - server, username, password
- $location = ((string) $_GET["server"] === $_POST["server"] ? remove_from_uri(session_name()) : preg_replace('~^([^?]*).*~', '\\1', ME) . ($_POST["server"] != "" ? '?server=' . urlencode($_POST["server"]) : ''));
- if (SID_FORM) {
- $pos = strpos($location, '?');
- $location = ($pos ? substr_replace($location, SID . "&", $pos + 1, 0) : "$location?" . SID);
- }
- redirect($location);
+ if (count($_POST) == ($_POST["permanent"] ? 5 : 4) // 4 - driver, server, username, password
+ || DRIVER != $_POST["driver"]
+ || SERVER != $_POST["server"]
+ || $_GET["username"] !== $_POST["username"] // "0" == "00"
+ ) {
+ preg_match('~([^?]*)\\??(.*)~', remove_from_uri(implode("|", array_keys($drivers)) . "|username|" . session_name()), $match);
+ redirect("$match[1]?"
+ . (SID ? SID . "&" : "")
+ . ($_POST["driver"] != "server" || $_POST["server"] != "" ? urlencode($_POST["driver"]) . "=" . urlencode($_POST["server"]) . "&" : "")
+ . "username=" . urlencode($_POST["username"])
+ . ($match[2] ? "&$match[2]" : "")
+ );
}
- $_GET["server"] = $_POST["server"]; //! used also in ME
} elseif ($_POST["logout"]) {
- $token = $_SESSION["tokens"][$_GET["server"]];
if ($token && $_POST["token"] != $token) {
page_header(lang('Logout'), lang('Invalid CSRF token. Send the form again.'));
page_footer("db");
exit;
} else {
- foreach (array("usernames", "passwords", "databases", "tokens", "history") as $val) {
- unset($_SESSION[$val][$_GET["server"]]);
- }
- if (!isset($_SESSION["passwords"])) { // don't require login to logout
- $_SESSION["passwords"] = array();
+ foreach (array("passwords", "databases", "history") as $key) {
+ set_session($key, null);
}
cookie("adminer_permanent", "");
- redirect(substr(preg_replace('~db=[^&]*&~', '', ME), 0, -1), lang('Logout successful.'));
+ redirect(substr(preg_replace('~(username|db)=[^&]*&~', '', ME), 0, -1), lang('Logout successful.'));
}
-} elseif ($_COOKIE["adminer_permanent"] && !isset($_SESSION["usernames"][$_GET["server"]])) {
- list($server, $username, $cipher) = array_map('base64_decode', explode(":", $_COOKIE["adminer_permanent"]));
- if (($_GET["server"] == "" && !$_POST) || $server == $_GET["server"]) {
+} elseif ($_COOKIE["adminer_permanent"]) {
+ list($server, $username, $cipher, $system) = array_map('base64_decode', explode(":", $_COOKIE["adminer_permanent"])); // $driver is a global variable
+ if ($server == SERVER && $username === $_GET["username"] && $system == DRIVER) {
session_regenerate_id(); // defense against session fixation
- $_SESSION["usernames"][$server] = $username;
- $_SESSION["passwords"][$server] = decrypt_string($cipher, $adminer->permanentLogin());
- if ($server != $_GET["server"]) {
- redirect(preg_replace('~^([^?]*).*~', '\\1', ME) . '?server=' . urlencode($server));
- }
+ set_session("passwords", decrypt_string($cipher, $adminer->permanentLogin()));
}
+ //! redirect ?select=tab
}
function auth_error($exception = null) {
- global $connection, $adminer;
+ global $connection, $adminer, $token;
$session_name = session_name();
- $username = $_SESSION["usernames"][$_GET["server"]];
- unset($_SESSION["usernames"][$_GET["server"]]);
- page_header(lang('Login'), (isset($username) ? h($exception ? $exception->getMessage() : (is_string($connection) ? $connection : lang('Invalid credentials.')))
- : (!$_COOKIE[$session_name] && $_GET[$session_name] && ini_get("session.use_only_cookies") ? lang('Session support must be enabled.')
- : (($_COOKIE[$session_name] || $_GET[$session_name]) && !isset($_SESSION["passwords"]) ? lang('Session expired, please login again.')
- : ""))), null);
+ $error = "";
+ if (!$_COOKIE[$session_name] && $_GET[$session_name] && ini_bool("session.use_only_cookies")) {
+ $error = lang('Session support must be enabled.');
+ } elseif (isset($_GET["username"])) {
+ if (($_COOKIE[$session_name] || $_GET[$session_name]) && !$token) {
+ $error = lang('Session expired, please login again.');
+ } else {
+ $password = get_session("passwords");
+ if (isset($password)) {
+ $error = h($exception ? $exception->getMessage() : (is_string($connection) ? $connection : lang('Invalid credentials.')));
+ }
+ }
+ }
+ page_header(lang('Login'), $error, null);
echo "<form action='' method='post'>\n";
- $adminer->loginForm($username);
+ $adminer->loginForm();
echo "<div>";
- hidden_fields($_POST, array("server", "username", "password")); // expired session
+ hidden_fields($_POST, array("driver", "server", "username", "password", "permanent")); // expired session
echo "</div>\n";
echo "</form>\n";
page_footer("auth");
}
-$username = &$_SESSION["usernames"][$_GET["server"]];
-if (!isset($username)) {
- $username = $_GET["username"]; // default username can be passed in URL
+if (isset($_GET["username"]) && class_exists("Min_DB")) { // doesn't exists with passing wrong driver
+ $connection = connect();
}
-$connection = (isset($username) ? connect() : '');
-if (is_string($connection) || !$adminer->login($username, $_SESSION["passwords"][$_GET["server"]])) {
+if (is_string($connection) || !$adminer->login($_GET["username"], get_session("passwords"))) {
auth_error();
exit;
}
-unset($username);
-if (!$_SESSION["tokens"][$_GET["server"]]) {
- $_SESSION["tokens"][$_GET["server"]] = rand(1, 1e6); // defense against cross-site request forgery
-}
+$token = $_SESSION["token"]; ///< @var string CSRF protection
if (isset($_POST["server"]) && $_POST["token"]) {
- $_POST["token"] = $_SESSION["tokens"][$_GET["server"]];
+ $_POST["token"] = $token; // reset token after explicit login
}
-$token = $_SESSION["tokens"][$_GET["server"]]; ///< @var string CSRF protection
$error = ($_POST ///< @var string
? ($_POST["token"] == $token ? "" : lang('Invalid CSRF token. Send the form again.'))
: ($_SERVER["REQUEST_METHOD"] != "POST" ? "" : lang('Too big POST data. Reduce the data or increase the %s configuration directive.', '"post_max_size"')) // posted form with no data means that post_max_size exceeded because Adminer always sends token at least
exit;
}
+include "../adminer/include/functions.inc.php";
+
if (!isset($_SERVER["REQUEST_URI"])) {
- $_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"] . ($_SERVER["QUERY_STRING"] != "" ? "?$_SERVER[QUERY_STRING]" : "");
+ $_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"] . ($_SERVER["QUERY_STRING"] != "" ? "?$_SERVER[QUERY_STRING]" : ""); // IIS 5 compatibility
}
@ini_set("session.use_trans_sid", false); // protect links in export, @ - may be disabled
-if (!ini_get("session.auto_start")) {
+if (!ini_bool("session.auto_start")) {
session_name("adminer_sid"); // use specific session name to get own namespace
$params = array(0, preg_replace('~\\?.*~', '', $_SERVER["REQUEST_URI"]), "", $_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off"));
if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
}
@set_time_limit(0); // @ - can be disabled
-include "../adminer/include/version.inc.php";
-include "../adminer/include/functions.inc.php";
+include "../adminer/include/lang.inc.php";
+include "../adminer/lang/$LANG.inc.php";
+include "../adminer/include/pdo.inc.php";
+include "../adminer/drivers/sqlite.inc.php";
+include "../adminer/drivers/pgsql.inc.php";
+include "../adminer/drivers/mssql.inc.php";
+include "../adminer/drivers/mysql.inc.php"; // must be included as last driver
+define("SERVER", $_GET[DRIVER]); // read from pgsql=localhost
define("DB", $_GET["db"]); // for the sake of speed and size
-define("SID_FORM", SID && !ini_get("session.use_only_cookies") ? '<input type="hidden" name="' . session_name() . '" value="' . h(session_id()) . '">' : '');
-define("ME", preg_replace('~^[^?]*/([^?]*).*~', '\\1', $_SERVER["REQUEST_URI"]) . '?' . (SID_FORM ? SID . '&' : '') . ($_GET["server"] != "" ? 'server=' . urlencode($_GET["server"]) . '&' : '') . (DB != "" ? 'db=' . urlencode(DB) . '&' : ''));
+define("ME", preg_replace('~^[^?]*/([^?]*).*~', '\\1', $_SERVER["REQUEST_URI"]) . '?'
+ . (SID && !$_COOKIE ? SID . '&' : '') // !$_COOKIE - don't pass SID with permanent login
+ . (SERVER !== null ? DRIVER . "=" . urlencode(SERVER) . '&' : '')
+ . (isset($_GET["username"]) ? "username=" . urlencode($_GET["username"]) . '&' : '')
+ . (DB != "" ? 'db=' . urlencode(DB) . '&' : '')
+);
-include "../adminer/include/lang.inc.php";
-include "../adminer/lang/$LANG.inc.php";
+include "../adminer/include/version.inc.php";
include "./include/adminer.inc.php";
include "../adminer/include/design.inc.php";
-include "../adminer/include/pdo.inc.php";
-include "../adminer/include/mysql.inc.php";
include "../adminer/include/xxtea.inc.php";
include "../adminer/include/auth.inc.php";
include "./include/connect.inc.php";
include "./include/export.inc.php";
session_cache_limiter(""); // to allow restarting session
-if (!ini_get("session.use_cookies") || @ini_set("session.use_cookies", false) !== false) { // @ - may be disabled
+if (!ini_bool("session.use_cookies") || @ini_set("session.use_cookies", false) !== false) { // @ - may be disabled
session_write_close(); // improves concurrency if a user opens several pages at once, may be restarted later
}
<?php
function connect_error() {
- global $connection, $VERSION, $token, $error;
+ global $connection, $VERSION, $token, $error, $drivers;
+ $databases = array();
if (DB != "") {
- page_header(lang('Database') . ": " . h(DB), lang('Invalid database.'), false);
+ page_header(lang('Database') . ": " . h(DB), lang('Invalid database.'), true);
} else {
if ($_POST["db"] && !$error) {
- unset($_SESSION["databases"][$_GET["server"]]);
+ set_session("databases", null);
foreach ($_POST["db"] as $db) {
if (!queries("DROP DATABASE " . idf_escape($db))) {
break;
queries_redirect(substr(ME, 0, -1), lang('Database has been dropped.'), !$connection->error);
}
- page_header(lang('Select database'), $error, null);
- echo "<p>";
+ page_header(lang('Select database'), $error, false);
+ echo "<p><a href='" . h(ME) . "database='>" . lang('Create new database') . "</a>\n";
foreach (array(
- 'database' => lang('Create new database'),
'privileges' => lang('Privileges'),
'processlist' => lang('Process list'),
'variables' => lang('Variables'),
'status' => lang('Status'),
) as $key => $val) {
- echo "<a href='" . h(ME) . "$key='>$val</a>\n";
+ if (support($key)) {
+ echo "<a href='" . h(ME) . "$key='>$val</a>\n";
+ }
}
- echo "<p>" . lang('MySQL version: %s through PHP extension %s', "<b" . ($connection->server_info < 4.1 ? " class='binary'" : "") . ">$connection->server_info</b>", "<b>$connection->extension</b>") . "\n";
- echo "<p>" . lang('Logged as: %s', "<b>" . h($connection->result($connection->query("SELECT USER()"))) . "</b>") . "\n";
+ echo "<p>" . lang('%s version: %s through PHP extension %s', $drivers[DRIVER], "<b>$connection->server_info</b>", "<b>$connection->extension</b>") . "\n";
+ echo "<p>" . lang('Logged as: %s', "<b>" . h(logged_user()) . "</b>") . "\n";
$databases = get_databases();
if ($databases) {
$collations = collations();
echo "<form action='' method='post'>\n";
echo "<table cellspacing='0' onclick='tableClick(event);'>\n";
- echo "<thead><tr><td><input type='hidden' name='token' value='$token'> <th>" . lang('Database') . "<td>" . lang('Collation') . "</thead>\n";
+ echo "<thead><tr><td><input type='hidden' name='token' value='$token'> <th>" . lang('Database') . "<td>" . lang('Collation') . "<td>" . lang('Tables') . "</thead>\n";
foreach ($databases as $db) {
$root = h(ME) . "db=" . urlencode($db);
echo "<tr" . odd() . "><td>" . checkbox("db[]", $db, in_array($db, (array) $_POST["db"]));
echo "<th><a href='$root'>" . h($db) . "</a>";
echo "<td><a href='$root&database='>" . nbsp(db_collation($db, $collations)) . "</a>";
+ echo "<td align='right'><a href='$root&schema=' id='tables-" . h($db) . "'>?</a>";
echo "\n";
}
echo "</table>\n";
}
}
page_footer("db");
+ echo "<script type='text/javascript'>\n";
+ foreach (count_tables($databases) as $db => $val) {
+ echo "setHtml('tables-" . addcslashes($db, "\\'/") . "', '$val');\n";
+ }
+ echo "</script>\n";
}
if (isset($_GET["status"])) {
}
if (!(DB != "" ? $connection->select_db(DB) : isset($_GET["sql"]) || isset($_GET["dump"]) || isset($_GET["database"]) || isset($_GET["processlist"]) || isset($_GET["privileges"]) || isset($_GET["user"]) || isset($_GET["variables"]))) {
if (DB != "") {
- unset($_SESSION["databases"][$_GET["server"]]);
+ set_session("databases", null);
}
connect_error(); // separate function to catch SQLite error
exit;
<?php
+/** Print HTML header
+* @param string used in title, breadcrumb and heading
+* @param string
+* @param mixed array("key" => "link=desc", "key2" => array("link", "desc")), null for nothing, false for driver only, true for driver and server
+* @param string used after colon in title and heading
+* @return null
+*/
function page_header($title, $error = "", $breadcrumb = array(), $title2 = "") {
- global $LANG, $VERSION, $adminer, $connection;
+ global $LANG, $VERSION, $adminer, $connection, $drivers;
header("Content-Type: text/html; charset=utf-8");
- header("X-Frame-Options: deny"); // ClickJacking protection in IE8, Safari 4, Chrome 2, NoScript plugin
+ header("X-Frame-Options: deny"); // ClickJacking protection in IE8, Safari 4, Chrome 2, Firefox NoScript plugin
$title_all = $title . ($title2 != "" ? ": " . h($title2) : "");
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta name="robots" content="noindex">
-<title><?php echo $title_all . ($_GET["server"] != "" && $_GET["server"] != "localhost" ? h(" - $_GET[server]") : "") . " - " . $adminer->name(); ?></title>
+<title><?php echo $title_all . (SERVER != "" && SERVER != "localhost" ? h(" - " . SERVER) : "") . " - " . $adminer->name(); ?></title>
<link rel="shortcut icon" type="image/x-icon" href="../adminer/static/favicon.ico">
<link rel="stylesheet" type="text/css" href="../adminer/static/default.css<?php // Ondrej Valka, http://valka.info ?>">
<?php if (file_exists("adminer.css")) { ?>
<link rel="stylesheet" type="text/css" href="adminer.css">
<?php } ?>
-<body onload="bodyLoad('<?php echo substr($connection->server_info, 0, 3); ?>');<?php echo (isset($_COOKIE["adminer_version"]) ? "" : " verifyVersion();"); ?>">
+<body onload="bodyLoad('<?php echo (is_object($connection) ? substr($connection->server_info, 0, 3) : ""); ?>');<?php echo (isset($_COOKIE["adminer_version"]) ? "" : " verifyVersion();"); ?>">
<script type="text/javascript" src="../adminer/static/functions.js"></script>
<script type="text/javascript" src="static/editing.js"></script>
<div id="content">
<?php
if (isset($breadcrumb)) {
+ $link = substr(preg_replace('~(username|db)=[^&]*&~', '', ME), 0, -1);
+ echo '<p id="breadcrumb"><a href="' . ($link ? h($link) : ".") . '">' . $drivers[DRIVER] . '</a> » ';
$link = substr(preg_replace('~db=[^&]*&~', '', ME), 0, -1);
- echo '<p id="breadcrumb"><a href="' . ($link != "" ? h($link) : ".") . '">' . (isset($_GET["server"]) ? h($_GET["server"]) : lang('Server')) . '</a> » ';
- if (is_array($breadcrumb)) {
- if (DB != "") {
- echo '<a href="' . h(substr(ME, 0, -1)) . '">' . h(DB) . '</a> » ';
- }
- foreach ($breadcrumb as $key => $val) {
- $desc = (is_array($val) ? $val[1] : $val);
- if ($desc != "") {
- echo '<a href="' . h(ME . "$key=") . urlencode(is_array($val) ? $val[0] : $val) . '">' . h($desc) . '</a> » ';
+ $server = (SERVER != "" ? h(SERVER) : lang('Server'));
+ if ($breadcrumb === false) {
+ echo "$server\n";
+ } else {
+ echo "<a href='" . ($link ? h($link) : ".") . "'>$server</a> » ";
+ if (is_array($breadcrumb)) {
+ if (DB != "") {
+ echo '<a href="' . h(substr(ME, 0, -1)) . '">' . h(DB) . '</a> » ';
+ }
+ foreach ($breadcrumb as $key => $val) {
+ $desc = (is_array($val) ? $val[1] : $val);
+ if ($desc != "") {
+ echo '<a href="' . h(ME . "$key=") . urlencode(is_array($val) ? $val[0] : $val) . '">' . h($desc) . '</a> » ';
+ }
}
}
+ echo "$title\n";
}
- echo "$title\n";
}
echo "<h2>$title_all</h2>\n";
restart_session();
echo "<div class='message'>" . implode("</div>\n<div class='message'>", $_SESSION["messages"]) . "</div>\n";
$_SESSION["messages"] = array();
}
- if (!$_POST && !isset($_SESSION["passwords"])) { // used in auth
- $_SESSION["passwords"] = array();
- }
- $databases = &$_SESSION["databases"][$_GET["server"]];
+ $databases = &get_session("databases");
if (DB != "" && $databases && !in_array(DB, $databases, true)) {
$databases = null;
}
}
}
-function page_footer($missing = false) {
+/** Print HTML footer
+* @param string auth|db
+* @return null
+*/
+function page_footer($missing = "") {
global $adminer;
?>
</div>
<?php $adminer->navigation($missing); ?>
</div>
<?php
+ // don't wait for code after footer
+ session_write_close();
+ ob_flush();
+ flush();
}
*/
function referencable_primary($self) {
$return = array(); // table_name => field
- foreach (table_status_referencable() as $table_name => $table) {
- if ($table_name != $self) {
+ foreach (table_status() as $table_name => $table) {
+ if ($table_name != $self && fk_support($table)) {
foreach (fields($table_name) as $field) {
if ($field["primary"]) {
if ($return[$table_name]) { // multi column primary key
/** Create SQL string from field
* @param array basic field information
* @param array information about field type
-* @return string
+* @return array array("field", "type", "NULL", "DEFAULT", "ON UPDATE", "COMMENT", "AUTO_INCREMENT")
*/
function process_field($field, $type_field) {
global $connection;
- return idf_escape($field["field"]) . process_type($type_field)
- . ($field["null"] ? " NULL" : " NOT NULL") // NULL for timestamp
- . (!isset($field["default"]) ? "" : " DEFAULT " . ($field["type"] == "timestamp" && eregi("^CURRENT_TIMESTAMP$", $field["default"]) ? $field["default"] : $connection->quote($field["default"])))
- . ($field["on_update"] ? " ON UPDATE $field[on_update]" : "")
- . " COMMENT " . $connection->quote($field["comment"])
- ;
+ return array(
+ idf_escape($field["field"]),
+ process_type($type_field),
+ ($field["null"] ? " NULL" : " NOT NULL"), // NULL for timestamp
+ (isset($field["default"]) ? " DEFAULT " . ($field["type"] == "timestamp" && eregi("^CURRENT_TIMESTAMP$", $field["default"]) ? $field["default"] : $connection->quote($field["default"])) : ""),
+ ($field["on_update"] ? " ON UPDATE $field[on_update]" : ""),
+ (support("comment") && $field["comment"] != "" ? " COMMENT " . $connection->quote($field["comment"]) : ""),
+ ($field["auto_increment"] ? auto_increment() : ""),
+ );
}
/** Get type class to use in CSS
* @param array returned by referencable_primary()
* @return bool column comments used
*/
-function edit_fields($fields, $collations, $type = "TABLE", $allowed = 0, $foreign_keys = array()) {
+function edit_fields($fields, $collations, $type = "TABLE", $allowed = 0, $foreign_keys = array(), $comments = false) {
global $inout;
- $column_comments = false;
foreach ($fields as $field) {
if ($field["comment"] != "") {
- $column_comments = true;
+ $comments = true;
break;
}
}
<td><?php echo lang('Options'); ?>
<?php if ($type == "TABLE") { ?>
<td>NULL
-<td><input type="radio" name="auto_increment_col" value=""><acronym title="<?php echo lang('Auto Increment'); ?>">A_I</acronym>
+<td><input type="radio" name="auto_increment_col" value=""><acronym title="<?php echo lang('Auto Increment'); ?>">AI</acronym>
<td class="hidden"><?php echo lang('Default values'); ?>
-<td<?php echo ($column_comments ? "" : " class='hidden'"); ?>><?php echo lang('Comment'); ?>
+<?php echo (support("comment") ? "<td" . ($comments ? "" : " class='hidden'") . ">" . lang('Comment') : ""); ?>
<?php } ?>
<td><?php echo "<input type='image' name='add[0]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "'>"; ?><script type="text/javascript">row_count = <?php echo count($fields); ?>;</script>
</thead>
$display = (isset($_POST["add"][$i-1]) || (isset($field["field"]) && !$_POST["drop_col"][$i]));
?>
<tr<?php echo ($display ? "" : " style='display: none;'"); ?>>
-<?php
-if ($type == "PROCEDURE") {
- echo "<td>" . html_select("fields[$i][inout]", $inout, $field["inout"]);
-}
-?>
+<?php echo ($type == "PROCEDURE" ? "<td>" . html_select("fields[$i][inout]", $inout, $field["inout"]) : ""); ?>
<th><?php if ($display) { ?><input name="fields[<?php echo $i; ?>][field]" value="<?php echo h($field["field"]); ?>" onchange="<?php echo ($field["field"] != "" || count($fields) > 1 ? "" : "editingAddRow(this, $allowed); "); ?>editingNameChange(this);" maxlength="64"><?php } ?><input type="hidden" name="fields[<?php echo $i; ?>][orig]" value="<?php echo h($field[($_POST ? "orig" : "field")]); ?>">
<?php edit_type("fields[$i]", $field, $collations, $foreign_keys); ?>
<?php if ($type == "TABLE") { ?>
<td><?php echo checkbox("fields[$i][null]", 1, $field["null"]); ?>
<td><input type="radio" name="auto_increment_col" value="<?php echo $i; ?>"<?php if ($field["auto_increment"]) { ?> checked<?php } ?>>
<td class="hidden"><?php echo checkbox("fields[$i][has_default]", 1, $field["has_default"]); ?><input name="fields[<?php echo $i; ?>][default]" value="<?php echo h($field["default"]); ?>" onchange="this.previousSibling.checked = true;">
-<td<?php echo ($column_comments ? "" : " class='hidden'"); ?>><input name="fields[<?php echo $i; ?>][comment]" value="<?php echo h($field["comment"]); ?>" maxlength="255">
+<?php echo (support("comment") ? "<td" . ($comments ? "" : " class='hidden'") . "><input name='fields[$i][comment]' value='" . h($field["comment"]) . "' maxlength='255'>" : ""); ?>
<?php } ?>
<?php
+ //! hide operations not supported by the driver - column change, adding column not at the end, drop column, ...
echo "<td><input type='image' name='add[$i]' src='../adminer/static/plus.gif' alt='+' title='" . lang('Add next') . "' onclick='return !editingAddRow(this, $allowed, 1);'>";
echo " <input type='image' name='drop_col[$i]' src='../adminer/static/cross.gif' alt='x' title='" . lang('Remove') . "' onclick='return !editingRemoveRow(this);'>";
echo " <input type='image' name='up[$i]' src='../adminer/static/up.gif' alt='^' title='" . lang('Move up') . "'>";
echo " <input type='image' name='down[$i]' src='../adminer/static/down.gif' alt='v' title='" . lang('Move down') . "'>";
echo "\n";
}
- return $column_comments;
+ return $comments;
}
/** Move fields up and down or add field
* @return string
*/
function normalize_enum($match) {
- return "'" . str_replace("'", "''", addcslashes(stripcslashes(str_replace($match[0]{0} . $match[0]{0}, $match[0]{0}, substr($match[0], 1, -1))), '\\')) . "'";
+ return "'" . str_replace("'", "''", addcslashes(stripcslashes(str_replace($match[0][0] . $match[0][0], $match[0][0], substr($match[0], 1, -1))), '\\')) . "'";
}
/** Get information about stored routine
$aliases = array("bit" => "tinyint", "bool" => "tinyint", "boolean" => "tinyint", "integer" => "int", "double precision" => "float", "real" => "float", "dec" => "decimal", "numeric" => "decimal", "fixed" => "decimal", "national char" => "char", "national varchar" => "varchar");
$type_pattern = "(" . implode("|", array_keys($types + $aliases)) . ")(?:\\s*\\(((?:[^'\")]*|$enum_length)+)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s]+)['\"]?)?";
$pattern = "\\s*(" . ($type == "FUNCTION" ? "" : implode("|", $inout)) . ")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$type_pattern";
- $create = $connection->result($connection->query("SHOW CREATE $type " . idf_escape($name)), 2);
+ $create = $connection->result("SHOW CREATE $type " . idf_escape($name), 2);
preg_match("~\\(((?:$pattern\\s*,?)*)\\)" . ($type == "FUNCTION" ? "\\s*RETURNS\\s+$type_pattern" : "") . "\\s*(.*)~is", $create, $match);
$fields = array();
preg_match_all("~$pattern\\s*,?~is", $match[1], $matches, PREG_SET_ORDER);
function dump_triggers($table, $style) {
global $connection;
- if ($_POST["format"] == "sql" && $style && $connection->server_info >= 5) {
+ if ($_POST["format"] == "sql" && $style && support("trigger")) {
$result = $connection->query("SHOW TRIGGERS LIKE " . $connection->quote(addcslashes($table, "%_")));
if ($result->num_rows) {
$s = "\nDELIMITER ;;\n";
function dump_table($table, $style, $is_view = false) {
global $connection;
- if ($_POST["format"] == "csv") {
+ if ($_POST["format"] != "sql") {
echo "\xef\xbb\xbf"; // UTF-8 byte order mark
if ($style) {
dump_csv(array_keys(fields($table)));
}
} elseif ($style) {
- $result = $connection->query("SHOW CREATE TABLE " . idf_escape($table));
- if ($result) {
+ $create = create_sql($table);
+ if ($create) {
if ($style == "DROP+CREATE") {
echo "DROP " . ($is_view ? "VIEW" : "TABLE") . " IF EXISTS " . idf_escape($table) . ";\n";
}
- $create = $connection->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";
}
if ($style == "CREATE+ALTER" && !$is_view) {
}
function dump_data($table, $style, $select = "") {
- global $connection;
- $max_packet = 1048576; // default, minimum is 1024
+ global $connection, $driver;
+ $max_packet = ($driver == "sqlite" ? 0 : 1048576); // default, minimum is 1024
if ($style) {
- if ($_POST["format"] != "csv" && $style == "TRUNCATE+INSERT") {
+ if ($_POST["format"] == "sql" && $style == "TRUNCATE+INSERT") {
echo "TRUNCATE " . idf_escape($table) . ";\n";
}
$fields = fields($table);
$insert = "";
$buffer = "";
while ($row = $result->fetch_assoc()) {
- if ($_POST["format"] == "csv") {
+ if ($_POST["format"] != "sql") {
dump_csv($row);
} else {
if (!$insert) {
}
echo "$insert ($s) ON DUPLICATE KEY UPDATE " . implode(", ", $set) . ";\n";
} else {
- $s = "\n($s)";
+ $s = ($max_packet ? "\n" : " ") . "($s)";
if (!$buffer) {
$buffer = $insert . $s;
} elseif (strlen($buffer) + 2 + strlen($s) < $max_packet) { // 2 - separator and terminator length
}
}
}
- if ($_POST["format"] != "csv" && $style != "INSERT+UPDATE" && $buffer) {
+ if ($_POST["format"] == "sql" && $style != "INSERT+UPDATE" && $buffer) {
$buffer .= ";\n";
echo $buffer;
}
return $connection;
}
-/** Escape database identifier
-* @param string
-* @return string
-*/
-function idf_escape($idf) {
- return "`" . str_replace("`", "``", $idf) . "`";
-}
-
/** Unescape database identifier
* @param string text inside ``
* @return string
*/
function idf_unescape($idf) {
- return str_replace("``", "`", $idf);
+ return str_replace($idf[0] . $idf[0], $idf[0], substr($idf, 1, -1));
}
/** Escape string to use inside ''
return (trim($string) != "" ? h($string) : " ");
}
+/** Convert \n to <br>
+* @param string
+* @return string
+*/
+function nl_br($string) {
+ return str_replace("\n", "<br>", $string); // nl2br() uses XHTML before PHP 5.3
+}
+
/** Generate HTML checkbox
* @param string
* @param string
function checkbox($name, $value, $checked, $label = "", $onclick = "") {
static $id = 0;
$id++;
- $return = "<input type='checkbox' name='$name' value='" . h($value) . "'" . ($checked ? " checked" : "") . ($onclick ? " onclick=\"$onclick\"" : "") . " id='checkbox-$id'>";
+ $return = "<input type='checkbox'" . ($name ? " name='$name' value='" . h($value) . "'" : "") . ($checked ? " checked" : "") . ($onclick ? " onclick=\"$onclick\"" : "") . " id='checkbox-$id'>";
return ($label != "" ? "<label for='checkbox-$id'>$return" . h($label) . "</label>" : $return);
}
return $return;
}
+/** Get INI boolean value
+* @param string
+* @return bool
+*/
+function ini_bool($ini) {
+ $val = ini_get($ini);
+ return (eregi('^(on|true|yes)$', $val) || (int) $val); // boolean values set by php_value are strings
+}
+
/** Get list of values from database
* @param string
* @param mixed
return $return;
}
+/** Get keys from first column and values from second
+* @param string
+* @param Min_DB
+* @return array
+*/
+function get_key_vals($query, $connection2 = null) {
+ global $connection;
+ if (!is_object($connection2)) {
+ $connection2 = $connection;
+ }
+ $return = array();
+ $result = $connection2->query($query);
+ while ($row = $result->fetch_row()) {
+ $return[$row[0]] = $row[1];
+ }
+ return $return;
+}
+
/** Find unique identifier of a row
* @param array
* @param array result of indexes()
* @return bool
*/
function cookie($name, $value) {
- $params = array($name, $value, time() + 2592000, preg_replace('~\\?.*~', '', $_SERVER["REQUEST_URI"]), "", $_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off")); // 2592000 = 30 * 24 * 60 * 60
+ $params = array(
+ $name,
+ (ereg("\n", $value) ? "" : $value), // HTTP Response Splitting protection in PHP < 5.1.2
+ time() + 2592000, // 2592000 - 30 days
+ preg_replace('~\\?.*~', '', $_SERVER["REQUEST_URI"]),
+ "",
+ $_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off")
+ );
if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
$params[] = true; // HttpOnly
}
* @return null
*/
function restart_session() {
- if (!ini_get("session.use_cookies")) {
+ if (!ini_bool("session.use_cookies")) {
session_start();
}
}
+/** Get session variable for current server
+* @param string
+* @return mixed
+*/
+function &get_session($key) {
+ return $_SESSION[$key][DRIVER][SERVER][$_GET["username"]];
+}
+
+/** Set session variable for current server
+* @param string
+* @param mixed
+* @return mixed
+*/
+function set_session($key, $val) {
+ $_SESSION[$key][DRIVER][SERVER][$_GET["username"]] = $val; // used also in auth.inc.php
+}
+
/** Send Location header and exit
* @param string null to only set a message
* @param string
}
}
+/** Print hidden fields for GET forms
+* @return null
+*/
+function hidden_fields_get() {
+ echo (SID && !$_COOKIE ? '<input type="hidden" name="' . session_name() . '" value="' . h(session_id()) . '">' : '');
+ echo (SERVER !== null ? '<input type="hidden" name="' . DRIVER . '" value="' . h(SERVER) . '">' : "");
+ echo '<input type="hidden" name="username" value="' . h($_GET["username"]) . '">';
+}
+
/** Find out foreign keys for each column
* @param string
* @return array array($col => array())
return $return;
}
+/** Print enum input field
+* @param string "radio"|"checkbox"
+* @param string
+* @param array
+* @param mixed int|string|array
+* @return null
+*/
+function enum_input($type, $name, $field, $value) {
+ preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
+ foreach ($matches[1] as $i => $val) {
+ $val = stripcslashes(str_replace("''", "'", $val));
+ $checked = (is_int($value) ? $value == $i+1 : (is_array($value) ? in_array($i+1, $value) : $value === $val));
+ echo " <label><input type='$type' name='$name' value='" . ($i+1) . "'" . ($checked ? ' checked' : '') . '>' . h($val) . '</label>';
+ }
+}
+
/** Print edit input field
* @param array one field from fields()
* @param mixed
* @return null
*/
function input($field, $value, $function) {
- global $types, $adminer;
+ global $types, $adminer, $driver;
$name = h(bracket_escape($field["field"]));
echo "<td class='function'>";
$functions = (isset($_GET["select"]) ? array("orig" => lang('original')) : array()) + $adminer->editFunctions($field);
if ($field["type"] == "enum") {
echo nbsp($functions[""]) . "<td>" . ($functions["orig"] ? "<label><input type='radio' name='fields[$name]' value='-1' checked><em>$functions[orig]</em></label> " : "");
echo $adminer->editInput($_GET["edit"], $field, " name='fields[$name]'", $value);
- preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
- foreach ($matches[1] as $i => $val) {
- $val = stripcslashes(str_replace("''", "'", $val));
- $checked = (is_int($value) ? $value == $i+1 : $value === $val);
- echo " <label><input type='radio' name='fields[$name]' value='" . ($i+1) . "'" . ($checked ? ' checked' : '') . '>' . h($val) . '</label>';
- }
+ enum_input("radio", "fields[$name]", $field, $value);
} else {
$first = 0;
foreach ($functions as $key => $val) {
$checked = (is_int($value) ? ($value >> $i) & 1 : in_array($val, explode(",", $value), true));
echo " <label><input type='checkbox' name='fields[$name][$i]' value='" . (1 << $i) . "'" . ($checked ? ' checked' : '') . "$onchange>" . h($val) . '</label>';
}
- } elseif (ereg('binary|blob', $field["type"]) && ini_get("file_uploads")) {
+ } elseif (ereg('binary|blob|bytea', $field["type"]) && ini_bool("file_uploads")) {
echo "<input type='file' name='fields-$name'$onchange>";
} elseif (ereg('text|blob', $field["type"])) {
- echo "<textarea cols='50' rows='12'$attrs>" . h($value) . '</textarea>';
+ echo "<textarea cols='50' rows='" . ($driver != "sqlite" || ereg("\n", $value) ? 12 : 1) . "'$attrs>" . h($value) . '</textarea>';
} 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));
$idf = bracket_escape($field["field"]);
$function = $_POST["function"][$idf];
$value = $_POST["fields"][$idf];
- if ($field["type"] == "enum" ? $value == -1 : $function == "orig") {
+ if ($field["type"] == "enum") {
+ if ($value == -1) {
+ return false;
+ }
+ if ($value == "") {
+ return "NULL";
+ }
+ return intval($value);
+ }
+ if ($field["auto_increment"] && $value == "") {
+ return null;
+ }
+ if ($function == "orig") {
return false;
- } elseif ($field["type"] == "enum" || $field["auto_increment"] ? $value == "" : $function == "NULL") {
+ }
+ if ($function == "NULL") {
return "NULL";
- } elseif ($field["type"] == "enum") {
- return intval($value);
- } elseif ($field["type"] == "set") {
+ }
+ if ($field["type"] == "set") {
return array_sum((array) $value);
- } elseif (ereg('binary|blob', $field["type"]) && ini_get("file_uploads")) {
+ }
+ if (ereg('binary|blob|bytea', $field["type"]) && ini_bool("file_uploads")) {
$file = get_file("fields-$idf");
if (!is_string($file)) {
return false; //! report errors
}
return $connection->quote($file);
- } else {
- return $adminer->processInput($field, $value, $function);
}
+ return $adminer->processInput($field, $value, $function);
}
/** Print results of search in all tables
foreach (table_status() as $table => $table_status) {
$name = $adminer->tableName($table_status);
if (isset($table_status["Engine"]) && $name != "" && (!$_POST["tables"] || in_array($table, $_POST["tables"]))) {
- $result = $connection->query("SELECT 1 FROM " . idf_escape($table) . " WHERE " . implode(" AND ", $adminer->selectSearchProcess(fields($table), array())) . " LIMIT 1");
+ $result = $connection->query("SELECT" . limit("1 FROM " . idf_escape($table) . " WHERE " . implode(" AND ", $adminer->selectSearchProcess(fields($table), array())), 1));
if ($result->num_rows) {
if (!$found) {
echo "<ul>\n";
*/
function dump_csv($row) {
foreach ($row as $key => $val) {
- if (preg_match("~[\"\n,]~", $val) || $val === "") {
+ if (preg_match("~[\"\n,;]~", $val) || $val === "") {
$row[$key] = '"' . str_replace('"', '""', $val) . '"';
}
}
- echo implode(",", $row) . "\n";
+ echo implode(($_POST["format"] == "csv;" ? ";" : ","), $row) . "\n";
}
/** Apply SQL function
* @return string
*/
function apply_sql_function($function, $column) {
- return ($function ? ($function == "count distinct" ? "COUNT(DISTINCT " : strtoupper("$function(")) . "$column)" : $column);
+ return ($function ? ($function == "unixepoch" ? "DATETIME($column, '$function')" : ($function == "count distinct" ? "COUNT(DISTINCT " : strtoupper("$function(")) . "$column)") : $column);
}
/** Check whether the string is e-mail address
+++ /dev/null
-<?php
-// MySQLi supports everything, MySQL doesn't support multiple result sets, PDO_MySQL doesn't support orgtable
-if (extension_loaded("mysqli")) {
- class Min_DB extends MySQLi {
- var $extension = "MySQLi";
-
- function Min_DB() {
- parent::init();
- }
-
- function connect($server, $username, $password) {
- list($host, $port) = explode(":", $server, 2); // part after : is used for port or socket
- return @$this->real_connect(
- ($server != "" ? $host : ini_get("mysqli.default_host")),
- ("$server$username" != "" ? $username : ini_get("mysqli.default_user")),
- ("$server$username$password" != "" ? $password : ini_get("mysqli.default_pw")),
- null,
- (is_numeric($port) ? $port : ini_get("mysqli.default_port")),
- (!is_numeric($port) ? $port : null)
- );
- }
-
- function result($result, $field = 0) {
- if (!$result) {
- return false;
- }
- $row = $result->fetch_array();
- return $row[$field];
- }
-
- function quote($string) {
- return "'" . $this->escape_string($string) . "'";
- }
- }
-
-} elseif (extension_loaded("mysql")) {
- class Min_DB {
- var $extension = "MySQL", $_link, $_result, $server_info, $affected_rows, $error;
-
- function connect($server, $username, $password) {
- $this->_link = @mysql_connect(
- ($server != "" ? $server : ini_get("mysql.default_host")),
- ("$server$username" != "" ? $username : ini_get("mysql.default_user")),
- ("$server$username$password" != "" ? $password : ini_get("mysql.default_password")),
- true,
- 131072 // CLIENT_MULTI_RESULTS for CALL
- );
- if ($this->_link) {
- $this->server_info = mysql_get_server_info($this->_link);
- } else {
- $this->error = mysql_error();
- }
- return (bool) $this->_link;
- }
-
- function quote($string) {
- return "'" . mysql_real_escape_string($string, $this->_link) . "'";
- }
-
- function select_db($database) {
- return mysql_select_db($database, $this->_link);
- }
-
- function query($query, $unbuffered = false) {
- $result = @($unbuffered ? mysql_unbuffered_query($query, $this->_link) : mysql_query($query, $this->_link)); // @ - mute mysql.trace_mode
- if (!$result) {
- $this->error = mysql_error($this->_link);
- return false;
- }
- if ($result === true) {
- $this->affected_rows = mysql_affected_rows($this->_link);
- $this->info = mysql_info($this->_link);
- return true;
- }
- return new Min_Result($result);
- }
-
- function multi_query($query) {
- return $this->_result = $this->query($query);
- }
-
- function store_result() {
- return $this->_result;
- }
-
- function next_result() {
- // MySQL extension doesn't support multiple results
- return false;
- }
-
- function result($result, $field = 0) {
- if (!$result) {
- return false;
- }
- return mysql_result($result->_result, 0, $field);
- }
- }
-
- class Min_Result {
- var $_result, $_offset = 0, $num_rows;
-
- function Min_Result($result) {
- $this->_result = $result;
- $this->num_rows = mysql_num_rows($result);
- }
-
- function fetch_assoc() {
- return mysql_fetch_assoc($this->_result);
- }
-
- function fetch_row() {
- return mysql_fetch_row($this->_result);
- }
-
- function fetch_field() {
- $row = mysql_fetch_field($this->_result, $this->_offset++);
- $row->orgtable = $row->table;
- $row->orgname = $row->name;
- $row->charsetnr = ($row->blob ? 63 : 0);
- return $row;
- }
-
- function __destruct() {
- mysql_free_result($this->_result); //! is not called in PHP 4 which is a problem with mysql.trace_mode
- }
- }
-
-} elseif (extension_loaded("pdo_mysql")) {
- class Min_DB extends Min_PDO {
- var $extension = "PDO_MySQL";
-
- function connect($server, $username, $password) {
- $this->dsn("mysql:host=" . str_replace(":", ";unix_socket=", preg_replace('~:([0-9])~', ';port=\\1', $server)), $username, $password);
- $this->server_info = $this->result($this->query("SELECT VERSION()"));
- return true;
- }
-
- function query($query, $unbuffered = false) {
- $this->setAttribute(1000, !$unbuffered); // 1000 - PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
- return parent::query($query, $unbuffered);
- }
- }
-
-} else {
- page_header(lang('No MySQL extension'), lang('None of the supported PHP extensions (%s) are available.', 'MySQLi, MySQL, PDO_MySQL'), null);
- page_footer("auth");
- exit;
-}
-
-/** Connect to the database
-* @return mixed Min_DB or string for error
-*/
-function connect() {
- global $adminer;
- $connection = new Min_DB;
- $credentials = $adminer->credentials();
- if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
- $connection->query("SET SQL_QUOTE_SHOW_CREATE=1");
- $connection->query("SET NAMES utf8");
- return $connection;
- }
- return $connection->error;
-}
-
-/** Get cached list of databases
-* @param bool
-* @return array
-*/
-function get_databases($flush = true) {
- // SHOW DATABASES can take a very long time so it is cached
- $return = &$_SESSION["databases"][$_GET["server"]];
- if (!isset($return)) {
- restart_session();
- $return = get_vals("SHOW DATABASES");
- if ($flush) {
- ob_flush();
- flush();
- }
- }
- return $return;
-}
-
-/** Get database collation
-* @param string
-* @param array result of collations()
-* @return array
-*/
-function db_collation($db, $collations) {
- global $connection;
- $return = null;
- $result = $connection->query("SHOW CREATE DATABASE " . idf_escape($db));
- if ($result) {
- $create = $connection->result($result, 1);
- if (preg_match('~ COLLATE ([^ ]+)~', $create, $match)) {
- $return = $match[1];
- } elseif (preg_match('~ CHARACTER SET ([^ ]+)~', $create, $match)) {
- // default collation
- $return = $collations[$match[1]][0];
- }
- }
- return $return;
-}
-
-/**Get supported engines
-* @return array
-*/
-function engines() {
- global $connection;
- $return = array();
- $result = $connection->query("SHOW ENGINES");
- while ($row = $result->fetch_assoc()) {
- if (ereg("YES|DEFAULT", $row["Support"])) {
- $return[] = $row["Engine"];
- }
- }
- return $return;
-}
-
-/** Get tables list
-* @return array
-*/
-function tables_list() {
- return get_vals("SHOW TABLES");
-}
-
-/** Get table status
-* @param string
-* @return array
-*/
-function table_status($name = "") {
- global $connection;
- $return = array();
- $result = $connection->query("SHOW TABLE STATUS" . ($name != "" ? " LIKE " . $connection->quote(addcslashes($name, "%_")) : ""));
- while ($row = $result->fetch_assoc()) {
- if ($row["Engine"] == "InnoDB") {
- // ignore internal comment, unnecessary since MySQL 5.1.21
- $row["Comment"] = preg_replace('~(?:(.+); )?InnoDB free: .*~', '\\1', $row["Comment"]);
- }
- if ($name != "") {
- return $row;
- }
- $return[$row["Name"]] = $row;
- }
- return $return;
-}
-
-/** Get status of referencable tables
-* @return array
-*/
-function table_status_referencable() {
- $return = array();
- foreach (table_status() as $name => $row) {
- if ($row["Engine"] == "InnoDB") {
- $return[$name] = $row;
- }
- }
- return $return;
-}
-
-/** Get information about fields
-* @param string
-* @return array array($name => array("field" => , "full_type" => , "type" => , "length" => , "unsigned" => , "default" => , "null" => , "auto_increment" => , "on_update" => , "collation" => , "privileges" => , "comment" => , "primary" => ))
-*/
-function fields($table) {
- global $connection;
- $return = array();
- $result = $connection->query("SHOW FULL COLUMNS FROM " . idf_escape($table));
- if ($result) {
- while ($row = $result->fetch_assoc()) {
- preg_match('~^([^( ]+)(?:\\((.+)\\))?( unsigned)?( zerofill)?$~', $row["Type"], $match);
- $return[$row["Field"]] = array(
- "field" => $row["Field"],
- "full_type" => $row["Type"],
- "type" => $match[1],
- "length" => $match[2],
- "unsigned" => ltrim($match[3] . $match[4]),
- "default" => ($row["Default"] != "" || ereg("char", $match[1]) ? $row["Default"] : null),
- "null" => ($row["Null"] == "YES"),
- "auto_increment" => ($row["Extra"] == "auto_increment"),
- "on_update" => (eregi('^on update (.+)', $row["Extra"], $match) ? $match[1] : ""), //! available since MySQL 5.1.23
- "collation" => $row["Collation"],
- "privileges" => array_flip(explode(",", $row["Privileges"])),
- "comment" => $row["Comment"],
- "primary" => ($row["Key"] == "PRI"),
- );
- }
- }
- return $return;
-}
-
-/** Get table indexes
-* @param string
-* @param string Min_DB to use
-* @return array array($key_name => array("type" => , "columns" => array(), "lengths" => array()))
-*/
-function indexes($table, $connection2 = null) {
- global $connection;
- if (!is_object($connection2)) { // use the main connection if the separate connection is unavailable
- $connection2 = $connection;
- }
- $return = array();
- $result = $connection2->query("SHOW INDEX FROM " . idf_escape($table));
- if ($result) {
- while ($row = $result->fetch_assoc()) {
- $return[$row["Key_name"]]["type"] = ($row["Key_name"] == "PRIMARY" ? "PRIMARY" : ($row["Index_type"] == "FULLTEXT" ? "FULLTEXT" : ($row["Non_unique"] ? "INDEX" : "UNIQUE")));
- $return[$row["Key_name"]]["columns"][$row["Seq_in_index"]] = $row["Column_name"];
- $return[$row["Key_name"]]["lengths"][$row["Seq_in_index"]] = $row["Sub_part"];
- }
- }
- return $return;
-}
-
-/** Get foreign keys in table
-* @param string
-* @return array array($name => array("db" => , "table" => , "source" => array(), "target" => array(), "on_delete" => , "on_update" => ))
-*/
-function foreign_keys($table) {
- global $connection, $on_actions;
- static $pattern = '(?:[^`]|``)+';
- $return = array();
- $result = $connection->query("SHOW CREATE TABLE " . idf_escape($table));
- if ($result) {
- $create_table = $connection->result($result, 1);
- preg_match_all("~CONSTRAINT `($pattern)` FOREIGN KEY \\(((?:`$pattern`,? ?)+)\\) REFERENCES `($pattern)`(?:\\.`($pattern)`)? \\(((?:`$pattern`,? ?)+)\\)(?: ON DELETE (" . implode("|", $on_actions) . "))?(?: ON UPDATE (" . implode("|", $on_actions) . "))?~", $create_table, $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- preg_match_all("~`($pattern)`~", $match[2], $source);
- preg_match_all("~`($pattern)`~", $match[5], $target);
- $return[$match[1]] = array(
- "db" => idf_unescape($match[4] != "" ? $match[3] : $match[4]),
- "table" => idf_unescape($match[4] != "" ? $match[4] : $match[3]),
- "source" => array_map('idf_unescape', $source[1]),
- "target" => array_map('idf_unescape', $target[1]),
- "on_delete" => $match[6],
- "on_update" => $match[7],
- );
- }
- }
- return $return;
-}
-
-/** Get view SELECT
-* @param string
-* @return array array("select" => )
-*/
-function view($name) {
- global $connection;
- return array("select" => preg_replace('~^(?:[^`]|`[^`]*`)* AS ~U', '', $connection->result($connection->query("SHOW CREATE VIEW " . idf_escape($name)), 1)));
-}
-
-/** Get sorted grouped list of collations
-* @return array
-*/
-function collations() {
- global $connection;
- $return = array();
- $result = $connection->query("SHOW COLLATION");
- while ($row = $result->fetch_assoc()) {
- $return[$row["Charset"]][] = $row["Collation"];
- }
- ksort($return);
- foreach ($return as $key => $val) {
- sort($return[$key]);
- }
- return $return;
-}
-
-/** Find out if database is information_schema
-* @param string
-* @return bool
-*/
-function information_schema($db) {
- global $connection;
- return ($connection->server_info >= 5 && $db == "information_schema");
-}
-
-/** Get escaped error message
-* @return string
-*/
-function error() {
- global $connection;
- return h(preg_replace('~^You have an error.*syntax to use~U', "Syntax error", $connection->error));
-}
-
-/** Return expression for binary comparison
-* @param string
-* @return string
-*/
-function exact_value($val) {
- global $connection;
- return "BINARY " . $connection->quote($val);
-}
-
-// value means maximum unsigned length
-$types = array();
-$structured_types = array();
-foreach (array(
- lang('Numbers') => array("tinyint" => 3, "smallint" => 5, "mediumint" => 8, "int" => 10, "bigint" => 20, "decimal" => 66, "float" => 12, "double" => 21),
- lang('Date and time') => array("date" => 10, "datetime" => 19, "timestamp" => 19, "time" => 10, "year" => 4),
- lang('Strings') => array("char" => 255, "varchar" => 65535, "tinytext" => 255, "text" => 65535, "mediumtext" => 16777215, "longtext" => 4294967295),
- lang('Binary') => array("binary" => 255, "varbinary" => 65535, "tinyblob" => 255, "blob" => 65535, "mediumblob" => 16777215, "longblob" => 4294967295),
- lang('Lists') => array("enum" => 65535, "set" => 64),
-) as $key => $val) {
- $types += $val;
- $structured_types[$key] = array_keys($val);
-}
-$unsigned = array("unsigned", "zerofill", "unsigned zerofill");
<?php
// PDO can be used in several database drivers
if (extension_loaded('pdo')) {
- class Min_PDO extends PDO {
+ /*abstract */class Min_PDO extends PDO {
var $_result, $server_info, $affected_rows, $error;
function __construct() {
}
- function dsn($dsn, $username, $password) {
- set_exception_handler('auth_error'); // try/catch is not compatible with PHP 4
+ function dsn($dsn, $username, $password, $exception_handler = 'auth_error') {
+ set_exception_handler($exception_handler); // try/catch is not compatible with PHP 4
parent::__construct($dsn, $username, $password);
restore_exception_handler();
- $this->setAttribute(13, array('Min_PDOStatement')); // PDO::ATTR_STATEMENT_CLASS
+ $this->setAttribute(13, array('Min_PDOStatement')); // 13 - PDO::ATTR_STATEMENT_CLASS
+ $this->server_info = $this->getAttribute(4); // 4 - PDO::ATTR_SERVER_VERSION
}
- function select_db($database) {
- // database selection is separated from the connection so dbname in DSN can't be used
- return $this->query("USE " . idf_escape($database));
- }
+ /*abstract function select_db($database);*/
function query($query, $unbuffered = false) {
$result = parent::query($query);
return $this->_result->nextRowset();
}
- function result($result, $field = 0) {
+ function result($query, $field = 0) {
+ $result = $this->query($query);
if (!$result) {
return false;
}
}
}
}
+
+$possible_drivers = array();
+$drivers = array();
<?php
-$VERSION = "2.3.2";
+$VERSION = "3.0.0-dev";
<?php
-/** Adminer - Compact MySQL management
+/** Adminer - Compact database management
* @link http://www.adminer.org/
* @author Jakub Vrana, http://php.vrana.cz/
* @copyright 2007 Jakub Vrana
<?php
$TABLE = $_GET["indexes"];
-$index_types = array("PRIMARY", "UNIQUE", "INDEX", "FULLTEXT");
+$index_types = array("PRIMARY", "UNIQUE", "INDEX");
+$table_status = table_status($TABLE);
+if (ereg("MyISAM|Maria", $table_status["Engine"])) {
+ $index_types[] = "FULLTEXT";
+}
$indexes = indexes($TABLE);
if ($_POST && !$error && !$_POST["add"]) {
$alter = array();
if ($column != "") {
$length = $index["lengths"][$key];
$set[] = idf_escape($column) . ($length ? "(" . intval($length) . ")" : "");
- $columns[count($columns) + 1] = $column;
- $lengths[count($lengths) + 1] = ($length ? $length : null);
+ $columns[] = $column;
+ $lengths[] = ($length ? $length : null);
}
}
if ($columns) {
foreach ($indexes as $name => $existing) {
ksort($existing["columns"]);
ksort($existing["lengths"]);
- if ($index["type"] == $existing["type"] && $existing["columns"] === $columns && $existing["lengths"] === $lengths) {
+ if ($index["type"] == $existing["type"] && array_values($existing["columns"]) === $columns && (!$existing["lengths"] || array_values($existing["lengths"]) === $lengths)) {
// skip existing index
unset($indexes[$name]);
continue 2;
}
}
- $alter[] = "\nADD $index[type]" . ($index["type"] == "PRIMARY" ? " KEY" : "") . " (" . implode(", ", $set) . ")";
+ $alter[] = array($index["type"], "(" . implode(", ", $set) . ")");
}
}
}
// drop removed indexes
foreach ($indexes as $name => $existing) {
- $alter[] = "\nDROP INDEX " . idf_escape($name);
+ $alter[] = array($existing["type"], idf_escape($name), "DROP");
}
if (!$alter) {
redirect(ME . "table=" . urlencode($TABLE));
}
- query_redirect("ALTER TABLE " . idf_escape($TABLE) . implode(",", $alter), ME . "table=" . urlencode($TABLE), lang('Indexes have been altered.'));
+ queries_redirect(ME . "table=" . urlencode($TABLE), lang('Indexes have been altered.'), alter_indexes($TABLE, $alter));
}
page_header(lang('Indexes'), $error, array("table" => $TABLE), $TABLE);
ksort($index["columns"]);
foreach ($index["columns"] as $i => $column) {
echo "<span>" . html_select("indexes[$j][columns][$i]", array(-1 => "") + $fields, $column, ($i == count($index["columns"]) ? "indexesAddColumn(this);" : 1));
- echo "<input name='indexes[$j][lengths][$i]' size='2' value='" . h($index["lengths"][$i]) . "'> </span>\n";
+ echo "<input name='indexes[$j][lengths][$i]' size='2' value='" . h($index["lengths"][$i]) . "'> </span>\n"; //! hide for non-MySQL drivers, add ASC|DESC
}
echo "\n";
$j++;
'File uploads are disabled.' => 'Nahrávání souborů není povoleno.',
'Routine has been called, %d row(s) affected.' => array('Procedura byla zavolána, byl změněn %d záznam.', 'Procedura byla zavolána, byly změněny %d záznamy.', 'Procedura byla zavolána, bylo změněno %d záznamů.'),
'Call' => 'Zavolat',
- 'No MySQL extension' => 'Žádná MySQL extenze',
+ 'No extension' => 'Žádná extenze',
'None of the supported PHP extensions (%s) are available.' => 'Není dostupná žádná z podporovaných PHP extenzí (%s).',
'Session support must be enabled.' => 'Session proměnné musí být povolené.',
'Session expired, please login again.' => 'Session vypršela, přihlašte se prosím znovu.',
'Create trigger' => 'Vytvořit trigger',
'Time' => 'Čas',
'Event' => 'Událost',
- 'MySQL version: %s through PHP extension %s' => 'Verze MySQL: %s přes PHP extenzi %s',
+ '%s version: %s through PHP extension %s' => 'Verze %s: %s přes PHP extenzi %s',
'%d row(s)' => array('%d řádek', '%d řádky', '%d řádků'),
- '~ %s' => '~ %s',
'Remove' => 'Odebrat',
'Are you sure?' => 'Opravdu?',
'Privileges' => 'Oprávnění',
'Select data' => 'Vypsat data',
'Stop on error' => 'Zastavit při chybě',
'Maximum number of allowed fields exceeded. Please increase %s and %s.' => 'Byl překročen maximální povolený počet polí. Zvyšte prosím %s a %s.',
- '(anywhere)' => '(kdekoliv)',
+ 'anywhere' => 'kdekoliv',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$6.$4.$1',
'[yyyy]-mm-dd' => 'd.m.[rrrr]',
'File does not exist.' => 'Soubor neexistuje.',
'Permanent login' => 'Trvalé přihlášení',
'%d in total' => '%d celkem',
+ 'Attachments' => 'Přílohy',
+ 'System' => 'Systém',
+ 'last' => 'poslední',
+ 'Network' => 'Síť',
+ 'Geometry' => 'Geometrie',
);
'File uploads are disabled.' => 'Importieren von Dateien abgeschaltet.',
'Routine has been called, %d row(s) affected.' => array('Kommando SQL ausgeführt, %d Datensatz betroffen.', 'Kommando SQL ausgeführt, %d Datensätze betroffen.'),
'Call' => 'Aufrufen',
- 'No MySQL extension' => 'Keine MySQL-Erweiterungen installiert',
+ 'No extension' => 'Keine Erweiterungen installiert',
'None of the supported PHP extensions (%s) are available.' => 'Keine der unterstützten PHP-Erweiterungen (%s) ist vorhanden.',
'Session support must be enabled.' => 'Sitzungen müssen aktiviert sein.',
'Session expired, please login again.' => 'Sitzungsdauer abgelaufen, bitte erneut anmelden.',
'Create trigger' => 'Trigger hinzufügen',
'Time' => 'Zeitpunkt',
'Event' => 'Ereignis',
- 'MySQL version: %s through PHP extension %s' => 'Version MySQL: %s, mit PHP-Erweiterung %s',
+ '%s version: %s through PHP extension %s' => 'Version %s: %s, mit PHP-Erweiterung %s',
'%d row(s)' => array('%d Datensatz', '%d Datensätze'),
- '~ %s' => '~ %s',
'Remove' => 'Entfernen',
'Are you sure?' => 'Sind Sie sicher ?',
'Privileges' => 'Rechte',
'Partition name' => 'Name der Partition',
'Values' => 'Werte',
'%d row(s) have been imported.' => array('%d Datensatz importiert.', '%d Datensätze wurden importiert.'),
- 'Show structure' => 'Tabellenstruktur',
- '(anywhere)' => '(beliebig)',
+ 'anywhere' => 'beliebig',
'CSV Import' => 'Importiere CSV',
'Import' => 'Importieren',
'Stop on error' => 'Bei Fehler anhaltan',
- 'Select data' => 'Tabelle auswählen',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$6.$4.$1',
'[yyyy]-mm-dd' => 't.m.[jjjj]',
'File uploads are disabled.' => 'Importación de archivos deshablilitado.',
'Routine has been called, %d row(s) affected.' => array('Consulta ejecutada, %d registro afectado.', 'Consulta ejecutada, %d registros afectados.'),
'Call' => 'Llamar',
- 'No MySQL extension' => 'No hay extension MySQL',
+ 'No extension' => 'No hay extension',
'None of the supported PHP extensions (%s) are available.' => 'Ninguna de las extensiones PHP soportadas (%s) está disponible.',
'Session support must be enabled.' => 'Deben estar habilitadas las sesiones.',
'Session expired, please login again.' => 'Sesión expirada, favor loguéese de nuevo.',
'Create trigger' => 'Agregar Trigger',
'Time' => 'Tiempo',
'Event' => 'Evento',
- 'MySQL version: %s through PHP extension %s' => 'Versión MySQL: %s a través de extensión PHP %s',
+ '%s version: %s through PHP extension %s' => 'Versión %s: %s a través de extensión PHP %s',
'%d row(s)' => array('%d registro', '%d registros'),
- '~ %s' => '~ %s',
'Remove' => 'Eliminar',
'Are you sure?' => 'Está seguro?',
'Privileges' => 'Privilegios',
'Partition name' => 'Nombre de Partición',
'Values' => 'Valores',
'%d row(s) have been imported.' => array('%d registro importado.', '%d registros importados.'),
- 'Show structure' => 'Información de la Tabla',
- '(anywhere)' => '(donde sea)',
+ 'anywhere' => 'donde sea',
'CSV Import' => 'Importar CSV',
'Import' => 'Importar',
'Stop on error' => 'Parar en caso de error',
- 'Select data' => 'Mostrar datos',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$5/$3/$1',
'[yyyy]-mm-dd' => 'dd/mm/[aaaa]',
'File uploads are disabled.' => 'Failide üleslaadimine on keelatud.',
'Routine has been called, %d row(s) affected.' => array('Protseduur täideti edukalt, mõjutatud ridu: %d.', 'Protseduur täideti edukalt, mõjutatud ridu: %d.'),
'Call' => 'Käivita',
- 'No MySQL extension' => 'Ei leitud MySQL laiendust',
+ 'No extension' => 'Ei leitud laiendust',
'None of the supported PHP extensions (%s) are available.' => 'Serveris pole ühtegi toetatud PHP laiendustest (%s).',
'Session support must be enabled.' => 'Sessioonid peavad olema lubatud.',
'Session expired, please login again.' => 'Sessioon on aegunud, palun logige uuesti sisse.',
'Time' => 'Aeg',
'Event' => 'Sündmus',
'%d row(s)' => array('%d rida', '%d rida'),
- '~ %s' => '~ %s',
'Remove' => 'Eemalda',
'Are you sure?' => 'Kas oled kindel?',
'Privileges' => 'Õigused',
'Routine' => 'Protseduur',
'Grant' => 'Anna',
'Revoke' => 'Eemalda',
- 'MySQL version: %s through PHP extension %s' => 'MySQL versioon: %s, kasutatud PHP moodul: %s',
+ '%s version: %s through PHP extension %s' => '%s versioon: %s, kasutatud PHP moodul: %s',
'Logged as: %s' => 'Sisse logitud: %s',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'POST-andmete maht on liialt suur. Palun vähendage andmeid või suurendage %s php-seadet.',
'Move up' => 'Liiguta ülespoole',
'Partition name' => 'Partitsiooni nimi',
'Values' => 'Väärtused',
'%d row(s) have been imported.' => array('Imporditi %d rida.', 'Imporditi %d rida.'),
- 'Show structure' => 'Tabeli struktuur',
- '(anywhere)' => '(vahet pole)',
+ 'anywhere' => 'vahet pole',
'CSV Import' => 'Impordi CSV',
'Import' => 'Impordi',
'Stop on error' => 'Peatuda vea esinemisel',
- 'Select data' => 'Vali tabel',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$6.$4.$1',
'[yyyy]-mm-dd' => 'd.m.[yyyy]',
'File uploads are disabled.' => 'Importation de fichier désactivé.',
'Routine has been called, %d row(s) affected.' => array('Routine exécutée, %d ligne modifiée.', 'Routine exécutée, %d lignes modifiées.'),
'Call' => 'Appeler',
- 'No MySQL extension' => 'Extension MySQL introuvable',
+ 'No extension' => 'Extension introuvable',
'None of the supported PHP extensions (%s) are available.' => 'Aucune des extensions PHP supportées (%s) n\'est disponible.',
'Session support must be enabled.' => 'Veuillez activer les sessions.',
'Session expired, please login again.' => 'Session expirée, veuillez vous authentifier à nouveau.',
'Time' => 'Temps',
'Event' => 'Évènement',
'%d row(s)' => array('%d ligne', '%d lignes'),
- '~ %s' => '~ %s',
'Remove' => 'Effacer',
'Are you sure?' => 'Êtes-vous certain?',
'Privileges' => 'Privilège',
'Routine' => 'Routine',
'Grant' => 'Grant',
'Revoke' => 'Revoke',
- 'MySQL version: %s through PHP extension %s' => 'Version de MySQL: %s utilisant l\'extension %s',
+ '%s version: %s through PHP extension %s' => 'Version de %s: %s utilisant l\'extension %s',
'Logged as: %s' => 'Authentifié en tant que %s',
'Too big POST data. Reduce the data or increase the %s configuration directive.' => 'Donnée POST trop grande . Réduire la taille des données ou modifier le %s dans la configuration de PHP.',
'Move up' => 'Déplacer vers le haut',
'Partition name' => 'Nom de la partition',
'Values' => 'Valeurs',
'%d row(s) have been imported.' => array('%d ligne a été importé.','%d lignes ont été importé.'),
- 'Show structure' => 'Structure de la table',
- '(anywhere)' => '(n\'importe où)',
+ 'anywhere' => 'n\'importe où',
'CSV Import' => 'Importation CVS',
'Import' => 'Importer',
'Stop on error' => 'Arrêt sur erreur',
- 'Select data' => 'Selectionner la table',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$5/$3/$1',
'[yyyy]-mm-dd' => 'jj/mm/[aaaa]',
'File uploads are disabled.' => 'Caricamento file disabilitato.',
'Routine has been called, %d row(s) affected.' => array('Routine chiamata, %d riga interessata.', 'Routine chiamata, %d righe interessate.'),
'Call' => 'Chiama',
- 'No MySQL extension' => 'Estensioni MySQL non presenti',
+ 'No extension' => 'Estensioni non presenti',
'None of the supported PHP extensions (%s) are available.' => 'Nessuna delle estensioni PHP supportate (%s) disponibile.',
'Session support must be enabled.' => 'Le sessioni devono essere abilitate.',
'Session expired, please login again.' => 'Sessione scaduta, autenticarsi di nuovo.',
'Create trigger' => 'Crea trigger',
'Time' => 'Orario',
'Event' => 'Evento',
- 'MySQL version: %s through PHP extension %s' => 'Versione MySQL: %s via estensione PHP %s',
+ '%s version: %s through PHP extension %s' => 'Versione %s: %s via estensione PHP %s',
'%d row(s)' => array('%d riga', '%d righe'),
- '~ %s' => '~ %s',
'Remove' => 'Rimuovi',
'Are you sure?' => 'Sicuro?',
'Privileges' => 'Privilegi',
'Partition name' => 'Nome partizione',
'Values' => 'Valori',
'%d row(s) have been imported.' => array('%d riga importata.','%d righe importate.'),
- 'Show structure' => 'Struttura tabella',
- '(anywhere)' => '(ovunque)',
+ 'anywhere' => 'ovunque',
'CSV Import' => 'Importa da CSV',
'Import' => 'Importa',
'Stop on error' => 'Stop su errore',
- 'Select data' => 'Scegli tabella',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$5/$3/$1',
'[yyyy]-mm-dd' => 'dd/mm/[yyyy]',
'File uploads are disabled.' => 'Bestanden uploaden is uitgeschakeld.',
'Routine has been called, %d row(s) affected.' => array('Procedure uitgevoerd, %d rij geraakt.', 'Procedure uitgevoerd, %d rijen geraakt.'),
'Call' => 'Uitvoeren',
- 'No MySQL extension' => 'Geen MySQL extensie',
+ 'No extension' => 'Geen extensie',
'None of the supported PHP extensions (%s) are available.' => 'Geen geldige PHP extensies beschikbaar (%s).',
'Session support must be enabled.' => 'Sessies moeten geactiveerd zijn.',
'Session expired, please login again.' => 'Uw sessie is verlopen. Gelieve opnieuw in te loggen.',
'Create trigger' => 'Trigger aanmaken',
'Time' => 'Time',
'Event' => 'Event',
- 'MySQL version: %s through PHP extension %s' => 'MySQL versie: %s met PHP extensie %s',
+ '%s version: %s through PHP extension %s' => '%s versie: %s met PHP extensie %s',
'%d row(s)' => array('%d rij', '%d rijen'),
- '~ %s' => '~ %s',
'Remove' => 'Verwijderen',
'Are you sure?' => 'Weet u het zeker?',
'Privileges' => 'Rechten',
'Partition name' => 'Partitie naam',
'Values' => 'Waarden',
'%d row(s) have been imported.' => array('%d rij werd geïmporteerd.', '%d rijen werden geïmporteerd.'),
- 'Show structure' => 'Tabelstructuur',
- '(anywhere)' => '(overal)',
+ 'anywhere' => 'overal',
'CSV Import' => 'CSV Import',
'Import' => 'Importeren',
'Stop on error' => 'Stoppen bij fout',
- 'Select data' => 'Selecteer tabel',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$5-$3-$1',
'[yyyy]-mm-dd' => 'dd-mm-[jjjj]',
'File uploads are disabled.' => 'Загрузка файлов на сервер запрещена.',
'Routine has been called, %d row(s) affected.' => array('Была вызвана процедура, %d запись была изменена.', 'Была вызвана процедура, %d записи было изменено.', 'Была вызвана процедура, %d записей было изменено.'),
'Call' => 'Вызвать',
- 'No MySQL extension' => 'Нет MySQL расширений',
+ 'No extension' => 'Нет расширений',
'None of the supported PHP extensions (%s) are available.' => 'Не доступно ни одного расширения из поддерживаемых (%s).',
'Session support must be enabled.' => 'Сессии должны быть включены.',
'Session expired, please login again.' => 'Срок действия сесси истек, нужно снова войти в систему.',
'Create trigger' => 'Создать триггер',
'Time' => 'Время',
'Event' => 'Событие',
- 'MySQL version: %s through PHP extension %s' => 'Версия MySQL: %s с PHP-расширением %s',
+ '%s version: %s through PHP extension %s' => 'Версия %s: %s с PHP-расширением %s',
'%d row(s)' => array('%d строка', '%d строки', '%d строк'),
- '~ %s' => '~ %s',
'Remove' => 'Удалить',
'Are you sure?' => 'Вы уверены?',
'Privileges' => 'Полномочия',
'%d row(s) have been imported.' => array('Импортирована %d строка.', 'Импортировано %d строки.', 'Импортировано %d строк.'),
'CSV Import' => 'Импорт CSV',
'Import' => 'Импорт',
- 'Show structure' => 'Структура таблицы',
- 'Select data' => 'Выбрать данные из таблицы',
'Stop on error' => 'Остановить при ошибке',
'Maximum number of allowed fields exceeded. Please increase %s and %s.' => 'Достигнуто максимальное значение количества доступных полей. Увеличьте %s и %s.',
- '(anywhere)' => '(в любом месте)',
+ 'anywhere' => 'в любом месте',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$5.$3.$1',
'[yyyy]-mm-dd' => 'дд.мм.[гггг]',
'File uploads are disabled.' => 'Nahrávánie súborov nie je povolené.',
'Routine has been called, %d row(s) affected.' => array('Procedúra bola zavolaná, bol zmenený %d záznam.', 'Procedúra bola zavolaná, boli zmenené %d záznamy.', 'Procedúra bola zavolaná, bolo zmenených %d záznamov.'),
'Call' => 'Zavolať',
- 'No MySQL extension' => 'Žiadne MySQL rozšírenie',
+ 'No extension' => 'Žiadne rozšírenie',
'None of the supported PHP extensions (%s) are available.' => 'Nie je dostupné žiadne z podporovaných rozšírení (%s).',
'Session support must be enabled.' => 'Session premenné musia byť povolené.',
'Session expired, please login again.' => 'Session vypršala, prihláste sa prosím znova.',
'Create trigger' => 'Vytvoriť trigger',
'Time' => 'Čas',
'Event' => 'Udalosť',
- 'MySQL version: %s through PHP extension %s' => 'Verzia MySQL: %s cez PHP rozšírenie %s',
+ '%s version: %s through PHP extension %s' => 'Verzia %s: %s cez PHP rozšírenie %s',
'%d row(s)' => array('%d riadok', '%d riadky', '%d riadkov'),
- '~ %s' => '~ %s',
'Remove' => 'Odobrať',
'Are you sure?' => 'Naozaj?',
'Privileges' => 'Oprávnenia',
'%d row(s) have been imported.' => array('Bol importovaný %d záznam.', 'Boli importované %d záznamy.', 'Bolo importovaných %d záznamov.'),
'CSV Import' => 'Import CSV',
'Import' => 'Import',
- 'Show structure' => 'Štruktúra tabuľky',
- 'Select data' => 'Vypísať tabuľku',
'Stop on error' => 'Zastaviť pri chybe',
'Maximum number of allowed fields exceeded. Please increase %s and %s.' => 'Bol prekročený maximálny počet povolených polí. Zvýšte prosím %s a %s.',
- '(anywhere)' => '(kdekoľvek)',
+ 'anywhere' => 'kdekoľvek',
'%.3f s' => '%.3f s',
'$1-$3-$5' => '$6.$4.$1',
'[yyyy]-mm-dd' => 'd.m.[rrrr]',
'File uploads are disabled.' => '檔案上傳被禁用。',
'Routine has been called, %d row(s) affected.' => '程序已被執行,%d行被影響',
'Call' => '呼叫',
- 'No MySQL extension' => '沒有 MySQL 擴充模組',
+ 'No extension' => '沒有 擴充模組',
'None of the supported PHP extensions (%s) are available.' => '沒有任何支援的PHP擴充模組(%s)。',
'Session support must be enabled.' => 'Session 必須被啟用。',
'Session expired, please login again.' => 'Session 已過期,請重新登入。',
'Create trigger' => '建立觸發器',
'Time' => '時間',
'Event' => '事件',
- 'MySQL version: %s through PHP extension %s' => 'MySQL版本:%s 透過PHP擴充模組 %s',
+ '%s version: %s through PHP extension %s' => '%s版本:%s 透過PHP擴充模組 %s',
'%d row(s)' => '%d行',
- '~ %s' => '~ %s',
'Remove' => '移除',
'Are you sure?' => '你確定嗎?',
'Privileges' => '權限',
'Partition name' => '分區名',
'Values' => '值',
'%d row(s) have been imported.' => '%d行已導入。',
- 'Show structure' => '資料表結構',
- '(anywhere)' => '(任意位置)',
+ 'anywhere' => '任意位置',
'CSV Import' => '匯入 CSV',
'Import' => '匯入',
'Stop on error' => '出錯時停止',
- 'Select data' => '選擇資料表',
'%.3f s' => '%.3f秒',
'$1-$3-$5' => '$1.$3.$5',
'[yyyy]-mm-dd' => '[yyyy].mm.dd',
'File uploads are disabled.' => '文件上传被禁用。',
'Routine has been called, %d row(s) affected.' => '子程序被调用,%d 行被影响',
'Call' => '调用',
- 'No MySQL extension' => '没有MySQL扩展',
+ 'No extension' => '没有扩展',
'None of the supported PHP extensions (%s) are available.' => '没有支持的 PHP 扩展可用(%s)。',
'Session support must be enabled.' => '会话必须被启用。',
'Session expired, please login again.' => '会话已过期,请重新登录。',
'Create trigger' => '创建触发器',
'Time' => '时间',
'Event' => '事件',
- 'MySQL version: %s through PHP extension %s' => 'MySQL 版本:%s 通过 PHP 扩展 %s',
+ '%s version: %s through PHP extension %s' => '%s 版本:%s 通过 PHP 扩展 %s',
'%d row(s)' => '%d 行',
- '~ %s' => '~ %s',
'Remove' => '移除',
'Are you sure?' => '你确定吗?',
'Privileges' => '权限',
'Partition name' => '分区名',
'Values' => '值',
'%d row(s) have been imported.' => '%d 行已导入。',
- 'Show structure' => '表结构',
- '(anywhere)' => '(任意位置)',
+ 'anywhere' => '任意位置',
'CSV Import' => 'CSV 导入',
'Import' => '导入',
'Stop on error' => '出错时停止',
- 'Select data' => '选择表',
'%.3f s' => '%.3f 秒',
'$1-$3-$5' => '$1.$3.$5',
'[yyyy]-mm-dd' => '[yyyy].mm.dd',
if (!$result) {
?>
<form action=""><p>
-<?php echo SID_FORM; ?>
-<?php if ($_GET["server"] != "") { ?><input type="hidden" name="server" value="<?php echo h($_GET["server"]); ?>"><?php } ?>
+<?php hidden_fields_get(); ?>
<?php echo lang('Username'); ?>: <input name="user">
<?php echo lang('Server'); ?>: <input name="host" value="localhost">
<input type="hidden" name="grant" value="">
preg_match_all('~([^:]+):([-0-9.]+)x([-0-9.]+)(_|$)~', $_COOKIE["adminer_schema"], $matches, PREG_SET_ORDER); //! ':' in table name
foreach ($matches as $i => $match) {
$table_pos[$match[1]] = array($match[2], $match[3]);
- $table_pos_js[] = "\n\t'" . addcslashes($match[1], "\r\n'\\") . "': [ $match[2], $match[3] ]";
+ $table_pos_js[] = "\n\t'" . addcslashes($match[1], "\r\n'\\/") . "': [ $match[2], $match[3] ]";
}
$top = 0;
$schema[$row["Name"]]["fields"][$name] = $field;
}
$schema[$row["Name"]]["pos"] = ($table_pos[$row["Name"]] ? $table_pos[$row["Name"]] : array($top, 0));
- if ($row["Engine"] == "InnoDB") {
+ if (fk_support($row)) {
foreach (foreign_keys($row["Name"]) as $val) {
if (!$val["db"]) {
$left = $base_left;
$from = ($select ? implode(", ", $select) : "*") . "\nFROM " . idf_escape($TABLE) . ($where ? "\nWHERE " . implode(" AND ", $where) : "");
$group_by = ($group && count($group) < count($select) ? "\nGROUP BY " . implode(", ", $group) : "") . ($order ? "\nORDER BY " . implode(", ", $order) : "");
+if ($_GET["page"] == "last") {
+ session_write_close();
+ $found_rows = $connection->result("SELECT COUNT(*) FROM " . idf_escape($TABLE) . ($where ? " WHERE " . implode(" AND ", $where) : ""));
+ redirect(remove_from_uri("page") . ($found_rows > $limit ? "&page=" . floor(($found_rows - 1) / $limit) : ""));
+}
+
if ($_POST && !$error) {
$where_check = "(" . implode(") OR (", array_map('where_check', (array) $_POST["check"])) . ")";
$primary = ($indexes["PRIMARY"] ? ($select ? array_flip($indexes["PRIMARY"]["columns"]) : array()) : null); // empty array means that all primary fields are selected
if ($select) {
$row = array();
foreach ($select as $val) {
- $row[] = (ereg('^`(.*)`$', $val, $match) ? idf_unescape($match[1]) : $val); //! columns looking like functions
+ $row[] = (ereg('^`.*`$', $val) ? idf_unescape($val) : $val); //! columns looking like functions
}
}
dump_csv($row);
$union = array();
foreach ($_POST["check"] as $val) {
// where is not unique so OR can't be used
- $union[] = "(SELECT $from " . ($where ? "AND " : "WHERE ") . where_check($val) . $group_by . " LIMIT 1)";
+ $union[] = "(SELECT" . limit("$from " . ($where ? "AND " : "WHERE ") . where_check($val) . $group_by, 1) . ")";
}
dump_data($TABLE, "INSERT", implode(" UNION ALL ", $union));
}
if (!$_POST["import"]) { // edit
$result = true;
$affected = 0;
- $command = ($_POST["delete"] ? "DELETE FROM " : ($_POST["clone"] ? "INSERT INTO " : "UPDATE ")) . idf_escape($TABLE);
+ $query = idf_escape($TABLE);
$set = array();
if (!$_POST["delete"]) {
foreach ($columns as $name => $val) { //! should check also for edit or insert privileges
$val = process_input($fields[$name]);
- if ($_POST["clone"]) {
- $set[idf_escape($name)] = ($val !== false ? $val : idf_escape($name));
- } elseif ($val !== false) {
- $set[] = idf_escape($name) . " = $val";
+ if ($val !== null) {
+ if ($_POST["clone"]) {
+ $set[idf_escape($name)] = ($val !== false ? $val : idf_escape($name));
+ } elseif ($val !== false) {
+ $set[] = idf_escape($name) . " = $val";
+ }
}
}
- $command .= ($_POST["clone"] ? " (" . implode(", ", array_keys($set)) . ")\nSELECT " . implode(", ", $set) . "\nFROM " . idf_escape($TABLE) : " SET\n" . implode(",\n", $set));
+ $query .= ($_POST["clone"] ? " (" . implode(", ", array_keys($set)) . ")\nSELECT " . implode(", ", $set) . "\nFROM " . idf_escape($TABLE) : " SET\n" . implode(",\n", $set));
}
if ($_POST["delete"] || $set) {
- if ($_POST["all"] || ($primary === array() && $_POST["check"])) {
- $result = queries($command . ($_POST["all"] ? ($where ? "\nWHERE " . implode(" AND ", $where) : "") : "\nWHERE $where_check"));
+ $command = "UPDATE";
+ if ($_POST["delete"]) {
+ $command = "DELETE";
+ $query = "FROM $query";
+ }
+ if ($_POST["clone"]) {
+ $command = "INSERT";
+ $query = "INTO $query";
+ }
+ if ($_POST["all"] || ($primary === array() && $_POST["check"]) || count($group) < count($select)) {
+ $result = queries($command . " $query" . ($_POST["all"] ? ($where ? "\nWHERE " . implode(" AND ", $where) : "") : "\nWHERE $where_check"));
$affected = $connection->affected_rows;
} else {
foreach ((array) $_POST["check"] as $val) {
// where is not unique so OR can't be used
- $result = queries($command . "\nWHERE " . where_check($val) . (count($group) < count($select) ? "" : "\nLIMIT 1"));
+ $result = queries($command . limit1($query . "\nWHERE " . where_check($val)));
if (!$result) {
break;
}
preg_match_all('~(?>"[^"]*"|[^"\\r\\n]+)+~', $file, $matches);
$affected = count($matches[0]);
queries("START TRANSACTION");
+ $separator = ($_POST["separator"] == ";" ? ";" : ",");
foreach ($matches[0] as $key => $val) {
- preg_match_all('~(("[^"]*")+|[^,]*),~', "$val,", $matches2);
+ preg_match_all("~((\"[^\"]*\")+|[^$separator]*)$separator~", $val . $separator, $matches2);
if (!$key && !array_diff($matches2[1], $cols)) { //! doesn't work with column names containing ",\n
// first row corresponds to column names - use it for table structure
$cols = $matches2[1];
}
}
if ($result) {
- queries("COMMIT");
+ queries("COMMIT");
}
queries_redirect(remove_from_uri("page"), lang('%d row(s) have been imported.', $affected), $result);
queries("ROLLBACK");
$adminer->selectLinks($table_status, $set);
if (!$columns) {
- echo "<p class='error'>" . lang('Unable to select the table') . ($fields ? "" : ": " . error()) . ".\n";
+ echo "<p class='error'>" . lang('Unable to select the table') . ($fields ? "." : ": " . error()) . "\n";
} else {
echo "<form action='' id='form'>\n";
echo "<div style='display: none;'>";
- echo ($_GET["server"] != "" ? '<input type="hidden" name="server" value="' . h($_GET["server"]) . '">' : "");
+ hidden_fields_get();
echo (DB != "" ? '<input type="hidden" name="db" value="' . h(DB) . '">' : ""); // not used in Editor
echo '<input type="hidden" name="select" value="' . h($TABLE) . '">';
echo "</div>\n";
$adminer->selectActionPrint($text_length);
echo "</form>\n";
- $query = "SELECT " . (intval($limit) && $group && count($group) < count($select) ? "SQL_CALC_FOUND_ROWS " : "") . $from . $group_by . ($limit != "" ? "\nLIMIT " . intval($limit) . ($_GET["page"] ? " OFFSET " . ($limit * $_GET["page"]) : "") : "");
+ $query = "SELECT" . limit((intval($limit) && $group && count($group) < count($select) && $driver == "sql" ? "SQL_CALC_FOUND_ROWS " : "") . $from . $group_by, ($limit != "" ? intval($limit) : null), ($_GET["page"] ? $limit * $_GET["page"] : 0));
echo $adminer->selectQuery($query);
$result = $connection->query($query);
} else {
$email_fields = array();
echo "<form action='' method='post' enctype='multipart/form-data'>\n";
- if (!$result->num_rows) {
+ $rows = array();
+ while ($row = $result->fetch_assoc()) {
+ $rows[] = $row;
+ }
+ // use count($rows) without LIMIT, COUNT(*) without grouping, FOUND_ROWS otherwise (slowest)
+ $found_rows = (intval($limit) && $group && count($group) < count($select)
+ ? ($driver == "sql" ? $connection->result(" SELECT FOUND_ROWS()") : $connection->result("SELECT COUNT(*) FROM ($query) x")) // space to allow mysql.trace_mode
+ : count($rows)
+ );
+
+ if (!$rows) {
echo "<p class='message'>" . lang('No rows.') . "\n";
} else {
- $rows = array();
- while ($row = $result->fetch_assoc()) {
- $rows[] = $row;
- }
- // use count($rows) without LIMIT, COUNT(*) without grouping, FOUND_ROWS otherwise (slowest)
- $found_rows = (intval($limit) && $group && count($group) < count($select)
- ? $connection->result($connection->query(" SELECT FOUND_ROWS()")) // space to allow mysql.trace_mode
- : count($rows)
- );
-
$backward_keys = $adminer->backwardKeys($TABLE, $table_name);
echo "<table cellspacing='0' class='nowrap' onclick='tableClick(event);'>\n";
}
echo ($backward_keys ? "<th>" . lang('Relations') : "") . "</thead>\n";
foreach ($adminer->rowDescriptions($rows, $foreign_keys) as $n => $row) {
- $unique_array = unique_array($row, $indexes);
+ $unique_array = unique_array($rows[$n], $indexes);
$unique_idf = "";
foreach ($unique_array as $key => $val) {
$unique_idf .= "&" . (isset($val) ? urlencode("where[" . bracket_escape($key) . "]") . "=" . urlencode($val) : "null%5B%5D=" . urlencode($key));
if (!isset($val)) {
$val = "<i>NULL</i>";
} else {
- if (ereg('blob|binary', $field["type"]) && $val != "") {
+ if (ereg('binary|blob|bytea', $field["type"]) && $val != "") {
$link = h(ME . 'download=' . urlencode($TABLE) . '&field=' . urlencode($key) . $unique_idf);
}
if ($val == "") {
echo "</tr>\n"; // close to allow white-space: pre
}
echo "</table>\n";
-
- if (intval($limit) && count($group) >= count($select)) {
- // slow with big tables
- ob_flush();
- flush();
- $found_rows = $connection->result($connection->query("SELECT COUNT(*) FROM " . idf_escape($TABLE) . ($where ? " WHERE " . implode(" AND ", $where) : "")));
+ }
+
+ parse_str($_COOKIE["adminer_export"], $adminer_export);
+
+ if ($rows || $_GET["page"]) {
+ $exact_count = true;
+ if (intval($limit) && count($group) >= count($select) && ($found_rows >= $limit || $_GET["page"])) {
+ $found_rows = $table_status["Rows"];
+ if (!isset($found_rows) || $where || $_GET["page"] * $limit * 2 > $found_rows || ($table_status["Engine"] == "InnoDB" && $found_rows < 1e5)) {
+ // slow with big tables
+ ob_flush();
+ flush();
+ $found_rows = $connection->result("SELECT COUNT(*) FROM " . idf_escape($TABLE) . ($where ? " WHERE " . implode(" AND ", $where) : ""));
+ } else {
+ $exact_count = false;
+ }
}
echo "<p class='pages'>";
if (intval($limit) && $found_rows > $limit) {
- // display first, previous 3, next 3 and last page
+ // display first, previous 5, next 5 and last page
$max_page = floor(($found_rows - 1) / $limit);
- echo lang('Page') . ":" . pagination(0) . ($_GET["page"] > 3 ? " ..." : "");
- for ($i = max(1, $_GET["page"] - 2); $i < min($max_page, $_GET["page"] + 3); $i++) {
+ echo lang('Page') . ":" . pagination(0) . ($_GET["page"] > 5 ? " ..." : "");
+ for ($i = max(1, $_GET["page"] - 2); $i < min($max_page, $_GET["page"] + 5); $i++) {
echo pagination($i);
}
- echo ($_GET["page"] + 3 < $max_page ? " ..." : "") . pagination($max_page);
+ echo ($_GET["page"] + 5 < $max_page ? " ..." : "") . ($exact_count ? pagination($max_page) : ' <a href="' . h(remove_from_uri() . "&page=last") . '">' . lang('last') . "</a>");
}
- echo " (" . lang('%d row(s)', $found_rows) . ") " . checkbox("all", 1, 0, lang('whole result')) . "\n";
+ echo " (" . ($exact_count ? "" : "~ ") . lang('%d row(s)', $found_rows) . ") " . checkbox("all", 1, 0, lang('whole result')) . "\n";
echo (information_schema(DB) ? "" : "<fieldset><legend>" . lang('Edit') . "</legend><div><input type='submit' name='edit' value='" . lang('Edit') . "'> <input type='submit' name='clone' value='" . lang('Clone') . "'> <input type='submit' name='delete' value='" . lang('Delete') . "' onclick=\"return confirm('" . lang('Are you sure?') . " (' + (this.form['all'].checked ? $found_rows : formChecked(this, /check/)) + ')');\"></div></fieldset>\n");
print_fieldset("export", lang('Export'));
- echo $adminer->dumpOutput(1) . " " . $adminer->dumpFormat(1); // 1 - select
+ echo $adminer->dumpOutput(1, $adminer_export["output"]) . " " . $adminer->dumpFormat(1, $adminer_export["format"]); // 1 - select
echo " <input type='submit' name='export' value='" . lang('Export') . "'>\n";
echo "</div></fieldset>\n";
}
print_fieldset("import", lang('CSV Import'), !$result->num_rows);
- echo "<input type='hidden' name='token' value='$token'><input type='file' name='csv_file'> <input type='submit' name='import' value='" . lang('Import') . "'>\n";
+ echo "<input type='hidden' name='token' value='$token'><input type='file' name='csv_file'> ";
+ echo html_select("separator", array(",", ";"), ($adminer_export["format"] == "csv;" ? ";" : ","), 1); // 1 - select
+ echo " <input type='submit' name='import' value='" . lang('Import') . "'>\n";
echo "</div></fieldset>\n";
$adminer->selectEmailPrint(array_filter($email_fields, 'strlen'), $columns);
<?php
restart_session();
-$history = &$_SESSION["history"][$_GET["server"]][DB];
+$history_all = &get_session("history");
+$history = &$history_all[DB];
if (!$error && $_POST["clear"]) {
$history = array();
redirect(remove_from_uri("history"));
$history[] = $query;
}
$space = "(\\s|/\\*.*\\*/|(#|-- )[^\n]*\n|--\n)";
- $alter_database = "(CREATE|DROP)$space+(DATABASE|SCHEMA)\\b~isU";
- if (!ini_get("session.use_cookies")) {
+ if (!ini_bool("session.use_cookies")) {
session_write_close();
}
$delimiter = ";";
$offset = 0;
$empty = true;
- $connection2 = (DB != "" ? connect() : null); // connection for exploring indexes and EXPLAIN (to not replace FOUND_ROWS()) //! PDO - silent error
- if (is_object($connection2)) {
+ $connection2 = connect(); // connection for exploring indexes and EXPLAIN (to not replace FOUND_ROWS()) //! PDO - silent error
+ if (is_object($connection2) && DB != "") {
$connection2->select_db(DB);
}
$queries = 0;
$empty = false;
$q = substr($query, 0, $match[0][1]);
$queries++;
- echo "<pre class='jush-sql' id='sql-$queries'>" . shorten_utf8(trim($q), 1000) . "</pre>\n";
+ echo "<pre class='jush-$driver' id='sql-$queries'>" . shorten_utf8(trim($q), 1000) . "</pre>\n";
ob_flush();
flush(); // can take a long time - show the running query
$start = explode(" ", microtime()); // microtime(true) is available since PHP 5
break;
}
} else {
+ if (is_object($connection2) && preg_match("~^$space*(USE)\\b~isU", $q)) {
+ $connection2->query($q);
+ }
do {
$result = $connection->store_result();
$end = explode(" ", microtime());
$id = "explain-$queries";
echo ", <a href='#$id' onclick=\"return !toggle('$id');\">EXPLAIN</a>\n";
echo "<div id='$id' class='hidden'>\n";
- select($connection2->query("EXPLAIN $q"));
+ select(explain($connection2, $q));
echo "</div>\n";
}
} else {
- if (preg_match("~^$space*$alter_database", $query)) {
+ if (preg_match("~^$space*(CREATE|DROP|ALTER)$space+(DATABASE|SCHEMA)\\b~isU", $q)) {
restart_session();
- $_SESSION["databases"][$_GET["server"]] = null; // clear cache
+ set_session("databases", null); // clear cache
session_write_close();
}
echo "<p class='message' title='" . h($connection->info) . "'>" . lang('Query executed OK, %d row(s) affected.', $connection->affected_rows) . "$time\n";
}
- unset($result); // free resultset
$start = $end;
} while ($connection->next_result());
}
if ($empty) {
echo "<p class='message'>" . lang('No commands to execute.') . "\n";
}
+ //! MS SQL - SET SHOWPLAN_ALL OFF
} else {
echo "<p class='error'>" . upload_error($query) . "\n";
}
<p>
<?php
-if (!ini_get("file_uploads")) {
+if (!ini_bool("file_uploads")) {
echo lang('File uploads are disabled.');
} else { ?>
<?php echo lang('File upload'); ?>: <input type="file" name="sql_file">
print_fieldset("history", lang('History'), $_GET["history"] != "");
foreach ($history as $key => $val) {
//! save and display timestamp
- echo '<a href="' . h(ME . "sql=&history=$key") . '">' . lang('Edit') . '</a> <code class="jush-sql">' . shorten_utf8(ltrim(str_replace("\n", " ", str_replace("\r", "", preg_replace('~^(#|-- ).*~m', '', $val)))), 80, "</code>") . "<br>\n";
+ echo '<a href="' . h(ME . "sql=&history=$key") . '">' . lang('Edit') . "</a> <code class='jush-$driver'>" . shorten_utf8(ltrim(str_replace("\n", " ", str_replace("\r", "", preg_replace('~^(#|-- ).*~m', '', $val)))), 80, "</code>") . "<br>\n";
}
echo "<input type='submit' name='clear' value='" . lang('Clear') . "'>\n";
echo "</div></fieldset>\n";
a:hover { color: red; }
h1 { font-size: 150%; margin: 0; padding: .8em 1em; border-bottom: 1px solid #999; font-weight: normal; color: #777; background: #eee; }
h2 { font-size: 150%; margin: 0 0 20px -18px; padding: .8em 1em; border-bottom: 1px solid #000; color: #000; font-weight: normal; background: #ddf; }
-h3 { font-weight: normal; font-size: 130%; margin: .8em 0; }
+h3 { font-weight: normal; font-size: 130%; margin: 1em 0 0; }
form { margin: 0; }
-table { margin: 1em 20px .8em 0; border: 0; border-top: 1px solid #999; border-left: 1px solid #999; font-size: 90%; }
-td, th { margin-bottom: 1em; border: 0; border-right: 1px solid #999; border-bottom: 1px solid #999; padding: .2em .3em; }
+table { margin: 1em 20px 0 0; border: 0; border-top: 1px solid #999; border-left: 1px solid #999; font-size: 90%; }
+td, th { border: 0; border-right: 1px solid #999; border-bottom: 1px solid #999; padding: .2em .3em; }
th { background: #eee; text-align: left; }
thead th { text-align: center; }
thead td, thead th { background: #ddf; }
-fieldset { display: inline; vertical-align: top; padding: .5em .8em; margin: 0 .5em .5em 0; border: 1px solid #999; }
-p { margin: 0 20px 1em 0; }
+fieldset { display: inline; vertical-align: top; padding: .5em .8em; margin: .8em .5em 0 0; border: 1px solid #999; }
+p { margin: .8em 20px 0 0; }
img { vertical-align: middle; border: 0; }
td img { max-width: 200px; max-height: 200px; }
code { background: #eee; }
tr:hover td, tr:hover th { background: #ddf; }
+pre { margin: 1em 0 0; }
.version { color: #777; font-size: 67%; }
.js .hidden { display: none; }
.nowrap td, .nowrap th, td.nowrap { white-space: pre; }
.wrap td { white-space: normal; }
.error { color: red; background: #fee; }
+.error b { background: #fff; font-weight: normal; }
.message { color: green; background: #efe; }
-.error, .message { padding: .5em .8em; margin: 0 20px 1em 0; }
+.error, .message { padding: .5em .8em; margin: 1em 20px 0 0; }
.char { color: #007F00; }
.date { color: #7F007F; }
.enum { color: #007F7F; }
// Adminer specific functions
/** Load syntax highlighting
-* @param string first three characters of MySQL version
+* @param string first three characters of database system version
*/
function bodyLoad(version) {
var jushRoot = '../externals/jush/';
script.onload = function () {
if (window.jush) { // IE runs in case of an error too
jush.create_links = ' target="_blank"';
+ jush.urls.pgsql[0] = 'http://www.postgresql.org/docs/' + version + '/static/$key';
jush.urls.sql[0] = 'http://dev.mysql.com/doc/refman/' + version + '/en/$key';
jush.urls.sqlset[0] = jush.urls.sql[0];
jush.urls.sqlstatus[0] = jush.urls.sql[0];
document.body.appendChild(script);
}
-
-
/** Get value of select
* @param HTMLSelectElement
* @return string
function verifyVersion() {
cookie('adminer_version=0', 1);
var script = document.createElement('script');
- script.src = 'https://adminer.svn.sourceforge.net/svnroot/adminer/trunk/version.js';
+ script.src = 'https://www.adminer.org/version.php';
document.body.appendChild(script);
}
el.onclick && el.onclick();
}
+/** Set HTML code of an element
+* @param string
+* @param string undefined to set parentNode to
+*/
+function setHtml(id, html) {
+ var el = document.getElementById(id);
+ if (el) {
+ if (html == undefined) {
+ el.parentNode.innerHTML = ' ';
+ } else {
+ el.innerHTML = html;
+ }
+ }
+}
+
/** Add row in select fieldset
}
$table_status = ($fields ? table_status($TABLE) : array());
-page_header(($fields && !isset($table_status["Rows"]) ? lang('View') : lang('Table')) . ": " . h($TABLE), $error);
+page_header(($fields && $table_status["Engine"] == "VIEW" ? lang('View') : lang('Table')) . ": " . h($TABLE), $error);
$adminer->selectLinks($table_status);
if ($fields) {
echo "<table cellspacing='0'>\n";
- echo "<thead><tr><th>" . lang('Column') . "<td>" . lang('Type') . "<td>" . lang('Comment') . "</thead>\n";
+ echo "<thead><tr><th>" . lang('Column') . "<td>" . lang('Type') . (support("comment") ? "<td>" . lang('Comment') : "") . "</thead>\n";
foreach ($fields as $field) {
echo "<tr" . odd() . "><th>" . h($field["field"]);
echo "<td>" . h($field["full_type"]) . ($field["null"] ? " <i>NULL</i>" : "") . ($field["auto_increment"] ? " <i>" . lang('Auto Increment') . "</i>" : "");
- echo "<td>" . nbsp($field["comment"]);
+ echo (support("comment") ? "<td>" . nbsp($field["comment"]) : "");
echo "\n";
}
echo "</table>\n";
- if (isset($table_status["Rows"])) {
+ if ($table_status["Engine"] != "VIEW") {
echo "<h3>" . lang('Indexes') . "</h3>\n";
$indexes = indexes($TABLE);
if ($indexes) {
}
echo '<p><a href="' . h(ME) . 'indexes=' . urlencode($TABLE) . '">' . lang('Alter indexes') . "</a>\n";
- if ($table_status["Engine"] == "InnoDB") {
+ if (fk_support($table_status)) {
echo "<h3>" . lang('Foreign keys') . "</h3>\n";
$foreign_keys = foreign_keys($TABLE);
if ($foreign_keys) {
}
echo "</table>\n";
}
- echo '<p><a href="' . h(ME) . 'foreign=' . urlencode($TABLE) . '">' . lang('Add foreign key') . "</a>\n";
+ if ($driver != "sqlite") {
+ echo '<p><a href="' . h(ME) . 'foreign=' . urlencode($TABLE) . '">' . lang('Add foreign key') . "</a>\n";
+ }
}
- if ($connection->server_info >= 5) {
+ if (support("trigger")) {
echo "<h3>" . lang('Triggers') . "</h3>\n";
- $result = $connection->query("SHOW TRIGGERS LIKE " . $connection->quote(addcslashes($TABLE, "%_")));
- if ($result->num_rows) {
+ $triggers = triggers($TABLE);
+ if ($triggers) {
echo "<table cellspacing='0'>\n";
- while ($row = $result->fetch_assoc()) {
- echo "<tr valign='top'><td>$row[Timing]<td>$row[Event]<th>" . h($row["Trigger"]) . "<td><a href='" . h(ME . 'trigger=' . urlencode($TABLE) . '&name=' . urlencode($row["Trigger"])) . "'>" . lang('Alter') . "</a>\n";
+ foreach ($triggers as $key => $val) {
+ echo "<tr valign='top'><td>$val[0]<td>$val[1]<th>" . h($key) . "<td><a href='" . h(ME . 'trigger=' . urlencode($TABLE) . '&name=' . urlencode($key)) . "'>" . lang('Alter') . "</a>\n";
}
echo "</table>\n";
}
$dropped = false;
if ($_POST && !$error && in_array($_POST["Timing"], $trigger_time) && in_array($_POST["Event"], $trigger_event)) {
$dropped = drop_create(
- "DROP TRIGGER " . idf_escape($_GET["name"]),
- "CREATE TRIGGER " . idf_escape($_POST["Trigger"]) . " $_POST[Timing] $_POST[Event] ON " . idf_escape($TABLE) . " FOR EACH ROW\n$_POST[Statement]",
+ "DROP TRIGGER " . idf_escape($_GET["name"]) . ($driver == "pgsql" ? " ON " . idf_escape($TABLE) : ""),
+ "CREATE TRIGGER " . idf_escape($_POST["Trigger"]) . " $_POST[Timing] $_POST[Event] ON " . idf_escape($TABLE) . " FOR EACH ROW\n$_POST[Statement]", //! FOR EACH STATEMENT
ME . "table=" . urlencode($TABLE),
lang('Trigger has been dropped.'),
lang('Trigger has been altered.'),
if ($_POST) {
$row = $_POST;
} elseif ($_GET["name"] != "") {
- $result = $connection->query("SHOW TRIGGERS WHERE `Trigger` = " . $connection->quote($_GET["name"]));
- $row = $result->fetch_assoc();
+ $row = trigger($_GET["name"]);
}
?>
$row = $_POST;
$grants = $new_grants;
} else {
- $row = $_GET + array("host" => $connection->result($connection->query("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', -1)"))); // create user on the same domain by default
+ $row = $_GET + array("host" => $connection->result("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', -1)")); // create user on the same domain by default
$row["pass"] = $old_pass;
$row["hashed"] = true;
$grants[""] = true;
$dropped = drop_create(
"DROP VIEW " . idf_escape($TABLE),
"CREATE VIEW " . idf_escape($_POST["name"]) . " AS\n$_POST[select]",
- substr(ME, 0, -1),
+ ($_POST["drop"] ? substr(ME, 0, -1) : ME . "table=" . urlencode($_POST["name"])),
lang('View has been dropped.'),
lang('View has been altered.'),
lang('View has been created.'),
+Adminer 3.0.0-dev:
+Drivers for MS SQL, SQLite, PostgreSQL
+Show number of tables in server overview
+Allow concurrent logins on the same server
+Operator LIKE %%
+Remember export parameters in cookie
+Allow semicolon as CSV separator
+Defer table information in database overview to JavaScript (performance)
+Big tables optimizations (performance)
+
Adminer 2.3.2 (released 2010-04-21):
Fix COUNT(*) link
Fix Save and continue edit
} elseif ($token[0] === T_VARIABLE && !isset($special_variables[$token[1]])) {
$token[1] = '$' . $short_variables[$token[1]];
}
- if (isset($set[substr($output, -1)]) || isset($set[$token[1]{0}])) {
+ if (isset($set[substr($output, -1)]) || isset($set[$token[1][0]])) {
$space = '';
}
$output .= $space . $token[1];
return call_user_func($match[2], file_get_contents(dirname(__FILE__) . "/$project/$match[1]"));
}
+$DRIVER = "";
+if (file_exists(dirname(__FILE__) . "/adminer/drivers/" . $_SERVER["argv"][1] . ".inc.php")) {
+ $DRIVER = $_SERVER["argv"][1];
+ array_shift($_SERVER["argv"]);
+}
+
unset($_COOKIE["adminer_lang"]);
$_SESSION["lang"] = $_SERVER["argv"][1]; // Adminer functions read language from session
+include dirname(__FILE__) . "/adminer/include/lang.inc.php";
if (isset($_SESSION["lang"])) {
- include dirname(__FILE__) . "/adminer/include/lang.inc.php";
if (isset($_SERVER["argv"][2]) || !isset($langs[$_SESSION["lang"]])) {
echo "Usage: php compile.php [lang]\nPurpose: Compile adminer[-lang].php and editor[-lang].php.\n";
exit(1);
include dirname(__FILE__) . "/adminer/lang/$_SESSION[lang].inc.php";
}
+// check function definition in drivers
+$filename = dirname(__FILE__) . "/adminer/drivers/mysql.inc.php";
+preg_match_all('~\\bfunction ([^(]+)~', file_get_contents($filename), $matches); //! respect context (extension, class)
+$functions = array_combine($matches[1], $matches[0]);
+unset($functions["__destruct"], $functions["Min_DB"], $functions["Min_Result"]);
+foreach (glob(dirname(__FILE__) . "/adminer/drivers/" . ($DRIVER ? $DRIVER : "*") . ".inc.php") as $filename) {
+ if ($filename != "mysql.inc.php") {
+ $file = file_get_contents($filename);
+ foreach ($functions as $val) {
+ if (!strpos($file, "$val(")) {
+ echo "Missing $val in $filename\n";
+ }
+ }
+ }
+}
+
foreach (array("adminer", "editor") as $project) {
$lang_ids = array(); // global variable simplifies usage in a callback function
$file = file_get_contents(dirname(__FILE__) . "/$project/index.php");
+ if ($DRIVER && $DRIVER != "mysql") {
+ $_GET[$DRIVER] = true; // to load the driver
+ include_once dirname(__FILE__) . "/adminer/drivers/$DRIVER.inc.php";
+ foreach (array("view", "event", "privileges", "user", "processlist", "variables", "trigger") as $feature) {
+ if (!support($feature)) {
+ $file = str_replace("} elseif (isset(\$_GET[\"$feature\"])) {\n\tinclude \"./$feature.inc.php\";\n", "", $file);
+ }
+ }
+ if (!support("routine")) {
+ $file = str_replace("} elseif (isset(\$_GET[\"procedure\"])) {\n\tinclude \"./procedure.inc.php\";\n", "", $file);
+ $file = str_replace("} elseif (isset(\$_GET[\"call\"])) {\n\tinclude \"./call.inc.php\";\n", "", $file);
+ $file = str_replace("if (isset(\$_GET[\"callf\"])) {\n\t\$_GET[\"call\"] = \$_GET[\"callf\"];\n}\nif (isset(\$_GET[\"function\"])) {\n\t\$_GET[\"procedure\"] = \$_GET[\"function\"];\n}\n", "", $file);
+ }
+ }
$file = preg_replace_callback('~\\b(include|require) "([^"]*)";~', 'put_file', $file);
$file = str_replace('include "../adminer/include/coverage.inc.php";', '', $file);
+ if ($DRIVER) {
+ $file = preg_replace('(include "../adminer/drivers/(?!' . preg_quote($DRIVER) . ').*\\s*)', '', $file);
+ }
$file = preg_replace_callback('~\\b(include|require) "([^"]*)";~', 'put_file', $file); // bootstrap.inc.php
$file = preg_replace_callback("~lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])~s", 'lang_ids', $file);
$file = preg_replace_callback('~\\b(include|require) "([^"]*\\$LANG.inc.php)";~', 'put_file_lang', $file);
$replace = 'h(preg_replace("~\\\\\\\\?.*~", "", $_SERVER["REQUEST_URI"])) . "?file=\\1&version=' . $VERSION;
$file = preg_replace('~\\.\\./adminer/static/(default\\.css|functions\\.js|favicon\\.ico)~', '<?php echo ' . $replace . '"; ?>', $file);
$file = preg_replace('~\\.\\./adminer/static/([^\'"]*)~', '" . ' . $replace, $file);
- $file = str_replace("../externals/jush/", "https://jush.svn.sourceforge.net/svnroot/jush/trunk/", $file); // mixed-content warning if Adminer runs on HTTPS and external files on HTTP
+ $file = str_replace("../externals/jush/", "https://www.adminer.org/static/", $file);
$file = preg_replace("~<\\?php\\s*\\?>\n?|\\?>\n?<\\?php~", '', $file);
$file = php_shrink($file);
- $filename = $project . ($_SESSION["lang"] ? "-$_SESSION[lang]" : "") . ".php"; // "$project-$VERSION"
+ $filename = $project . ($DRIVER ? "-$DRIVER" : "") . ($_SESSION["lang"] ? "-$_SESSION[lang]" : "") . ".php"; // . "-$VERSION"
fwrite(fopen($filename, "w"), $file); // file_put_contents() since PHP 5
- echo "$filename created.\n";
+ echo "$filename created (" . strlen($file) . " B).\n";
}
$return = array();
preg_match_all('~<([^>]+)~', $s, $matches);
foreach ($matches[1] as $val) {
- if ($val{0} == "/") {
+ if ($val[0] == "/") {
array_pop($return);
} elseif (substr($val, -1) != "/") {
$return[] = $val;
<?php
-page_header(lang('Server'), "", null);
+page_header(lang('Server'), "", false);
?>
<form action=""><p>
-<?php echo SID_FORM; ?>
+<?php hidden_fields_get(); ?>
<input name="where[0][val]" value="<?php echo h($_GET["where"][0]["val"]); ?>">
<input type="submit" value="<?php echo lang('Search'); ?>" />
</form>
<?php
class Adminer {
var $operators = array("<=", ">=");
- var $values = array(); // protected
+ var $_values = array();
function name() {
return lang('Editor');
}
+ //! driver
+
function credentials() {
return array(); // default INI settings
}
global $connection;
$dbs = get_databases(false);
return (!$dbs
- ? $connection->result($connection->query("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', 1)")) // username without the database list
+ ? $connection->result("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', 1)") // username without the database list
: $dbs[(information_schema($dbs[0]) ? 1 : 0)] // first available database
);
}
- function loginForm($username) {
+ function loginForm() {
?>
<table cellspacing="0">
-<tr><th><?php echo lang('Username'); ?><td><input type="hidden" name="server" value=""><input name="username" value="<?php echo h($username); ?>">
+<tr><th><?php echo lang('Username'); ?><td><input type="hidden" name="driver" value="server"><input type="hidden" name="server" value=""><input name="username" value="<?php echo h($_GET["username"]); ?>">
<tr><th><?php echo lang('Password'); ?><td><input type="password" name="password">
</table>
<?php
function backwardKeys($table, $tableName) {
global $connection;
$return = array();
- if ($connection->server_info >= 5) { //! requires MySQL 5
- $result = $connection->query("SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_COLUMN_NAME
+ $result = $connection->query("SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_COLUMN_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = " . $connection->quote($this->database()) . "
AND REFERENCED_TABLE_SCHEMA = " . $connection->quote($this->database()) . "
AND REFERENCED_TABLE_NAME = " . $connection->quote($table) . "
ORDER BY ORDINAL_POSITION");
+ if ($result) { //! requires MySQL 5
while ($row = $result->fetch_assoc()) {
$return[$row["TABLE_NAME"]]["keys"][$row["CONSTRAINT_NAME"]][$row["COLUMN_NAME"]] = $row["REFERENCED_COLUMN_NAME"];
}
foreach ($cols as $column => $val) {
$link .= where_link($i++, $column, $row[$val]);
}
- echo "<a href='" . h($link) . "'>$backwardKey[name]</a>";
+ echo "<a href='" . h($link) . "'>" . h($backwardKey["name"]) . "</a>";
$link = ME . 'edit=' . urlencode($table);
foreach ($cols as $column => $val) {
$link .= "&set" . urlencode("[" . bracket_escape($column) . "]") . "=" . urlencode($row[$val]);
}
function rowDescriptions($rows, $foreignKeys) {
- global $connection;
$return = $rows;
foreach ($rows[0] as $key => $val) {
foreach ((array) $foreignKeys[$key] as $foreignKey) {
$ids[$row[$key]] = exact_value($row[$key]);
}
// uses constant number of queries to get the descriptions, join would be complex, multiple queries would be slow
- $descriptions = $this->values[$foreignKey["table"]];
+ $descriptions = $this->_values[$foreignKey["table"]];
if (!$descriptions) {
$descriptions = get_key_vals("SELECT $id, $name FROM " . idf_escape($foreignKey["table"]) . " WHERE $id IN (" . implode(", ", $ids) . ")");
}
function selectVal($val, $link, $field) {
$return = ($val == "<i>NULL</i>" ? " " : $val);
- if (ereg('blob|binary', $field["type"]) && !is_utf8($val)) {
+ if (ereg('binary|blob|bytea', $field["type"]) && !is_utf8($val)) {
$return = lang('%d byte(s)', strlen($val));
if (ereg("^(GIF|\xFF\xD8\xFF|\x89\x50\x4E\x47\x0D\x0A\x1A\x0A)", $val)) { // GIF|JPG|PNG, getimagetype() works with filename
$return = "<img src='$link' alt='$return'>";
}
function selectColumnsPrint($select, $columns) {
- //! allow grouping functions by indexes
+ // can allow grouping functions by indexes
}
function selectSearchPrint($where, $columns, $indexes) {
- //! foreign keys
+ $where = (array) $_GET["where"];
echo '<fieldset><legend>' . lang('Search') . "</legend><div>\n";
$keys = array();
- foreach ((array) $_GET["where"] as $key => $val) {
+ foreach ($where as $key => $val) {
$keys[$val["col"]] = $key;
}
- $i = -1;
+ $i = 0;
+ foreach (fields($_GET["select"]) as $name => $field) {
+ if (ereg("enum", $field["type"])) { //! set - uses 1 << $i and FIND_IN_SET()
+ $desc = $columns[$name];
+ $key = $keys[$name];
+ $i--;
+ echo "<div>" . h($desc) . "<input type='hidden' name='where[$i][col]' value='" . h($name) . "'>:";
+ enum_input("checkbox", "where[$i][val][]", $field, (array) $where[$key]["val"]); //! impossible to search for NULL
+ echo "</div>\n";
+ unset($columns[$name]);
+ }
+ }
foreach ($columns as $name => $desc) {
- $key = $keys[$name];
- $options = $this->foreignKeyOptions($_GET["select"], $name);
+ $options = $this->_foreignKeyOptions($_GET["select"], $name);
if ($options) {
- echo "<div>" . h($desc) . "<input type='hidden' name='where[$i][col]' value='" . h($name) . "'><input type='hidden' name='where[$i][op]' value='='>: <select name='where[$i][val]'>" . optionlist($options, $_GET["where"][$key]["val"], true) . "</select></div>\n";
+ $key = $keys[$name];
$i--;
+ echo "<div>" . h($desc) . "<input type='hidden' name='where[$i][col]' value='" . h($name) . "'><input type='hidden' name='where[$i][op]' value='='>: <select name='where[$i][val]'>" . optionlist($options, $where[$key]["val"], true) . "</select></div>\n";
unset($columns[$name]);
- if (isset($key)) {
- unset($_GET["where"][$key]);
- }
}
}
$i = 0;
- foreach ((array) $_GET["where"] as $val) {
- if ("$val[col]$val[val]" != "") {
- echo "<div><select name='where[$i][col]'><option value=''>" . lang('(anywhere)') . optionlist($columns, $val["col"], true) . "</select>";
+ foreach ($where as $val) {
+ if ($columns[$val["col"]] && "$val[col]$val[val]" != "") {
+ echo "<div><select name='where[$i][col]'><option value=''>(" . lang('anywhere') . ")" . optionlist($columns, $val["col"], true) . "</select>";
echo html_select("where[$i][op]", array(-1 => "") + $this->operators, $val["op"]);
echo "<input name='where[$i][val]' value='" . h($val["val"]) . "'></div>\n";
$i++;
}
}
- echo "<div><select name='where[$i][col]' onchange='selectAddRow(this);'><option value=''>" . lang('(anywhere)') . optionlist($columns, null, true) . "</select>";
+ echo "<div><select name='where[$i][col]' onchange='selectAddRow(this);'><option value=''>(" . lang('anywhere') . ")" . optionlist($columns, null, true) . "</select>";
echo html_select("where[$i][op]", array(-1 => "") + $this->operators);
echo "<input name='where[$i][val]'></div>\n";
echo "</div></fieldset>\n";
echo lang('Subject') . ": <input name='email_subject' value='" . h($_POST["email_subject"]) . "'>\n";
echo "<p><textarea name='email_message' rows='15' cols='75'>" . h($_POST["email_message"] . ($_POST["email_append"] ? '{$' . "$_POST[email_addition]}" : "")) . "</textarea><br>\n";
echo html_select("email_addition", $columns, $_POST["email_addition"]) . "<input type='submit' name='email_append' value='" . lang('Insert') . "'>\n"; //! JavaScript
- echo "<p><input type='file' name='email_files[]' onchange=\"var el = this.cloneNode(true); el.value = ''; this.parentNode.appendChild(el); this.onchange = function () { };\">";
+ echo "<p>" . lang('Attachments') . ": <input type='file' name='email_files[]' onchange=\"var el = this.cloneNode(true); el.value = ''; this.parentNode.appendChild(el); this.onchange = function () { };\">";
echo "<p>" . (count($emailFields) == 1 ? '<input type="hidden" name="email_field" value="' . h(key($emailFields)) . '">' : html_select("email_field", $emailFields));
echo "<input type='submit' name='email' value='" . lang('Send') . "' onclick=\"return this.form['delete'].onclick();\">\n";
echo "</div></fieldset>\n";
function selectSearchProcess($fields, $indexes) {
$return = array();
- foreach ((array) $_GET["where"] as $key => $val) {
- $col = $val["col"];
- if (($key < 0 ? "" : $col) . $val["val"] != "") {
+ foreach ((array) $_GET["where"] as $key => $where) {
+ $col = $where["col"];
+ $op = $where["op"];
+ $val = $where["val"];
+ if (($key < 0 ? "" : $col) . $val != "") {
$conds = array();
foreach (($col != "" ? array($col => $fields[$col]) : $fields) as $name => $field) {
- if ($col != "" || is_numeric($val["val"]) || !ereg('int|float|double|decimal', $field["type"])) {
- $text_type = ereg('char|text|enum|set', $field["type"]);
- $value = $this->processInput($field, ($text_type && ereg('^[^%]+$', $val["val"]) ? "%$val[val]%" : $val["val"]));
- $conds[] = idf_escape($name) . ($value == "NULL" ? " IS" . ($val["op"] == ">=" ? " NOT" : "") : (in_array($val["op"], $this->operators) ? " $val[op]" : ($val["op"] != "=" && $text_type ? " LIKE" : " ="))) . " $value"; //! can issue "Illegal mix of collations" for columns in other character sets - solve by CONVERT($name using utf8)
+ if ($col != "" || is_numeric($val) || !ereg('int|float|double|decimal', $field["type"])) {
+ if ($col != "" && $field["type"] == "enum") {
+ $conds[] = idf_escape($name) . " IN (" . implode(", ", array_map('intval', $val)) . ")";
+ } else {
+ $text_type = ereg('char|text|enum|set', $field["type"]);
+ $value = $this->processInput($field, ($text_type && ereg('^[^%]+$', $val) ? "%$val%" : $val));
+ $conds[] = idf_escape($name) . ($value == "NULL" ? " IS" . ($op == ">=" ? " NOT" : "") : (in_array($op, $this->operators) ? " $op" : ($op != "=" && $text_type ? " LIKE" : " ="))) . " $value"; //! can issue "Illegal mix of collations" for columns in other character sets - solve by CONVERT($name using utf8)
+ }
}
}
$return[] = ($conds ? "(" . implode(" OR ", $conds) . ")" : "0");
if ($_POST["all"] || $_POST["check"]) {
$field = idf_escape($_POST["email_field"]);
$subject = $_POST["email_subject"];
- $eol = (strncasecmp(PHP_OS, "win", 3) ? "\n" : "\r\n");
- $message = str_replace("\n", $eol, wordwrap(str_replace("\r", "", "$_POST[email_message]\n")));
+ $message = $_POST["email_message"];
preg_match_all('~\\{\\$([a-z0-9_]+)\\}~i', "$subject.$message", $matches); // allows {$name} in subject or message
$result = $connection->query("SELECT DISTINCT $field" . ($matches[1] ? ", " . implode(", ", array_map('idf_escape', array_unique($matches[1]))) : "") . " FROM " . idf_escape($_GET["select"])
. " WHERE $field IS NOT NULL AND $field != ''"
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
- $boundary = uniqid("boundary");
- $attachments = "";
- $email_files = $_FILES["email_files"];
- foreach ($email_files["error"] as $key => $val) {
- if (!$val) {
- $attachments .= "--$boundary$eol"
- . "Content-Type: " . str_replace("\n", "", $email_files["type"][$key]) . $eol
- . "Content-Disposition: attachment; filename=\"" . preg_replace('~["\\n]~', '', $email_files["name"][$key]) . "\"$eol"
- . "Content-Transfer-Encoding: base64$eol"
- . $eol . chunk_split(base64_encode(file_get_contents($email_files["tmp_name"][$key])), 76, $eol) . $eol
- ;
- }
- }
- $beginning = "";
- $headers = "Content-Type: text/plain; charset=utf-8$eol" . "Content-Transfer-Encoding: 8bit";
- if ($attachments) {
- $attachments .= "--$boundary--$eol";
- $beginning = "--$boundary$eol$headers$eol$eol";
- $headers = "Content-Type: multipart/mixed; boundary=\"$boundary\"";
- }
- $headers .= $eol . "MIME-Version: 1.0$eol" . "X-Mailer: Adminer Editor"
- . ($_POST["email_from"] ? $eol . "From: " . str_replace("\n", "", $_POST["email_from"]) : "") //! should escape display name
- ;
$fields = fields($_GET["select"]);
foreach ($this->rowDescriptions($rows, $foreignKeys) as $row) {
- $replace = array();
+ $replace = array('{\\' => '{'); // allow literal {$name}
foreach ($matches[1] as $val) {
- $replace['{$' . "$val}"] = $this->editVal($row[$val], $fields[$val]); //! allow literal {$name}
+ $replace['{$' . "$val}"] = $this->editVal($row[$val], $fields[$val]);
}
$email = $row[$_POST["email_field"]];
- if (is_email($email) && mail($email, email_header(strtr($subject, $replace)), $beginning . strtr($message, $replace) . $attachments, $headers)) {
+ if (is_email($email) && send_email($email, strtr($subject, $replace), strtr($message, $replace), $_POST["email_from"], $_FILES["email_files"])) {
$sent++;
}
}
function editFunctions($field) {
$return = array("" => ($field["null"] || $field["auto_increment"] || $field["full_type"] == "tinyint(1)" ? "" : "*"));
+ //! respect driver
if (ereg('date|time', $field["type"])) {
$return[] = "now";
}
if ($field["type"] == "enum") {
return ($field["null"] ? "<input type='radio'$attrs value=''" . ($value || isset($_GET["select"]) ? "" : " checked") . ">" : "");
}
- $options = $this->foreignKeyOptions($table, $field["field"]);
+ $options = $this->_foreignKeyOptions($table, $field["field"]);
if ($options) {
return "<select$attrs>" . optionlist($options, $value, true) . "</select>";
}
$return = $connection->quote($return);
if (!ereg('varchar|text', $field["type"]) && $field["full_type"] != "tinyint(1)" && $value == "") {
$return = "NULL";
+ } elseif (ereg('^(md5|sha1)$', $function)) {
+ $return = "$function($return)";
}
return $return;
}
- function dumpOutput($select) {
+ function dumpOutput($select, $value = "") {
return "";
}
- function dumpFormat($select) {
- return "CSV";
+ function dumpFormat($select, $value = "") {
+ return html_select("format", array('csv' => 'CSV,', 'csv;' => 'CSV;'), $value, $select);
}
function navigation($missing) {
- global $VERSION;
+ global $VERSION, $token;
?>
<h1>
<a href="http://www.adminer.org/" id="h1"><?php echo $this->name(); ?></a>
?>
<form action="" method="post">
<p class="logout">
-<input type="hidden" name="token" value="<?php echo $_SESSION["tokens"][$_GET["server"]]; ?>">
+<input type="hidden" name="token" value="<?php echo $token; ?>">
<input type="submit" name="logout" value="<?php echo lang('Logout'); ?>">
</p>
</form>
}
}
- function foreignKeyOptions($table, $column) { // protected
+ function _foreignKeyOptions($table, $column) {
global $connection;
+ $table_status = table_status($table);
$foreignKeys = column_foreign_keys($table);
foreach ((array) $foreignKeys[$column] as $foreignKey) {
if (count($foreignKey["source"]) == 1) {
$id = idf_escape($foreignKey["target"][0]);
$name = $this->rowDescription($foreignKey["table"]);
if ($name != "") {
- $return = &$this->values[$foreignKey["table"]];
+ $return = &$this->_values[$foreignKey["table"]];
if (!isset($return)) {
- $return = array("" => "") + get_key_vals("SELECT $id, $name FROM " . idf_escape($foreignKey["table"]) . " ORDER BY 2 LIMIT 1001");
- if (count($return) > 1001) {
- $return = array();
- }
+ $return = ($table_status["Rows"] > 1000 ? array() : array("" => "") + get_key_vals("SELECT $id, $name FROM " . idf_escape($foreignKey["table"]) . " ORDER BY 2"));
}
return $return;
}
}
}
}
-
+
}
$adminer = (function_exists('adminer_object') ? adminer_object() : new Adminer);
return "=?UTF-8?B?" . base64_encode($header) . "?="; //! split long lines
}
-/** Get keys from first column and values from second
+/** Send e-mail in UTF-8
* @param string
-* @return array
+* @param string
+* @param string
+* @param string
+* @param array
+* @return
*/
-function get_key_vals($query) {
- global $connection;
- $return = array();
- $result = $connection->query($query);
- while ($row = $result->fetch_row()) {
- $return[$row[0]] = $row[1];
+function send_email($email, $subject, $message, $from = "", $files = array()) {
+ $eol = (strncasecmp(PHP_OS, "win", 3) ? "\n" : "\r\n"); // PHP_EOL available since PHP 4.3.10 and 5.0.2
+ $message = str_replace("\n", $eol, wordwrap(str_replace("\r", "", "$message\n")));
+ $boundary = uniqid("boundary");
+ $attachments = "";
+ foreach ($files["error"] as $key => $val) {
+ if (!$val) {
+ $attachments .= "--$boundary$eol"
+ . "Content-Type: " . str_replace("\n", "", $files["type"][$key]) . $eol
+ . "Content-Disposition: attachment; filename=\"" . preg_replace('~["\\n]~', '', $files["name"][$key]) . "\"$eol"
+ . "Content-Transfer-Encoding: base64$eol$eol"
+ . chunk_split(base64_encode(file_get_contents($files["tmp_name"][$key])), 76, $eol) . $eol
+ ;
+ }
+ }
+ $beginning = "";
+ $headers = "Content-Type: text/plain; charset=utf-8$eol" . "Content-Transfer-Encoding: 8bit";
+ if ($attachments) {
+ $attachments .= "--$boundary--$eol";
+ $beginning = "--$boundary$eol$headers$eol$eol";
+ $headers = "Content-Type: multipart/mixed; boundary=\"$boundary\"";
}
- return $return;
+ $headers .= $eol . "MIME-Version: 1.0$eol" . "X-Mailer: Adminer Editor"
+ . ($from ? $eol . "From: " . str_replace("\n", "", $from) : "") //! should escape display name
+ ;
+ return mail($email, email_header($subject), $beginning . $message . $attachments, $headers);
}
<?php
-/** Adminer Editor - Compact MySQL editor
+/** Adminer Editor - Compact database editor
* @link http://www.adminer.org/
* @author Jakub Vrana, http://php.vrana.cz/
* @copyright 2009 Jakub Vrana
*/
include "../adminer/include/bootstrap.inc.php";
+$drivers[DRIVER] = lang('Login');
if (isset($_GET["select"]) && ($_POST["edit"] || $_POST["clone"]) && !$_POST["save"]) {
$_GET["edit"] = $_GET["select"];
foreach (array_merge(
glob(dirname(__FILE__) . "/adminer/*.php"),
glob(dirname(__FILE__) . "/adminer/include/*.php"),
+ glob(dirname(__FILE__) . "/adminer/drivers/*.php"),
glob(dirname(__FILE__) . "/editor/*.php"),
glob(dirname(__FILE__) . "/editor/include/*.php")
) as $filename) {
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/coverage.php?coverage=0</td>
+ <td>coverage.php?coverage=0</td>
<td></td>
</tr>
<tr>
<td>open</td>
- <td>/adminer/adminer/?lang=en&username=ODBC</td>
+ <td>adminer/?username=ODBC&lang=en</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/</td>
+ <td>adminer/?username=ODBC</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&select=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&select=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&select=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&select=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&edit=albums&where%5Bid%5D=2</td>
+ <td>adminer/?username=ODBC&db=adminer_test&edit=albums&where%5Bid%5D=2</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&select=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&select=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&select=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&select=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?user=</td>
+ <td>adminer/?username=ODBC&user=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?processlist=</td>
+ <td>adminer/?username=ODBC&processlist=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&dump=</td>
+ <td>adminer/?username=ODBC&db=adminer_test&dump=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&event=</td>
+ <td>adminer/?username=ODBC&db=adminer_test&event=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&procedure=</td>
+ <td>adminer/?username=ODBC&db=adminer_test&procedure=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test</td>
+ <td>adminer/?username=ODBC&db=adminer_test</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&table=interprets</td>
+ <td>adminer/?username=ODBC&db=adminer_test&table=interprets</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?variables=</td>
+ <td>adminer/?username=ODBC&variables=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?sql=</td>
+ <td>adminer/?username=ODBC&sql=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/editor/example.php?lang=en&username=admin</td>
+ <td>editor/example.php?lang=en&username=admin</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&select=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&select=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&table=interprets</td>
+ <td>adminer/?username=ODBC&db=adminer_test&table=interprets</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&table=interprets&lang=en</td>
+ <td>adminer/?username=ODBC&db=adminer_test&table=interprets&lang=en</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&table=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&table=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&table=interprets</td>
+ <td>adminer/?username=ODBC&db=adminer_test&table=interprets</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&trigger=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&trigger=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&view=</td>
+ <td>adminer/?username=ODBC&db=adminer_test&view=</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&edit=interprets</td>
+ <td>adminer/?username=ODBC&db=adminer_test&edit=interprets</td>
<td></td>
</tr>
<tr>
</tr>
<tr>
<td>open</td>
- <td>/adminer/adminer/?db=adminer_test&edit=albums</td>
+ <td>adminer/?username=ODBC&db=adminer_test&edit=albums</td>
<td></td>
</tr>
<tr>
</thead><tbody>
<tr>
<td>open</td>
- <td>/adminer/adminer/</td>
+ <td>adminer/?username=ODBC</td>
<td></td>
</tr>
<tr>
</tr>
<tr>
<td>open</td>
- <td>/adminer/coverage.php</td>
+ <td>coverage.php</td>
<td></td>
</tr>
Transactions in export
Create view and routine options
Mass editation of individual rows
-Offer enum and set items in search - whisperer
Variables editation, especially timezone
-Use event $intervals + microseconds in relative date functions
Optionally check IP address
Disable spell checking in SQL textareas - spellcheck="false"
Accept Tab in SQL textareas, Ctrl+Enter to send form
Blob download and image display in edit form (important for Editor with hidden fields in select)
Add title to Logout, edit (in select) and select (in menu) in style "hever"
Shift-click in checkboxes to select range
-? LIKE %% operator
+Export by GET parameters
+Only first part of big BZ2 export is readable
? Column and table names auto-completition in SQL textarea
-? Aliasing of built-in functions can save 7 KB, function minification can save 7 KB, substitution of repetitive $a["a"] can save 4 KB, substitution of $_GET and friends can save 2 KB, JS packer can save 1 KB, not enclosing HTML attribute values can save 1.2 KB, replacing \\n by \n can save .3 KB
+? Aliasing of built-in functions can save 7 KB, function minification can save 7 KB, substitution of repetitive $a["a"] can save 4 KB, substitution of $_GET and friends can save 2 KB, aliasing of $connection->query, $connection->result and $connection->quote can save ~ 3 KB, JS packer can save 1 KB, not enclosing HTML attribute values can save 1.2 KB, replacing \\n by \n can save .3 KB
? Branch binary_compile: LZW compression of translations can save 30 KB, LZW compression of all texts can save 11 KB, remove of base64_decode() + using chars 127-255 in minification can save 1 KB
? AJAX editing - select page has all data to display edit form
+? MySQL geometry support
+Translations - database(s) have been dropped
Editor:
JavaScript data validation - columns containing word email, url, ...
Joining tables - PRIMARY KEY (table, joining)
Rank, Tree structure
Add whisperer to fields with foreign key to big table
+
+SQLite:
+CREATE DATABASE - PRAGMA encoding = "UTF-8"
+Detecion of non-existing database
+DROP DATABASE by file operations
+CSV import - ON DUPLICATE KEY UPDATE
+Export - views, triggers
+Delimiter in export and SQL command
+
+PostgreSQL:
+Users - SELECT * FROM pg_user
+ORDER BY COUNT(*)
+Table schema
+Export - http://www.postgresql.org/docs/8.4/static/functions-info.html
+Table status - http://www.postgresql.org/docs/8.4/static/functions-admin.html
+Column rights - http://www.postgresql.org/docs/8.4/static/functions-info.html
+Move table - ALTER TABLE SET SCHEMA
+bool in Editor
+
+MS SQL:
+Rename by sp_rename
+Detection of table collation
+PDO driver
-// downloaded from repository by verifyVersion()
+// downloaded from repository by verifyVersion() before Adminer 3.0.0
(function () { // cookie function is not defined in older versions
var date = new Date();
date.setDate(date.getDate() + 7); // valid for 7 days