├── .editorconfig ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── adminer ├── call.inc.php ├── check.inc.php ├── create.inc.php ├── database.inc.php ├── db.inc.php ├── designs.php ├── download.inc.php ├── drivers │ ├── mssql.inc.php │ ├── mysql.inc.php │ ├── oracle.inc.php │ ├── pgsql.inc.php │ └── sqlite.inc.php ├── dump.inc.php ├── edit.inc.php ├── elastic.php ├── event.inc.php ├── file.inc.php ├── foreign.inc.php ├── include │ ├── adminer.inc.php │ ├── auth.inc.php │ ├── bootstrap.inc.php │ ├── connect.inc.php │ ├── coverage.inc.php │ ├── db.inc.php │ ├── design.inc.php │ ├── driver.inc.php │ ├── editing.inc.php │ ├── errors.inc.php │ ├── functions.inc.php │ ├── html.inc.php │ ├── lang.inc.php │ ├── pdo.inc.php │ ├── plugin.inc.php │ ├── plugins.inc.php │ ├── tmpfile.inc.php │ ├── version.inc.php │ └── xxtea.inc.php ├── index.php ├── indexes.inc.php ├── lang │ ├── ar.inc.php │ ├── bg.inc.php │ ├── bn.inc.php │ ├── bs.inc.php │ ├── ca.inc.php │ ├── cs.inc.php │ ├── da.inc.php │ ├── de.inc.php │ ├── el.inc.php │ ├── en.inc.php │ ├── es.inc.php │ ├── et.inc.php │ ├── fa.inc.php │ ├── fi.inc.php │ ├── fr.inc.php │ ├── gl.inc.php │ ├── he.inc.php │ ├── hi.inc.php │ ├── hu.inc.php │ ├── id.inc.php │ ├── it.inc.php │ ├── ja.inc.php │ ├── ka.inc.php │ ├── ko.inc.php │ ├── lt.inc.php │ ├── lv.inc.php │ ├── ms.inc.php │ ├── nl.inc.php │ ├── no.inc.php │ ├── pl.inc.php │ ├── pt-br.inc.php │ ├── pt.inc.php │ ├── ro.inc.php │ ├── ru.inc.php │ ├── sk.inc.php │ ├── sl.inc.php │ ├── sr.inc.php │ ├── sv.inc.php │ ├── ta.inc.php │ ├── th.inc.php │ ├── tr.inc.php │ ├── uk.inc.php │ ├── uz.inc.php │ ├── vi.inc.php │ ├── xx.inc.php │ ├── zh-tw.inc.php │ └── zh.inc.php ├── privileges.inc.php ├── procedure.inc.php ├── processlist.inc.php ├── schema.inc.php ├── scheme.inc.php ├── script.inc.php ├── select.inc.php ├── sequence.inc.php ├── sql.inc.php ├── sqlite.php ├── static │ ├── dark.css │ ├── default.css │ ├── editing.js │ ├── functions.js │ └── logo.png ├── table.inc.php ├── trigger.inc.php ├── type.inc.php ├── user.inc.php ├── variables.inc.php └── view.inc.php ├── compile.php ├── composer.json ├── coverage.php ├── designs ├── README.md ├── adminer-dark │ ├── README.md │ └── adminer-dark.css ├── brade │ ├── README.md │ └── adminer.css ├── bueltge │ ├── README.md │ └── adminer.css ├── dracula │ ├── README.md │ └── adminer-dark.css ├── esterka │ ├── README.md │ └── adminer.css ├── flat │ ├── README.md │ └── adminer.css ├── galkaev │ ├── README.md │ └── adminer-dark.css ├── haeckel │ ├── README.md │ └── adminer.css ├── hever │ ├── README.md │ └── adminer.css ├── konya │ ├── README.md │ └── adminer.css ├── lavender-light │ ├── README.md │ └── adminer.css ├── lucas-sandery │ ├── README.md │ └── adminer.css ├── mancave │ ├── README.md │ └── adminer-dark.css ├── mvt │ ├── README.md │ └── adminer.css ├── nette │ ├── README.md │ └── adminer.css ├── ng9 │ ├── README.md │ └── adminer.css ├── nicu │ ├── README.md │ └── adminer.css ├── pappu687 │ ├── README.md │ └── adminer.css ├── paranoiq │ ├── README.md │ └── adminer.css ├── pepa-linha │ ├── README.md │ └── adminer.css ├── pokorny │ ├── README.md │ └── adminer.css ├── price │ ├── README.md │ └── adminer.css ├── rmsoft │ ├── README.md │ └── adminer.css ├── rmsoft_blue-dark │ ├── README.md │ └── adminer.css ├── rmsoft_blue │ ├── README.md │ └── adminer.css └── win98 │ ├── README.md │ └── adminer.css ├── developing.md ├── editor ├── db.inc.php ├── example.php ├── include │ ├── adminer.inc.php │ ├── connect.inc.php │ └── editing.inc.php ├── index.php ├── script.inc.php ├── sqlite.php └── static │ └── editing.js ├── eslint.config.mjs ├── lang.php ├── phpcs.xml ├── phpstan.neon ├── plugins ├── README.md ├── adminer.js.php ├── backward-keys.php ├── before-unload.php ├── codemirror.php ├── config.php ├── dark-switcher.php ├── database-hide.php ├── designs.php ├── drivers │ ├── README.md │ ├── clickhouse.php │ ├── elastic.php │ ├── firebird.php │ ├── imap.php │ ├── mongo.php │ └── simpledb.php ├── dump-alter.php ├── dump-bz2.php ├── dump-date.php ├── dump-json.php ├── dump-php.php ├── dump-xml.php ├── dump-zip.php ├── edit-calendar.php ├── edit-foreign.php ├── edit-textarea.php ├── editor-setup.php ├── editor-views.php ├── email-table.php ├── enum-option.php ├── file-upload.php ├── foreign-system.php ├── frames.php ├── json-column.php ├── login-ip.php ├── login-otp.php ├── login-password-less.php ├── login-servers.php ├── login-ssl.php ├── login-table.php ├── master-slave.php ├── menu-links.php ├── monaco.php ├── pretty-json-column.php ├── prism.php ├── select-email.php ├── slugify.php ├── sql-gemini.php ├── sql-log.php ├── table-indexes-structure.php ├── table-structure.php ├── tables-filter.php ├── tinymce.php ├── translation.php ├── version-github.php └── version-noverify.php └── todo.txt /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{php,css,js,xml}] 11 | indent_style = tab 12 | 13 | [*.json] 14 | indent_style = space 15 | indent_size = 4 16 | 17 | [*.md] 18 | indent_style = space 19 | trim_trailing_whitespace = false 20 | max_line_length = 120 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | - Reproducible [bug reports](https://github.com/vrana/adminer/issues/new?template=bug_report.md) are warmly welcomed. 2 | - [Feature requests](https://github.com/vrana/adminer/issues/new?template=BLANK_ISSUE) are also fine, but I'm quite picky about what to accept into Adminer. Please don't be offended if I close the issue as "Not Planned," especially if it can be achieved with a plugin. 3 | - [Pull requests](https://github.com/vrana/adminer/pulls) for both bug fixes and simple features are welcome. Before working on anything more complicated, get familiar with the [Adminer philosophy](https://github.com/vrana/adminer/blob/master/developing.md). 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2.0 or GPL 2 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ROOT_DIRECTORY = $(shell dirname "$(realpath $(lastword $(MAKEFILE_LIST)))") 2 | PHP := $(shell which php) 3 | PORT := 8000 4 | 5 | 6 | .DEFAULT_GOAL := default 7 | 8 | 9 | .PHONY: default 10 | default: compile 11 | 12 | .PHONY: compile 13 | compile: 14 | $(PHP) $(ROOT_DIRECTORY)/compile.php 15 | 16 | .PHONY: server 17 | server: 18 | php \ 19 | --server 127.0.0.1:$(PORT) \ 20 | --docroot $(ROOT_DIRECTORY) 21 | 22 | .PHONY: initialize 23 | initialize: 24 | git \ 25 | -C $(ROOT_DIRECTORY) \ 26 | submodule \ 27 | update \ 28 | --init \ 29 | --recursive 30 | 31 | .PHONY: clean 32 | clean: 33 | rm \ 34 | --recursive \ 35 | --force \ 36 | $(ROOT_DIRECTORY)/adminer.php 37 | 38 | .PHONY: clean.all 39 | clean.all: clean 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adminer 2 | **Adminer** is a full-featured database management tool written in PHP. It consists of a single file ready to deploy to the target server. 3 | **Adminer Editor** offers data manipulation for end-users. 4 | 5 | [Official Website](https://www.adminer.org/) 6 | 7 | ## Features 8 | - **Supports:** MySQL, MariaDB, PostgreSQL, CockroachDB, SQLite, MS SQL, Oracle 9 | - **Plugins for:** Elasticsearch, SimpleDB, MongoDB, Firebird, ClickHouse, IMAP 10 | - **Requirements:** PHP 5.3+ (compiled file), PHP 7.4+ (source codes) 11 | 12 | ## Screenshot 13 | ![Table structure](https://www.adminer.org/static/screenshots/table.png) 14 | 15 | ## Installation 16 | If downloaded from Git then run: `git submodule update --init` 17 | 18 | - `adminer/index.php` - Run development version of Adminer 19 | - `editor/index.php` - Run development version of Adminer Editor 20 | - `editor/example.php` - Example customization 21 | - `compile.php` - Create a single file version 22 | - `lang.php` - Update translations 23 | - `tests/*.html` - Katalon Recorder test suites 24 | 25 | ## Plugins 26 | There are several plugins distributed with Adminer, as well as many user-contributed plugins listed on the [Adminer Plugins page](https://www.adminer.org/plugins/). 27 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Only the latest published version and the latest development version (last commit) are supported. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | To report a vulnerability, create a new draft security advisory at [GitHub Security Advisories](https://github.com/vrana/adminer/security/advisories/new). 10 | 11 | Security issues are handled with top priority. If you don't receive a response within a week, please follow up on the report. Once a vulnerability is acknowledged, a fix should be available and a new version released within a few days. The issue will be made public after the fix is released or if the report is declined. 12 | -------------------------------------------------------------------------------- /adminer/call.inc.php: -------------------------------------------------------------------------------- 1 | $field) { 11 | if (substr($field["inout"], -3) == "OUT" && JUSH == 'sql') { 12 | $out[$i] = "@" . idf_escape($field["field"]) . " AS " . idf_escape($field["field"]); 13 | } 14 | if (!$field["inout"] || substr($field["inout"], 0, 2) == "IN") { 15 | $in[] = $i; 16 | } 17 | } 18 | 19 | if (!$error && $_POST) { 20 | $call = array(); 21 | foreach ($routine["fields"] as $key => $field) { 22 | $val = ""; 23 | if (in_array($key, $in)) { 24 | $val = process_input($field); 25 | if ($val === false) { 26 | $val = "''"; 27 | } 28 | if (isset($out[$key])) { 29 | connection()->query("SET @" . idf_escape($field["field"]) . " = $val"); 30 | } 31 | } 32 | if (isset($out[$key])) { 33 | $call[] = "@" . idf_escape($field["field"]); 34 | } elseif (in_array($key, $in)) { 35 | $call[] = $val; 36 | } 37 | } 38 | 39 | $query = (isset($_GET["callf"]) ? "SELECT" : "CALL") . " " . table($PROCEDURE) . "(" . implode(", ", $call) . ")"; 40 | $start = microtime(true); 41 | $result = connection()->multi_query($query); 42 | $affected = connection()->affected_rows; // getting warnings overwrites this 43 | echo adminer()->selectQuery($query, $start, !$result); 44 | 45 | if (!$result) { 46 | echo "

" . error() . "\n"; 47 | } else { 48 | $connection2 = connect(); 49 | if ($connection2) { 50 | $connection2->select_db(DB); 51 | } 52 | 53 | do { 54 | $result = connection()->store_result(); 55 | if (is_object($result)) { 56 | print_select_result($result, $connection2); 57 | } else { 58 | echo "

" . lang('Routine has been called, %d row(s) affected.', $affected) 59 | . " " . @date("H:i:s") . "\n" // @ - time zone may be not set 60 | ; 61 | } 62 | } while (connection()->next_result()); 63 | 64 | if ($out) { 65 | print_select_result(connection()->query("SELECT " . implode(", ", $out))); 66 | } 67 | } 68 | } 69 | ?> 70 | 71 |

72 | \n"; 75 | foreach ($in as $key) { 76 | $field = $routine["fields"][$key]; 77 | $name = $field["field"]; 78 | echo "" . adminer()->fieldName($field); 79 | $value = idx($_POST["fields"], $name); 80 | if ($value != "") { 81 | if ($field["type"] == "set") { 82 | $value = implode(",", $value); 83 | } 84 | } 85 | input($field, $value, idx($_POST["function"], $name, "")); // param name can be empty 86 | echo "\n"; 87 | } 88 | echo "\n"; 89 | } 90 | ?> 91 |

92 | 93 | 94 |

95 | 96 |
 97 | ', preg_replace('~\|~', '', preg_replace('~\|$~m', "", rtrim($s))));
103 | }
104 | 
105 | $table = '(\+--[-+]+\+\n)';
106 | $row = '(\| .* \|\n)';
107 | echo preg_replace_callback(
108 | 	"~^$table?$row$table?($row*)$table?~m",
109 | 	function ($match) {
110 | 		$first_row = pre_tr($match[2]);
111 | 		return "\n" . ($match[1] ? "$first_row\n" : $first_row) . pre_tr($match[4]) . "\n
"; 112 | }, 113 | preg_replace( 114 | '~(\n( -|mysql)> )(.+)~', 115 | "\\1\\3", 116 | preg_replace('~(.+)\n---+\n~', "\\1\n", h($routine['comment'])) 117 | ) 118 | ); 119 | ?> 120 |
121 | -------------------------------------------------------------------------------- /adminer/check.inc.php: -------------------------------------------------------------------------------- 1 | $TABLE)); 25 | 26 | if (!$row) { 27 | $checks = driver()->checkConstraints($TABLE); 28 | $row = array("name" => $name, "clause" => $checks[$name]); 29 | } 30 | ?> 31 | 32 |
33 |

'; 36 | } 37 | echo doc_link(array( 38 | 'sql' => "create-table-check-constraints.html", 39 | 'mariadb' => "constraint/", 40 | 'pgsql' => "ddl-constraints.html#DDL-CONSTRAINTS-CHECK-CONSTRAINTS", 41 | 'mssql' => "relational-databases/tables/create-check-constraints", 42 | 'sqlite' => "lang_createtable.html#check_constraints", 43 | ), "?"); 44 | ?> 45 |

46 |

47 | 48 | 49 | 50 | 51 |

52 | -------------------------------------------------------------------------------- /adminer/database.inc.php: -------------------------------------------------------------------------------- 1 | 59 | 60 |
61 |

62 | ' . h($name) . '
' 65 | : '' 66 | ) . "\n" . ($collations ? html_select("collation", array("" => "(" . lang('collation') . ")") + $collations, $row["collation"]) . doc_link(array( 67 | 'sql' => "charset-charsets.html", 68 | 'mariadb' => "supported-character-sets-and-collations/", 69 | 'mssql' => "relational-databases/system-functions/sys-fn-helpcollations-transact-sql", 70 | )) : ""); 71 | ?> 72 | 73 | " . confirm(lang('Drop %s?', DB)) . "\n"; 76 | } elseif (!$_POST["add"] && $_GET["db"] == "") { 77 | echo icon("plus", "add[0]", "+", lang('Add next')) . "\n"; 78 | } 79 | echo input_token(); 80 | ?> 81 |

82 | -------------------------------------------------------------------------------- /adminer/designs.php: -------------------------------------------------------------------------------- 1 | select($TABLE, $select, array(where($_GET, $fields)), $select); 10 | $row = ($result ? $result->fetch_row() : array()); 11 | echo driver()->value($row[0], $fields[$_GET["field"]]); 12 | exit; // don't output footer 13 | -------------------------------------------------------------------------------- /adminer/edit.inc.php: -------------------------------------------------------------------------------- 1 | $field) { 12 | if (!isset($field["privileges"][$update ? "update" : "insert"]) || adminer()->fieldName($field) == "" || $field["generated"]) { 13 | unset($fields[$name]); 14 | } 15 | } 16 | 17 | if ($_POST && !$error && !isset($_GET["select"])) { 18 | $location = $_POST["referer"]; 19 | if ($_POST["insert"]) { // continue edit or insert 20 | $location = ($update ? null : $_SERVER["REQUEST_URI"]); 21 | } elseif (!preg_match('~^.+&select=.+$~', $location)) { 22 | $location = ME . "select=" . urlencode($TABLE); 23 | } 24 | 25 | $indexes = indexes($TABLE); 26 | $unique_array = unique_array($_GET["where"], $indexes); 27 | $query_where = "\nWHERE $where"; 28 | 29 | if (isset($_POST["delete"])) { 30 | queries_redirect( 31 | $location, 32 | lang('Item has been deleted.'), 33 | driver()->delete($TABLE, $query_where, $unique_array ? 0 : 1) 34 | ); 35 | 36 | } else { 37 | $set = array(); 38 | foreach ($fields as $name => $field) { 39 | $val = process_input($field); 40 | if ($val !== false && $val !== null) { 41 | $set[idf_escape($name)] = $val; 42 | } 43 | } 44 | 45 | if ($update) { 46 | if (!$set) { 47 | redirect($location); 48 | } 49 | queries_redirect( 50 | $location, 51 | lang('Item has been updated.'), 52 | driver()->update($TABLE, $set, $query_where, $unique_array ? 0 : 1) 53 | ); 54 | if (is_ajax()) { 55 | page_headers(); 56 | page_messages($error); 57 | exit; 58 | } 59 | } else { 60 | $result = driver()->insert($TABLE, $set); 61 | $last_id = ($result ? last_id($result) : 0); 62 | queries_redirect($location, lang('Item%s has been inserted.', ($last_id ? " $last_id" : "")), $result); //! link 63 | } 64 | } 65 | } 66 | 67 | $row = null; 68 | if ($_POST["save"]) { 69 | $row = (array) $_POST["fields"]; 70 | } elseif ($where) { 71 | $select = array(); 72 | foreach ($fields as $name => $field) { 73 | if (isset($field["privileges"]["select"])) { 74 | $as = ($_POST["clone"] && $field["auto_increment"] ? "''" : convert_field($field)); 75 | $select[] = ($as ? "$as AS " : "") . idf_escape($name); 76 | } 77 | } 78 | $row = array(); 79 | if (!support("table")) { 80 | $select = array("*"); 81 | } 82 | if ($select) { 83 | $result = driver()->select($TABLE, $select, array($where), $select, array(), (isset($_GET["select"]) ? 2 : 1)); 84 | if (!$result) { 85 | $error = error(); 86 | } else { 87 | $row = $result->fetch_assoc(); 88 | if (!$row) { // MySQLi returns null 89 | $row = false; 90 | } 91 | } 92 | if (isset($_GET["select"]) && (!$row || $result->fetch_assoc())) { // $result->num_rows != 1 isn't available in all drivers 93 | $row = null; 94 | } 95 | } 96 | } 97 | 98 | if (!support("table") && !$fields) { // used by Mongo and SimpleDB 99 | if (!$where) { // insert 100 | $result = driver()->select($TABLE, array("*"), array(), array("*")); 101 | $row = ($result ? $result->fetch_assoc() : false); 102 | if (!$row) { 103 | $row = array(driver()->primary => ""); 104 | } 105 | } 106 | if ($row) { 107 | foreach ($row as $key => $val) { 108 | if (!$where) { 109 | $row[$key] = null; 110 | } 111 | $fields[$key] = array("field" => $key, "null" => ($key != driver()->primary), "auto_increment" => ($key == driver()->primary)); 112 | } 113 | } 114 | } 115 | 116 | edit_form($TABLE, $fields, $row, $update, $error); 117 | -------------------------------------------------------------------------------- /adminer/elastic.php: -------------------------------------------------------------------------------- 1 | "ENABLE", "DISABLED" => "DISABLE", "SLAVESIDE_DISABLED" => "DISABLE ON SLAVE"); 7 | $row = $_POST; 8 | 9 | if ($_POST && !$error) { 10 | if ($_POST["drop"]) { 11 | query_redirect("DROP EVENT " . idf_escape($EVENT), substr(ME, 0, -1), lang('Event has been dropped.')); 12 | } elseif (in_array($row["INTERVAL_FIELD"], $intervals) && isset($statuses[$row["STATUS"]])) { 13 | $schedule = "\nON SCHEDULE " . ($row["INTERVAL_VALUE"] 14 | ? "EVERY " . q($row["INTERVAL_VALUE"]) . " $row[INTERVAL_FIELD]" 15 | . ($row["STARTS"] ? " STARTS " . q($row["STARTS"]) : "") 16 | . ($row["ENDS"] ? " ENDS " . q($row["ENDS"]) : "") //! ALTER EVENT doesn't drop ENDS - MySQL bug #39173 17 | : "AT " . q($row["STARTS"]) 18 | ) . " ON COMPLETION" . ($row["ON_COMPLETION"] ? "" : " NOT") . " PRESERVE" 19 | ; 20 | 21 | queries_redirect( 22 | substr(ME, 0, -1), 23 | ($EVENT != "" ? lang('Event has been altered.') : lang('Event has been created.')), 24 | queries( 25 | ($EVENT != "" 26 | ? "ALTER EVENT " . idf_escape($EVENT) . $schedule . ($EVENT != $row["EVENT_NAME"] ? "\nRENAME TO " . idf_escape($row["EVENT_NAME"]) : "") 27 | : "CREATE EVENT " . idf_escape($row["EVENT_NAME"]) . $schedule 28 | ) . "\n" . $statuses[$row["STATUS"]] . " COMMENT " . q($row["EVENT_COMMENT"]) 29 | . rtrim(" DO\n$row[EVENT_DEFINITION]", ";") . ";" 30 | ) 31 | ); 32 | } 33 | } 34 | 35 | page_header(($EVENT != "" ? lang('Alter event') . ": " . h($EVENT) : lang('Create event')), $error); 36 | 37 | if (!$row && $EVENT != "") { 38 | $rows = get_rows("SELECT * FROM information_schema.EVENTS WHERE EVENT_SCHEMA = " . q(DB) . " AND EVENT_NAME = " . q($EVENT)); 39 | $row = reset($rows); 40 | } 41 | ?> 42 | 43 |
44 | 45 |
" data-maxlength="64" autocapitalize="off"> 46 |
"> 47 |
"> 48 |
" class="size"> 49 |
50 |
" data-maxlength="64"> 51 |
52 |
53 |

54 |

55 | 56 | 57 | 58 | 59 | 60 |

61 | -------------------------------------------------------------------------------- /adminer/file.inc.php: -------------------------------------------------------------------------------- 1 | $val) { 14 | $target[$key] = $row["target"][$key]; 15 | } 16 | $row["target"] = $target; 17 | } 18 | 19 | if (JUSH == "sqlite") { 20 | $result = recreate_table($TABLE, $TABLE, array(), array(), array(" $name" => ($row["drop"] ? "" : " " . format_foreign_key($row)))); 21 | } else { 22 | $alter = "ALTER TABLE " . table($TABLE); 23 | $result = ($name == "" || queries("$alter DROP " . (JUSH == "sql" ? "FOREIGN KEY " : "CONSTRAINT ") . idf_escape($name))); 24 | if (!$row["drop"]) { 25 | $result = queries("$alter ADD" . format_foreign_key($row)); 26 | } 27 | } 28 | queries_redirect( 29 | ME . "table=" . urlencode($TABLE), 30 | ($row["drop"] ? lang('Foreign key has been dropped.') : ($name != "" ? lang('Foreign key has been altered.') : lang('Foreign key has been created.'))), 31 | $result 32 | ); 33 | if (!$row["drop"]) { 34 | $error = lang('Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.'); //! no partitioning 35 | } 36 | } 37 | 38 | page_header(lang('Foreign key'), $error, array("table" => $TABLE), h($TABLE)); 39 | 40 | if ($_POST) { 41 | ksort($row["source"]); 42 | if ($_POST["add"]) { 43 | $row["source"][] = ""; 44 | } elseif ($_POST["change"] || $_POST["change-js"]) { 45 | $row["target"] = array(); 46 | } 47 | } elseif ($name != "") { 48 | $foreign_keys = foreign_keys($TABLE); 49 | $row = $foreign_keys[$name]; 50 | $row["source"][] = ""; 51 | } else { 52 | $row["table"] = $TABLE; 53 | $row["source"] = array(""); 54 | } 55 | ?> 56 | 57 |
58 | select_db($row["db"]); 62 | } 63 | if ($row["ns"] != "") { 64 | $orig_schema = get_schema(); 65 | set_schema($row["ns"]); 66 | } 67 | $referencable = array_keys(array_filter(table_status('', true), 'Adminer\fk_support')); 68 | $target = array_keys(fields(in_array($row["table"], $referencable) ? $row["table"] : reset($referencable))); 69 | $onchange = "this.form['change-js'].value = '1'; this.form.submit();"; 70 | echo "

\n"; 71 | if (support("scheme")) { 72 | $schemas = array_filter(adminer()->schemas(), function ($schema) { 73 | return !preg_match('~^information_schema$~i', $schema); 74 | }); 75 | echo ""; 76 | if ($row["ns"] != "") { 77 | set_schema($orig_schema); 78 | } 79 | } elseif (JUSH != "sqlite") { 80 | $dbs = array(); 81 | foreach (adminer()->databases() as $db) { 82 | if (!information_schema($db)) { 83 | $dbs[] = $db; 84 | } 85 | } 86 | echo ""; 87 | } 88 | echo input_hidden("change-js"); 89 | ?> 90 |

91 | 92 | 93 | $val) { 96 | echo ""; 97 | echo "
" . html_select("source[" . (+$key) . "]", array(-1 => "") + $source, $val, ($j == count($row["source"]) - 1 ? "foreignAddRow.call(this);" : ""), "label-source"); 98 | echo "" . html_select("target[" . (+$key) . "]", $target, idx($row["target"], $key), "", "label-target"); 99 | $j++; 100 | } 101 | ?> 102 |
103 |

104 | 105 | 106 | "innodb-foreign-key-constraints.html", 108 | 'mariadb' => "foreign-keys/", 109 | 'pgsql' => "sql-createtable.html#SQL-CREATETABLE-REFERENCES", 110 | 'mssql' => "t-sql/statements/create-table-transact-sql", 111 | 'oracle' => "SQLRF01111", 112 | )); ?> 113 |

114 | 115 |

116 | 117 | 118 | 119 | 120 |

121 | -------------------------------------------------------------------------------- /adminer/include/bootstrap.inc.php: -------------------------------------------------------------------------------- 1 | $_POST["signature"], "version" => $_POST["version"]))); 38 | } 39 | exit; 40 | } 41 | 42 | // Adminer doesn't use any global variables; they used to be declared here 43 | 44 | if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility 45 | $_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"]; 46 | } 47 | if (!strpos($_SERVER["REQUEST_URI"], '?') && $_SERVER["QUERY_STRING"] != "") { // IIS 7 compatibility 48 | $_SERVER["REQUEST_URI"] .= "?$_SERVER[QUERY_STRING]"; 49 | } 50 | if ($_SERVER["HTTP_X_FORWARDED_PREFIX"]) { 51 | $_SERVER["REQUEST_URI"] = $_SERVER["HTTP_X_FORWARDED_PREFIX"] . $_SERVER["REQUEST_URI"]; 52 | } 53 | define('Adminer\HTTPS', ($_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off")) || ini_bool("session.cookie_secure")); // session.cookie_secure could be set on HTTP if we are behind a reverse proxy 54 | 55 | @ini_set("session.use_trans_sid", '0'); // protect links in export, @ - may be disabled 56 | if (!defined("SID")) { 57 | session_cache_limiter(""); // to allow restarting session 58 | session_name("adminer_sid"); // use specific session name to get own namespace 59 | session_set_cookie_params(0, preg_replace('~\?.*~', '', $_SERVER["REQUEST_URI"]), "", HTTPS, true); // ini_set() may be disabled 60 | session_start(); 61 | } 62 | 63 | // disable magic quotes to be able to use database escaping function 64 | remove_slashes(array(&$_GET, &$_POST, &$_COOKIE), $filter); 65 | if (function_exists("get_magic_quotes_runtime") && get_magic_quotes_runtime()) { 66 | set_magic_quotes_runtime(false); 67 | } 68 | @set_time_limit(0); // @ - can be disabled 69 | @ini_set("precision", '15'); // @ - can be disabled, 15 - internal PHP precision 70 | 71 | include "../adminer/include/lang.inc.php"; 72 | include "../adminer/lang/" . LANG . ".inc.php"; 73 | include "../adminer/include/db.inc.php"; 74 | include "../adminer/include/pdo.inc.php"; 75 | include "../adminer/include/driver.inc.php"; 76 | include "../adminer/drivers/sqlite.inc.php"; 77 | include "../adminer/drivers/pgsql.inc.php"; 78 | include "../adminer/drivers/oracle.inc.php"; 79 | include "../adminer/drivers/mssql.inc.php"; 80 | include "./include/adminer.inc.php"; 81 | include "../adminer/include/plugins.inc.php"; 82 | include "../adminer/include/plugin.inc.php"; 83 | 84 | Adminer::$instance = 85 | (function_exists('adminer_object') ? adminer_object() : 86 | (is_dir("adminer-plugins") || file_exists("adminer-plugins.php") ? new Plugins(null) : 87 | new Adminer 88 | )); 89 | 90 | // this is matched by compile.php 91 | include "../adminer/drivers/mysql.inc.php"; // must be included as last driver 92 | 93 | define('Adminer\JUSH', Driver::$jush); 94 | define('Adminer\SERVER', $_GET[DRIVER]); // read from pgsql=localhost, '' means default server, null means no server 95 | define('Adminer\DB', $_GET["db"]); // for the sake of speed and size 96 | define( 97 | 'Adminer\ME', 98 | preg_replace('~\?.*~', '', relative_uri()) . '?' 99 | . (sid() ? SID . '&' : '') 100 | . (SERVER !== null ? DRIVER . "=" . urlencode(SERVER) . '&' : '') 101 | . ($_GET["ext"] ? "ext=" . urlencode($_GET["ext"]) . '&' : '') 102 | . (isset($_GET["username"]) ? "username=" . urlencode($_GET["username"]) . '&' : '') 103 | . (DB != "" ? 'db=' . urlencode(DB) . '&' . (isset($_GET["ns"]) ? "ns=" . urlencode($_GET["ns"]) . "&" : "") : '') 104 | ); 105 | 106 | include "../adminer/include/design.inc.php"; 107 | include "../adminer/include/xxtea.inc.php"; 108 | include "../adminer/include/auth.inc.php"; 109 | include "./include/editing.inc.php"; 110 | include "./include/connect.inc.php"; 111 | -------------------------------------------------------------------------------- /adminer/include/coverage.inc.php: -------------------------------------------------------------------------------- 1 | $lines) { 10 | foreach ($lines as $l => $val) { 11 | if (!idx($coverage[$filename], $l) || $val > 0) { 12 | $coverage[$filename][$l] = $val; 13 | } 14 | } 15 | file_put_contents($coverage_filename, serialize($coverage)); 16 | } 17 | } 18 | xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); 19 | register_shutdown_function('Adminer\save_coverage'); 20 | } 21 | -------------------------------------------------------------------------------- /adminer/include/db.inc.php: -------------------------------------------------------------------------------- 1 | multi = $this->query($query); 43 | } 44 | 45 | /** Get current resultset 46 | * @return Result|bool 47 | */ 48 | function store_result() { 49 | return $this->multi; 50 | } 51 | 52 | /** Fetch next resultset */ 53 | function next_result(): bool { 54 | return false; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /adminer/include/errors.inc.php: -------------------------------------------------------------------------------- 1 | pdo = new \PDO($dsn, $username, $password, $options); 18 | } catch (\Exception $ex) { 19 | return $ex->getMessage(); 20 | } 21 | $this->server_info = @$this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION); 22 | return ''; 23 | } 24 | 25 | function quote(string $string): string { 26 | return $this->pdo->quote($string); 27 | } 28 | 29 | function query(string $query, bool $unbuffered = false) { 30 | /** @var Result|bool */ 31 | $result = $this->pdo->query($query); 32 | $this->error = ""; 33 | if (!$result) { 34 | list(, $this->errno, $this->error) = $this->pdo->errorInfo(); 35 | if (!$this->error) { 36 | $this->error = lang('Unknown error.'); 37 | } 38 | return false; 39 | } 40 | $this->store_result($result); 41 | return $result; 42 | } 43 | 44 | function store_result($result = null) { 45 | if (!$result) { 46 | $result = $this->multi; 47 | if (!$result) { 48 | return false; 49 | } 50 | } 51 | if ($result->columnCount()) { 52 | $result->num_rows = $result->rowCount(); // is not guaranteed to work with all drivers 53 | return $result; 54 | } 55 | $this->affected_rows = $result->rowCount(); 56 | return true; 57 | } 58 | 59 | function next_result(): bool { 60 | /** @var PdoResult|bool */ 61 | $result = $this->multi; 62 | if (!is_object($result)) { 63 | return false; 64 | } 65 | $result->_offset = 0; 66 | return @$result->nextRowset(); // @ - PDO_PgSQL doesn't support it 67 | } 68 | } 69 | 70 | class PdoResult extends \PDOStatement { 71 | public $_offset = 0, $num_rows; 72 | 73 | function fetch_assoc() { 74 | return $this->fetch_array(\PDO::FETCH_ASSOC); 75 | } 76 | 77 | function fetch_row() { 78 | return $this->fetch_array(\PDO::FETCH_NUM); 79 | } 80 | 81 | private function fetch_array(int $mode) { 82 | $return = $this->fetch($mode); 83 | return ($return ? array_map(array($this, 'unresource'), $return) : $return); 84 | } 85 | 86 | private function unresource($val) { 87 | return (is_resource($val) ? stream_get_contents($val) : $val); 88 | } 89 | 90 | function fetch_field(): \stdClass { 91 | $row = (object) $this->getColumnMeta($this->_offset++); 92 | $type = $row->pdo_type; 93 | $row->type = ($type == \PDO::PARAM_INT ? 0 : 15); 94 | $row->charsetnr = ($type == \PDO::PARAM_LOB || (isset($row->flags) && in_array("blob", (array) $row->flags)) ? 63 : 0); 95 | return $row; 96 | } 97 | 98 | function seek($offset) { 99 | for ($i=0; $i < $offset; $i++) { 100 | $this->fetch(); 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /adminer/include/plugin.inc.php: -------------------------------------------------------------------------------- 1 | >[] */ protected $translations = array(); // key is language code 7 | 8 | /** Get plain text plugin description; empty string means to use the first line of class doc-comment 9 | * @return string 10 | */ 11 | function description() { 12 | return $this->lang(''); 13 | } 14 | 15 | /** Get URL of plugin screenshot 16 | * @return string 17 | */ 18 | function screenshot() { 19 | return ""; 20 | } 21 | 22 | /** Translate a string from $this->translations; Adminer\lang() doesn't work for single language versions 23 | * @param literal-string $idf 24 | * @param float|string $number 25 | */ 26 | protected function lang(string $idf, $number = null): string { 27 | $args = func_get_args(); 28 | $args[0] = idx($this->translations[LANG], $idf) ?: $idf; 29 | return call_user_func_array('Adminer\lang_format', $args); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /adminer/include/plugins.inc.php: -------------------------------------------------------------------------------- 1 | true, 'dumpOutput' => true, 'editRowPrint' => true, 'editFunctions' => true, 'config' => true); // these hooks expect the value to be appended to the result 6 | 7 | /** @var list @visibility protected(set) */ public array $plugins; 8 | /** @visibility protected(set) */ public string $error = ''; // HTML 9 | /** @var list[] */ private array $hooks = array(); 10 | 11 | /** Register plugins 12 | * @param ?list $plugins object instances or null to autoload plugins from adminer-plugins/ 13 | */ 14 | function __construct(?array $plugins) { 15 | if ($plugins === null) { 16 | $plugins = array(); 17 | $basename = "adminer-plugins"; 18 | if (is_dir($basename)) { 19 | foreach (glob("$basename/*.php") as $filename) { 20 | $include = include_once "./$filename"; 21 | } 22 | } 23 | $help = " href='https://www.adminer.org/plugins/#use'" . target_blank(); 24 | if (file_exists("$basename.php")) { 25 | $include = include_once "./$basename.php"; // example: return array(new AdminerLoginOtp($secret)) 26 | if (is_array($include)) { 27 | foreach ($include as $plugin) { 28 | $plugins[get_class($plugin)] = $plugin; 29 | } 30 | } else { 31 | $this->error .= lang('%s must return an array.', "$basename.php", $help) . "
"; 32 | } 33 | } 34 | foreach (get_declared_classes() as $class) { 35 | if (!$plugins[$class] && preg_match('~^Adminer\w~i', $class)) { 36 | // we need to use reflection because PHP 7.1 throws ArgumentCountError for missing arguments but older versions issue a warning 37 | $reflection = new \ReflectionClass($class); 38 | $constructor = $reflection->getConstructor(); 39 | if ($constructor && $constructor->getNumberOfRequiredParameters()) { 40 | $this->error .= lang('Configure %s in %s.', $help, "$class", "$basename.php") . "
"; 41 | } else { 42 | $plugins[$class] = new $class; 43 | } 44 | } 45 | } 46 | } 47 | $this->plugins = $plugins; 48 | 49 | $adminer = new Adminer; 50 | $plugins[] = $adminer; 51 | $reflection = new \ReflectionObject($adminer); 52 | foreach ($reflection->getMethods() as $method) { 53 | foreach ($plugins as $plugin) { 54 | $name = $method->getName(); 55 | if (method_exists($plugin, $name)) { 56 | $this->hooks[$name][] = $plugin; 57 | } 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * @param literal-string $name 64 | * @param mixed[] $params 65 | * @return mixed 66 | */ 67 | function __call(string $name, array $params) { 68 | $args = array(); 69 | foreach ($params as $key => $val) { 70 | // some plugins accept params by reference - we don't need to propage it outside, just to the other plugins 71 | $args[] = &$params[$key]; 72 | } 73 | $return = null; 74 | foreach ($this->hooks[$name] as $plugin) { 75 | $value = call_user_func_array(array($plugin, $name), $args); 76 | if ($value !== null) { 77 | if (!self::$append[$name]) { // non-null value from non-appending method short-circuits the other plugins 78 | return $value; 79 | } 80 | $return = $value + (array) $return; 81 | } 82 | } 83 | return $return; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /adminer/include/tmpfile.inc.php: -------------------------------------------------------------------------------- 1 | handler = tmpfile(); 10 | } 11 | 12 | function write(string $contents): void { 13 | $this->size += strlen($contents); 14 | fwrite($this->handler, $contents); 15 | } 16 | 17 | function send(): void { 18 | fseek($this->handler, 0); 19 | fpassthru($this->handler); 20 | fclose($this->handler); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /adminer/include/version.inc.php: -------------------------------------------------------------------------------- 1 | 6 | * @link http://www.coolcode.cn/?action=show&id=128 7 | */ 8 | 9 | function int32(int $n): int { 10 | while ($n >= 2147483648) { 11 | $n -= 4294967296; 12 | } 13 | while ($n <= -2147483649) { 14 | $n += 4294967296; 15 | } 16 | return (int) $n; 17 | } 18 | 19 | /** 20 | * @param int[] $v 21 | */ 22 | function long2str(array $v, bool $w): string { 23 | $s = ''; 24 | foreach ($v as $val) { 25 | $s .= pack('V', $val); 26 | } 27 | if ($w) { 28 | return substr($s, 0, end($v)); 29 | } 30 | return $s; 31 | } 32 | 33 | /** 34 | * @return int[] 35 | */ 36 | function str2long(string $s, bool $w): array { 37 | $v = array_values(unpack('V*', str_pad($s, 4 * ceil(strlen($s) / 4), "\0"))); 38 | if ($w) { 39 | $v[] = strlen($s); 40 | } 41 | return $v; 42 | } 43 | 44 | function xxtea_mx(int $z, int $y, int $sum, int $k): int { 45 | return int32((($z >> 5 & 0x7FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k ^ $z)); 46 | } 47 | 48 | /** Cipher 49 | * @param string $str plain-text password 50 | * @return string binary cipher 51 | */ 52 | function encrypt_string(string $str, string $key): string { 53 | if ($str == "") { 54 | return ""; 55 | } 56 | $key = array_values(unpack("V*", pack("H*", md5($key)))); 57 | $v = str2long($str, true); 58 | $n = count($v) - 1; 59 | $z = $v[$n]; 60 | $y = $v[0]; 61 | $q = floor(6 + 52 / ($n + 1)); 62 | $sum = 0; 63 | while ($q-- > 0) { 64 | $sum = int32($sum + 0x9E3779B9); 65 | $e = $sum >> 2 & 3; 66 | for ($p=0; $p < $n; $p++) { 67 | $y = $v[$p + 1]; 68 | $mx = xxtea_mx($z, $y, $sum, $key[$p & 3 ^ $e]); 69 | $z = int32($v[$p] + $mx); 70 | $v[$p] = $z; 71 | } 72 | $y = $v[0]; 73 | $mx = xxtea_mx($z, $y, $sum, $key[$p & 3 ^ $e]); 74 | $z = int32($v[$n] + $mx); 75 | $v[$n] = $z; 76 | } 77 | return long2str($v, false); 78 | } 79 | 80 | /** Decipher 81 | * @param string $str binary cipher 82 | * @return string|false plain-text password 83 | */ 84 | function decrypt_string(string $str, string $key) { 85 | if ($str == "") { 86 | return ""; 87 | } 88 | if (!$key) { 89 | return false; 90 | } 91 | $key = array_values(unpack("V*", pack("H*", md5($key)))); 92 | $v = str2long($str, false); 93 | $n = count($v) - 1; 94 | $z = $v[$n]; 95 | $y = $v[0]; 96 | $q = floor(6 + 52 / ($n + 1)); 97 | $sum = int32($q * 0x9E3779B9); 98 | while ($sum) { 99 | $e = $sum >> 2 & 3; 100 | for ($p=$n; $p > 0; $p--) { 101 | $z = $v[$p - 1]; 102 | $mx = xxtea_mx($z, $y, $sum, $key[$p & 3 ^ $e]); 103 | $y = int32($v[$p] - $mx); 104 | $v[$p] = $y; 105 | } 106 | $z = $v[$n]; 107 | $mx = xxtea_mx($z, $y, $sum, $key[$p & 3 ^ $e]); 108 | $y = int32($v[0] - $mx); 109 | $v[0] = $y; 110 | $sum = int32($sum - 0x9E3779B9); 111 | } 112 | return long2str($v, true); 113 | } 114 | -------------------------------------------------------------------------------- /adminer/index.php: -------------------------------------------------------------------------------- 1 | array('Too many unsuccessful logins, try again in %d minute.', 'Too many unsuccessful logins, try again in %d minutes.'), 6 | 'Query executed OK, %d row(s) affected.' => array('Query executed OK, %d row affected.', 'Query executed OK, %d rows affected.'), 7 | '%d byte(s)' => array('%d byte', '%d bytes'), 8 | 'Routine has been called, %d row(s) affected.' => array('Routine has been called, %d row affected.', 'Routine has been called, %d rows affected.'), 9 | '%d process(es) have been killed.' => array('%d process has been killed.', '%d processes have been killed.'), 10 | '%d / ' => '%d / ', 11 | '%d row(s)' => array('%d row', '%d rows'), 12 | '%d item(s) have been affected.' => array('%d item has been affected.', '%d items have been affected.'), 13 | '%d row(s) have been imported.' => array('%d row has been imported.', '%d rows have been imported.'), 14 | '%d in total' => '%d in total', 15 | '%d query(s) executed OK.' => array('%d query executed OK.', '%d queries executed OK.'), 16 | ); 17 | 18 | // run `php ../../lang.php en` to update this file 19 | -------------------------------------------------------------------------------- /adminer/privileges.inc.php: -------------------------------------------------------------------------------- 1 | ' . lang('Create user') . ""; 7 | 8 | $result = connection()->query("SELECT User, Host FROM mysql." . (DB == "" ? "user" : "db WHERE " . q(DB) . " LIKE Db") . " ORDER BY Host, User"); 9 | $grant = $result; 10 | if (!$result) { 11 | // list logged user, information_schema.USER_PRIVILEGES lists just the current user too 12 | $result = connection()->query("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', 1) AS User, SUBSTRING_INDEX(CURRENT_USER, '@', -1) AS Host"); 13 | } 14 | 15 | echo "

\n"; 16 | hidden_fields_get(); 17 | echo input_hidden("db", DB); 18 | echo ($grant ? "" : input_hidden("grant")); 19 | echo "\n"; 20 | echo "\n"; 21 | 22 | while ($row = $result->fetch_assoc()) { 23 | echo '
" . lang('Username') . "" . lang('Server') . "
' . h($row["User"]) . "" . h($row["Host"]) . '' . lang('Edit') . "\n"; 24 | } 25 | 26 | if (!$grant || DB != "") { 27 | echo "
\n"; 28 | } 29 | 30 | echo "
\n"; 31 | echo "

\n"; 32 | -------------------------------------------------------------------------------- /adminer/procedure.inc.php: -------------------------------------------------------------------------------- 1 | $field) { 13 | if ($field["field"] == "") { 14 | unset($row["fields"][$key]); 15 | } 16 | } 17 | drop_create( 18 | "DROP $routine " . routine_id($PROCEDURE, $orig), 19 | create_routine($routine, $row), 20 | "DROP $routine " . routine_id($row["name"], $row), 21 | create_routine($routine, array("name" => $temp_name) + $row), 22 | "DROP $routine " . routine_id($temp_name, $row), 23 | substr(ME, 0, -1), 24 | lang('Routine has been dropped.'), 25 | lang('Routine has been altered.'), 26 | lang('Routine has been created.'), 27 | $PROCEDURE, 28 | $row["name"] 29 | ); 30 | } 31 | 32 | page_header(($PROCEDURE != "" ? (isset($_GET["function"]) ? lang('Alter function') : lang('Alter procedure')) . ": " . h($PROCEDURE) : (isset($_GET["function"]) ? lang('Create function') : lang('Create procedure'))), $error); 33 | 34 | if (!$_POST) { 35 | if ($PROCEDURE == "") { 36 | $row["language"] = "sql"; 37 | } else { 38 | $row = routine($_GET["procedure"], $routine); 39 | $row["name"] = $PROCEDURE; 40 | } 41 | } 42 | 43 | $collations = get_vals("SHOW CHARACTER SET"); 44 | sort($collations); 45 | $routine_languages = routine_languages(); 46 | echo ($collations ? "" . optionlist($collations) . "" : ""); 47 | ?> 48 | 49 |
50 |

: " data-maxlength="64" autocapitalize="off"> 51 | " . lang('Language') . ": " . html_select("language", $routine_languages, $row["language"]) . "\n" : ""); ?> 52 | 53 |

54 | 55 |
" . lang('Return type'); 59 | edit_type("returns", (array) $row["returns"], $collations, array(), (JUSH == "pgsql" ? array("void", "trigger") : array())); 60 | } 61 | ?> 62 |
63 | 64 |
65 |

66 |

67 | 68 | 69 | 70 | 71 | 72 |

73 | -------------------------------------------------------------------------------- /adminer/processlist.inc.php: -------------------------------------------------------------------------------- 1 | killProcess($val)) { 9 | $killed++; 10 | } 11 | } 12 | queries_redirect(ME . "processlist=", lang('%d process(es) have been killed.', $killed), $killed || !$_POST["kill"]); 13 | } 14 | } 15 | 16 | page_header(lang('Process list'), $error); 17 | ?> 18 | 19 |
20 |
21 | 22 | processList() as $i => $row) { 27 | if (!$i) { 28 | echo "" . (support("kill") ? "\n"; 37 | } 38 | echo "" . (support("kill") ? "
" : ""); 29 | foreach ($row as $key => $val) { 30 | echo "$key" . doc_link(array( 31 | 'sql' => "show-processlist.html#processlist_" . strtolower($key), 32 | 'pgsql' => "monitoring-stats.html#PG-STAT-ACTIVITY-VIEW", 33 | 'oracle' => "REFRN30223", 34 | )); 35 | } 36 | echo "
" . checkbox("kill[]", $row[JUSH == "sql" ? "Id" : "pid"], 0) : ""); 39 | foreach ($row as $key => $val) { 40 | echo "" . ( 41 | (JUSH == "sql" && $key == "Info" && preg_match("~Query|Killed~", $row["Command"]) && $val != "") || 42 | (JUSH == "pgsql" && $key == "current_query" && $val != "") || 43 | (JUSH == "oracle" && $key == "sql_text" && $val != "") 44 | ? "" . shorten_utf8($val, 100, "") . ' ' . lang('Clone') . '' 45 | : h($val) 46 | ); 47 | } 48 | echo "\n"; 49 | } 50 | ?> 51 |
52 |
53 |

54 | \n"; 58 | } 59 | echo input_token(); 60 | ?> 61 |

62 | 63 | -------------------------------------------------------------------------------- /adminer/scheme.inc.php: -------------------------------------------------------------------------------- 1 | 29 | 30 |
31 |

" autocapitalize="off"> 32 | 33 | " . confirm(lang('Drop %s?', $_GET["ns"])) . "\n"; 36 | } 37 | echo input_token(); 38 | ?> 39 |

40 | -------------------------------------------------------------------------------- /adminer/script.inc.php: -------------------------------------------------------------------------------- 1 | 0, "Index_length" => 0, "Data_free" => 0); 8 | foreach (table_status() as $name => $table_status) { 9 | json_row("Comment-$name", h($table_status["Comment"])); 10 | if (!is_view($table_status)) { 11 | foreach (array("Engine", "Collation") as $key) { 12 | json_row("$key-$name", h($table_status[$key])); 13 | } 14 | foreach ($sums + array("Auto_increment" => 0, "Rows" => 0) as $key => $val) { 15 | if ($table_status[$key] != "") { 16 | $val = format_number($table_status[$key]); 17 | if ($val >= 0) { 18 | json_row("$key-$name", ($key == "Rows" && $val && $table_status["Engine"] == (JUSH == "pgsql" ? "table" : "InnoDB") 19 | ? "~ $val" 20 | : $val 21 | )); 22 | } 23 | if (isset($sums[$key])) { 24 | // ignore innodb_file_per_table because it is not active for tables created before it was enabled 25 | $sums[$key] += ($table_status["Engine"] != "InnoDB" || $key != "Data_free" ? $table_status[$key] : 0); 26 | } 27 | } elseif (array_key_exists($key, $table_status)) { 28 | json_row("$key-$name", "?"); 29 | } 30 | } 31 | } 32 | } 33 | foreach ($sums as $key => $val) { 34 | json_row("sum-$key", format_number($val)); 35 | } 36 | json_row(""); 37 | 38 | } elseif ($_GET["script"] == "kill") { 39 | connection()->query("KILL " . number($_POST["kill"])); 40 | 41 | } else { // connect 42 | foreach (count_tables(adminer()->databases()) as $db => $val) { 43 | json_row("tables-$db", $val); 44 | json_row("size-$db", db_size($db)); 45 | } 46 | json_row(""); 47 | } 48 | 49 | exit; // don't print footer 50 | -------------------------------------------------------------------------------- /adminer/sequence.inc.php: -------------------------------------------------------------------------------- 1 | 27 | 28 |
29 |

" autocapitalize="off"> 30 | 31 | " . confirm(lang('Drop %s?', $SEQUENCE)) . "\n"; 34 | } 35 | echo input_token(); 36 | ?> 37 |

38 | -------------------------------------------------------------------------------- /adminer/sqlite.php: -------------------------------------------------------------------------------- 1 | $TABLE . "_bi"); 8 | 9 | if ($_POST) { 10 | if (!$error && in_array($_POST["Timing"], $trigger_options["Timing"]) && in_array($_POST["Event"], $trigger_options["Event"]) && in_array($_POST["Type"], $trigger_options["Type"])) { 11 | // don't use drop_create() because there may not be more triggers for the same action 12 | $on = " ON " . table($TABLE); 13 | $drop = "DROP TRIGGER " . idf_escape($name) . (JUSH == "pgsql" ? $on : ""); 14 | $location = ME . "table=" . urlencode($TABLE); 15 | if ($_POST["drop"]) { 16 | query_redirect($drop, $location, lang('Trigger has been dropped.')); 17 | } else { 18 | if ($name != "") { 19 | queries($drop); 20 | } 21 | queries_redirect( 22 | $location, 23 | ($name != "" ? lang('Trigger has been altered.') : lang('Trigger has been created.')), 24 | queries(create_trigger($on, $_POST)) 25 | ); 26 | if ($name != "") { 27 | queries(create_trigger($on, $row + array("Type" => reset($trigger_options["Type"])))); 28 | } 29 | } 30 | } 31 | $row = $_POST; 32 | } 33 | 34 | page_header(($name != "" ? lang('Alter trigger') . ": " . h($name) : lang('Create trigger')), $error, array("table" => $TABLE)); 35 | ?> 36 | 37 |
38 | 39 |
40 |
41 | ": ""); ?> 42 |
43 |
44 |

: " data-maxlength="64" autocapitalize="off"> 45 | 46 |

47 |

48 | 49 | 50 | 51 | 52 | 53 |

54 | -------------------------------------------------------------------------------- /adminer/type.inc.php: -------------------------------------------------------------------------------- 1 | 22 | 23 |
24 |

25 | types(); 28 | $enums = type_values($types[$TYPE]); 29 | if ($enums) { 30 | echo "ENUM (" . h($enums) . ")\n

"; 31 | } 32 | echo "" . confirm(lang('Drop %s?', $TYPE)) . "\n"; 33 | } else { 34 | echo lang('Name') . ": \n"; 35 | echo doc_link(array( 36 | 'pgsql' => "datatype-enum.html", 37 | ), "?"); 38 | textarea("as", $row["as"]); 39 | echo "

\n"; 40 | } 41 | echo input_token(); 42 | ?> 43 |

44 | -------------------------------------------------------------------------------- /adminer/variables.inc.php: -------------------------------------------------------------------------------- 1 | " . lang('No rows.') . "\n"; 10 | } else { 11 | echo "\n"; 12 | foreach ($variables as $row) { 13 | echo ""; 14 | $key = array_shift($row); 15 | echo "
" . h($key) . ""; 16 | foreach ($row as $val) { 17 | echo "" . nl_br(h($val)); 18 | } 19 | } 20 | echo "
\n"; 21 | } 22 | -------------------------------------------------------------------------------- /adminer/view.inc.php: -------------------------------------------------------------------------------- 1 | $TABLE), h($TABLE)); 50 | ?> 51 | 52 |
53 |

: " data-maxlength="64" autocapitalize="off"> 54 | 55 |

56 |

57 | 58 | 59 | 60 | 61 | 62 |

63 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vrana/adminer", 3 | "description": "Database management in a single PHP file.", 4 | "homepage": "https://www.adminer.org/", 5 | "keywords": [ 6 | "database" 7 | ], 8 | "support": { 9 | "issues": "https://github.com/vrana/adminer/issues", 10 | "forum": "https://github.com/vrana/adminer/discussions", 11 | "source": "https://github.com/vrana/adminer/" 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Jakub Vrána", 16 | "homepage": "https://www.vrana.cz/" 17 | } 18 | ], 19 | "autoload": { 20 | "exclude-from-classmap": [ 21 | "adminer/drivers/", 22 | "plugins/drivers/" 23 | ], 24 | "classmap": [ 25 | "plugins/" 26 | ] 27 | }, 28 | "license": [ 29 | "Apache-2.0", 30 | "GPL-2.0-only" 31 | ], 32 | "require": { 33 | "php": ">=7.4" 34 | }, 35 | "scripts": { 36 | "clean": "rm -f adminer*.php editor*.php", 37 | "compile": "@php compile.php" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /coverage.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Coverage 6 | 7 | 8 | 9 | ]+)~', $s, $matches); 16 | foreach ($matches[1] as $val) { 17 | if ($val[0] == "/") { 18 | array_pop($return); 19 | } elseif (substr($val, -1) != "/") { 20 | $return[] = $val; 21 | } 22 | } 23 | return $return; 24 | } 25 | 26 | $coverage_filename = sys_get_temp_dir() . "/adminer.coverage"; 27 | if (!extension_loaded("xdebug")) { 28 | echo "

Xdebug has to be enabled.\n"; 29 | } elseif ($_GET["coverage"] === "0") { 30 | file_put_contents($coverage_filename, serialize(array())); 31 | echo "

Coverage started.\n"; 32 | } elseif (preg_match('~^(adminer|editor)/(include/|drivers/)?[-_.a-z0-9]+$~i', $_GET["coverage"])) { 33 | // highlight single file 34 | $filename = $_GET["coverage"]; 35 | $coverage = (file_exists($coverage_filename) ? unserialize(file_get_contents($coverage_filename)) : array()); 36 | $file = explode("\n", substr(highlight_file($filename, true), 5, -6)); // unwrap


37 | 	$prev_color = null;
38 | 	$s = "";
39 | 	echo "
";
40 | 	for ($l=0; $l <= count($file); $l++) {
41 | 		$line = $file[$l];
42 | 		$color = "#C0FFC0"; // tested
43 | 		switch ($coverage[realpath($filename)][$l+1] ?? null) {
44 | 			case -1: // untested
45 | 				$color = "#FFC0C0";
46 | 				break;
47 | 			case -2: // dead code
48 | 				$color = "Silver";
49 | 				break;
50 | 			case null: // not executable
51 | 				$color = "";
52 | 				break;
53 | 		}
54 | 		if ($prev_color === null) {
55 | 			$prev_color = $color;
56 | 		}
57 | 		if ($prev_color != $color || $line === null) {
58 | 			echo "$s";
59 | 			$open_tags = xhtml_open_tags($s);
60 | 			foreach (array_reverse($open_tags) as $tag) {
61 | 				echo "";
62 | 			}
63 | 			echo "";
64 | 			$s = ($open_tags ? "<" . implode("><", $open_tags) . ">" : "");
65 | 			$prev_color = $color;
66 | 		}
67 | 		$s .= "$line\n";
68 | 	}
69 | 	echo "
"; 70 | } else { 71 | if (file_exists($coverage_filename)) { 72 | // display list of files 73 | $coverage = unserialize(file_get_contents($coverage_filename)); 74 | echo "\n"; 75 | foreach (array_merge(glob("adminer/*.php"), glob("adminer/drivers/*.php"), glob("adminer/include/*.php"), glob("editor/*.php"), glob("editor/include/*.php")) as $filename) { 76 | $cov = $coverage[realpath($filename)]; 77 | $ratio = 0; 78 | if (is_array($cov)) { 79 | $values = array_count_values($cov); 80 | $ratio = round(100 - 100 * $values[-1] / (count($cov) - $values[-2])); 81 | } 82 | echo "
$ratio%$filename\n"; 83 | } 84 | echo "
\n"; 85 | } 86 | echo "

Start new coverage\n"; 87 | } 88 | -------------------------------------------------------------------------------- /designs/README.md: -------------------------------------------------------------------------------- 1 | Copy `adminer.css` alongside Adminer PHP script to use an alternative design. 2 | If the design supports dark mode then it should be named `adminer-dark.css`. 3 | 4 | Gallery of designs (including external): https://www.adminer.org/#extras 5 | 6 | See also: [plugins/designs.php](/plugins/designs.php) 7 | -------------------------------------------------------------------------------- /designs/adminer-dark/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/screenshots/dark.png) 3 | -------------------------------------------------------------------------------- /designs/adminer-dark/adminer-dark.css: -------------------------------------------------------------------------------- 1 | /* Empty file named adminer-dark.css causes Adminer to switch to default dark mode. */ 2 | -------------------------------------------------------------------------------- /designs/brade/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/brade/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/brade/adminer.css: -------------------------------------------------------------------------------- 1 | /* CSS by Brade - www.bradezone.com */ 2 | html { 3 | --fg: #333; 4 | } 5 | 6 | *{margin:0;padding:0} 7 | body{font:13px/18px Helvetica,Arial,sans-serif;background:#fff;color:#333} 8 | /* generic */ 9 | a{color:#06c;text-decoration:none;border-bottom:1px dotted} 10 | a:hover,a:link:hover{border-bottom:1px solid #06c;background:#06c;color:#fff} 11 | p{padding-bottom:4px;margin-bottom:4px} 12 | h1{font-size:18px;font-weight:bold;padding-bottom:0px;height:40px;padding:0 0 8px 0;color:#666;border:0} 13 | h2{font:32px Georgia,serif;padding:10px 0 8px;margin:0;background:transparent;border:0;color:#333} 14 | h3{font-size:18px;font-weight:bold;padding:4px 0;margin:0} 15 | form#form{overflow:hidden} 16 | fieldset{float:left;min-height:48px;padding:0 4px 4px 4px;border:1px solid #ccc;margin-bottom:8px;margin-right:4px} 17 | fieldset div{margin-top:4px} 18 | input,select,textarea{font:13px Helvetica,Arial,sans-serif;color:#555;border:1px solid #999;padding:3px} 19 | input[type=submit]{background:#ccc;padding:2px;cursor:pointer;color:#333} 20 | input[type=submit]:hover{background:#bbb} 21 | input[type=image],input[type=checkbox]{border:0;padding:0} 22 | label input[type=checkbox],td input[type=radio],td span select{margin-right:4px} 23 | select{border:1px solid #999;padding:2px} 24 | fieldset select{margin-right:4px} 25 | option{padding:0 5px} 26 | optgroup{font-size:11px} 27 | code{background:#eee;padding:2px 4px;font:16px/20px Courier,monospace} 28 | code a:hover{background:transparent} 29 | table{margin:4px 0 8px;border:1px solid #ccc;font-size:inherit} 30 | tbody tr:hover td,tbody tr:hover th{background:#eee} 31 | thead { top: 40px; } 32 | thead tr:hover td,thead tr:hover th{background:#ddd} 33 | th,td{text-align:left;padding:2px 4px;vertical-align:top;font-weight:normal;border:1px dotted #ccc;border-width:0 0 0 1px; 34 | margin:0;background:inherit} 35 | thead th,thead td{white-space:nowrap;font-weight:bold;background:#ddd;border-color:#ddd} 36 | th:first-child,td:first-child{border-color:transparent;white-space:nowrap} 37 | td[align=right]{text-align:right} 38 | table code{font-size:13px;line-height:18px} 39 | .footer fieldset{float:none;} 40 | .hidden{display:none} 41 | .error,.message{padding:0;background:transparent;font-weight:bold} 42 | .error{color:#c00} 43 | .message{color:#090} 44 | /* specific */ 45 | #content{margin:0 0 0 320px;padding:50px 20px 40px 0;height:100%} 46 | #content:after{content:'.';clear:both;height:0;overflow:hidden;display:block} 47 | #lang{background:#333;color:#fff;position:fixed;top:0;left:0;width:100%;padding:0 20px 0 40px;line-height:40px;height:40px} 48 | #lang select{border-color:#333} 49 | #menu{background:#eee;position:fixed;top:60px;bottom:20px;overflow:auto;left:20px;width:240px;padding:10px 15px; 50 | border:5px solid #ccc;margin:0} 51 | #menu a{color:#333;margin-right:4px} 52 | #menu a:hover{background:#333;color:#fff;border-color:#333} 53 | #menu a.h1,#menu a.h1:hover{display:block;height:0;width:175px;padding:40px 0 0 0;overflow:hidden;float:left;border:0;margin:0; 54 | outline:0;background:url(//www.bradezone.com/random/adminer_logo.gif) no-repeat;line-height:32px} 55 | #menu p,#logins,#tables{border:0;padding:0 0 4px 0;margin:0 0 4px 0} 56 | #breadcrumb{background:#333;color:#fff;position:fixed;top:0;left:320px;line-height:40px;padding:0;z-index:1;margin:0} 57 | #breadcrumb a{color:#ff9} 58 | #breadcrumb a:hover{background:transparent;color:#ff9;border-color:#ff9} 59 | #schema .table{padding:4px 8px;background:#f3f3f3} 60 | .tables-filter{padding:0;margin:10px 0;} 61 | /* IE hacks */ 62 | *+html th:first-child,*+html td:first-child{border-color:inherit;white-space:inherit} 63 | * html #lang,* html #menu,* html #breadcrumb{position:absolute} 64 | * html #lang{padding-top:10px;height:30px} 65 | * html form#form{height:100%} 66 | #logins a,#tables a{background: none} 67 | .logout{color:#fff;background-color:#333;box-shadow:0 0 5px 5px #333;z-index:1} 68 | #logout{color:#333;text-decoration:none;border-bottom:1px dotted} 69 | #logout:hover{border-color:#333;background:#333;color:#fff} 70 | .js .column{background:#ddd} 71 | -------------------------------------------------------------------------------- /designs/bueltge/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/bueltge/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/dracula/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/dracula/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/esterka/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/esterka/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/esterka/adminer.css: -------------------------------------------------------------------------------- 1 | * { 2 | font: 11px/1.25 Verdana, 'Geneva CE', lucida, sans-serif; 3 | color:#333333; 4 | margin:0px; 5 | padding:0px; 6 | } 7 | 8 | a,a:visited { 9 | color:#0033ff; 10 | text-decoration:none; 11 | padding:3px 1px; 12 | } 13 | 14 | #content table thead span, #content table thead a { 15 | font-weight:bold; 16 | color:black; 17 | } 18 | 19 | #content table thead a:hover { 20 | background:none; 21 | text-decoration:underline; 22 | color:black; 23 | } 24 | 25 | a:hover { 26 | color:white; 27 | background:#0033ff; 28 | } 29 | 30 | h1 { 31 | font-size:1.5em; 32 | line-height: 2em; 33 | font-weight:bold; 34 | background:white; 35 | color:#1e5eb6; 36 | border-bottom:1px solid #f4f4f4; 37 | 38 | padding:20px; 39 | margin:0px; 40 | } 41 | 42 | #menu h1 { 43 | padding:0px 0px 5px 20px; 44 | background:none; 45 | } 46 | 47 | h2,h3 { 48 | font-size:1.5em; 49 | font-weight:normal; 50 | background:white; 51 | color:#A0522D; 52 | border-bottom:1px solid #f4f4f4; 53 | padding:5px 0px; 54 | margin:0px; 55 | } 56 | 57 | fieldset { 58 | padding:5px; 59 | border:1px solid #d0cdc4; 60 | background:#fcfaf5; 61 | } 62 | 63 | input,select,textarea { 64 | border:1px solid #e5e5e5; 65 | margin:1px; 66 | padding:3px; 67 | } 68 | 69 | input[type=submit] { 70 | color:white; 71 | background:#A0522D; 72 | padding:3px 10px; 73 | cursor:pointer; 74 | border:0px solid; 75 | } 76 | 77 | input[type=submit]:hover{ 78 | background:blue; 79 | } 80 | 81 | input[type=checkbox]{ 82 | margin-right:5px; 83 | } 84 | 85 | input[type=image] { 86 | border:1px solid #d0cdc4; 87 | } 88 | 89 | input[type=checkbox],input[type=radio]{ 90 | border:1px solid #e5e5e5; 91 | padding:2px 5px; 92 | } 93 | 94 | code{ 95 | background:#f0ffe1; 96 | border:1px dashed #d5f1b9; 97 | padding:2px 4px; 98 | font-family:"Courier New"; 99 | } 100 | code a:hover{background:transparent} 101 | 102 | table{ 103 | margin:10px 0px; 104 | border:1px solid #d0cdc4; 105 | border-collapse:collapse; 106 | } 107 | 108 | tbody tr:hover td,tbody tr:hover th{ 109 | background:#edf4ff 110 | } 111 | 112 | thead{ 113 | top: 44px; 114 | } 115 | 116 | thead th, thead td { 117 | text-align:center; 118 | vertical-align:middle; 119 | font-weight:bold; 120 | white-space:nowrap; 121 | background:#f2eee1; 122 | color:#808080; 123 | } 124 | 125 | th,td{ 126 | border:1px solid #d0cdc4; 127 | padding:1px 4px; 128 | vertical-align:middle; 129 | } 130 | 131 | th a { 132 | font-weight:bold; 133 | padding-bottom:0px; 134 | } 135 | 136 | th { 137 | background:white; 138 | } 139 | 140 | .odds tbody tr:nth-child(2n) { 141 | background:#fcfaf5; 142 | } 143 | 144 | #content tbody tr.checked td, .odds tbody tr.checked:nth-child(2n) td { 145 | background:#fbe2e2; 146 | color:red; 147 | } 148 | 149 | .hidden{ 150 | display:none 151 | } 152 | 153 | .error,.message{ 154 | padding:0px; 155 | background:transparent; 156 | font-weight:bold 157 | } 158 | 159 | .error{ 160 | color:#c00 161 | } 162 | 163 | .message{ 164 | color:#090 165 | } 166 | 167 | #content{ 168 | margin:0px 0px 0px 255px; 169 | padding:50px 20px 40px 0px; 170 | height:100%; 171 | } 172 | 173 | #lang { 174 | background:#f2eee1; 175 | color:#808080; 176 | position:fixed; 177 | top:0px; 178 | left:0px; 179 | width:100%; 180 | padding:10px 20px; 181 | z-index:1; 182 | } 183 | 184 | #breadcrumb { 185 | position:fixed; 186 | top:0px; 187 | left:260px; 188 | background:#f2eee1; 189 | z-index:2; 190 | width:100%; 191 | padding:10px; 192 | } 193 | 194 | #menu { 195 | background:#fcfaf5; 196 | position:fixed; 197 | top:-10px; 198 | padding:0px; 199 | padding-top:10px; 200 | bottom:0px; 201 | overflow:auto; 202 | left:0px; 203 | width:240px; 204 | border-right:5px solid #f2eee1; 205 | } 206 | 207 | #schema .table { 208 | padding:5px; 209 | background:#fcfaf5; 210 | border:1px solid #d0cdc4; 211 | } 212 | 213 | #schema .table b { 214 | color:#0033ff; 215 | font-weight:bold; 216 | text-decoration:underline; 217 | } 218 | 219 | #schema .table b:hover { 220 | color:white; 221 | } 222 | 223 | #logout { 224 | color:#fce2e2; 225 | background:#d73e3e; 226 | } 227 | 228 | #logout:hover { 229 | background:#ea0202; 230 | } 231 | 232 | #logins a, #tables a { 233 | background:none; 234 | } 235 | 236 | #logins a:hover, #tables a:hover { 237 | background:#A0522D; 238 | color:white; 239 | } 240 | 241 | .logout { 242 | z-index: 2; 243 | background-color: #f2eee1; 244 | box-shadow: 0 0 5px 5px #f2eee1; 245 | } 246 | 247 | .js .column { 248 | background:#f2eee1; 249 | } 250 | 251 | #content table thead a.text:hover { 252 | text-decoration:none; 253 | } 254 | 255 | #version, .version { 256 | font-size:50%; 257 | } 258 | 259 | #h1:hover { 260 | color:white; 261 | } 262 | -------------------------------------------------------------------------------- /designs/flat/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/flat/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/flat/adminer.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Adminer "flat" theme by Israel Viana 3 | * 4 | * Color palette from https://kuler.adobe.com/Copy-of-Flat-UI-color-theme-3785174/ 5 | * Navy: 2c3e50 6 | * Red: e74c3c 7 | * Gray: ecf0f1 8 | * Light blue: 3498db 9 | * Blue: 2980b9 10 | */ 11 | 12 | /* 13 | * Basic tags 14 | */ 15 | 16 | a { 17 | color: #2980b9; 18 | } 19 | 20 | a:visited { 21 | color: #3498db 22 | } 23 | 24 | a:link:hover, a:visited:hover { 25 | color: #e74c3c; 26 | } 27 | 28 | h1 { 29 | border-bottom: 1px solid #e74c3c; 30 | background: #ecf0f1; 31 | } 32 | 33 | h2 { 34 | border-bottom: 1px solid #e74c3c; 35 | background: #ecf0f1; 36 | } 37 | 38 | /* 39 | * Tables 40 | */ 41 | 42 | table { 43 | border-top: 0; 44 | border-left: 1px solid silver; 45 | } 46 | 47 | td, th { 48 | border-right: 1px solid silver; 49 | border-bottom: 1px solid silver; 50 | padding: .3em .5em; 51 | } 52 | 53 | thead th, thead td { 54 | background: #3498db; 55 | color: white; 56 | border-right: 1px solid white; 57 | border-bottom: 1px solid white; 58 | padding: .3em .5em; 59 | } 60 | 61 | thead th a, thead td a { 62 | color: #eee; 63 | } 64 | 65 | .js span.column { 66 | background: white; 67 | } 68 | th span.column a.text { 69 | color: #2980b9; 70 | } 71 | 72 | .js .checkable .checked td, .js .checkable .checked th { 73 | background: rgba(52, 152, 219, .3); 74 | } 75 | 76 | .pages { 77 | border: none; 78 | box-shadow: -1px -1px 4px silver; 79 | } 80 | 81 | /* 82 | * Common sections 83 | */ 84 | 85 | #breadcrumb a { 86 | color: #e74c3c; 87 | } 88 | 89 | #logout { 90 | font-weight: bold; 91 | } 92 | 93 | /* 94 | * Elements 95 | */ 96 | 97 | sup { 98 | padding: 3px 7px; 99 | background: #3498db; 100 | color: white; 101 | border-radius: 2em; 102 | } 103 | 104 | code.jush-sql { 105 | display: block; 106 | padding: .4em .7em; 107 | line-height: 1.5em; 108 | } 109 | -------------------------------------------------------------------------------- /designs/galkaev/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/galkaev/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/haeckel/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/haeckel/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/hever/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/hever/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/konya/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/konya/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/lavender-light/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/lavender-light/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/lucas-sandery/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/lucas-sandery/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/mancave/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/mancave/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/mvt/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/mvt/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/nette/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/nette/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/ng9/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/ng9/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/ng9/adminer.css: -------------------------------------------------------------------------------- 1 | * { 2 | font: 13px/1.5 Verdana, 'Geneva CE', lucida, sans-serif; 3 | color:#333333; 4 | margin:0px; 5 | padding:0px; 6 | } 7 | 8 | a,a:visited { 9 | color:#006aeb; 10 | text-decoration:none; 11 | padding:3px 1px; 12 | } 13 | 14 | #content table thead span, #content table thead a { 15 | font-weight:bold; 16 | color:black; 17 | } 18 | 19 | #content table thead a:hover { 20 | background:none; 21 | text-decoration:underline; 22 | color:black; 23 | } 24 | 25 | a:hover, a:link:hover { 26 | color:white; 27 | background:#006aeb; 28 | } 29 | 30 | h1 { 31 | font-size:1.9em; 32 | font-weight:normal; 33 | background:white; 34 | color:#1e5eb6; 35 | border-bottom:1px solid #f4f4f4; 36 | 37 | padding:20px; 38 | margin:0px; 39 | } 40 | 41 | #menu h1 { 42 | padding:0px 0px 5px 20px; 43 | background:none; 44 | } 45 | 46 | h2,h3 { 47 | font-size:1.5em; 48 | font-weight:normal; 49 | background:white; 50 | color:#1e5eb6; 51 | border-bottom:1px solid #f4f4f4; 52 | 53 | padding:20px 0px; 54 | margin:0px; 55 | } 56 | 57 | fieldset { 58 | padding:5px; 59 | border:1px solid #f4f4f4; 60 | } 61 | 62 | input,select,textarea { 63 | border:1px solid #e5e5e5; 64 | margin:1px; 65 | padding:3px; 66 | } 67 | 68 | input[type=submit] { 69 | color:white; 70 | background:#3390e6; 71 | padding:3px 10px; 72 | cursor:pointer; 73 | border:0px solid; 74 | } 75 | 76 | input[type=submit]:hover{ 77 | background:blue; 78 | } 79 | 80 | input[type=checkbox]{ 81 | margin-right:5px; 82 | } 83 | 84 | input[type=image] { 85 | border:1px solid #d0cdc4; 86 | } 87 | 88 | input[type=checkbox],input[type=radio]{ 89 | border:1px solid #e5e5e5; 90 | padding:2px 5px; 91 | } 92 | 93 | code{ 94 | background:#f0ffe1; 95 | border:1px dashed #d5f1b9; 96 | padding:2px 4px; 97 | font-family:"Courier New"; 98 | } 99 | code a:hover{background:transparent} 100 | 101 | table{ 102 | margin:10px 0px; 103 | border:1px solid #d0cdc4; 104 | border-collapse:collapse; 105 | } 106 | 107 | tbody tr:hover td,tbody tr:hover th{ 108 | background:#edf4ff 109 | } 110 | 111 | thead { 112 | top: 46px; 113 | } 114 | 115 | thead th, thead td { 116 | text-align:center; 117 | vertical-align:middle; 118 | font-weight:bold; 119 | white-space:nowrap; 120 | background:#f2eee1; 121 | color:#808080; 122 | } 123 | 124 | th,td{ 125 | border:1px solid #d0cdc4; 126 | padding:3px 6px; 127 | vertical-align:top; 128 | } 129 | 130 | th a { 131 | font-weight:bold; 132 | padding-bottom:0px; 133 | } 134 | 135 | th { 136 | background:white; 137 | } 138 | 139 | .odds tbody tr:nth-child(2n) { 140 | background:#fcfaf5; 141 | } 142 | 143 | #content tbody tr.checked td, .odds tbody tr:nth-child(2n).checked td { 144 | background:#fbe2e2; 145 | color:red; 146 | } 147 | 148 | .hidden{ 149 | display:none 150 | } 151 | 152 | .error,.message{ 153 | padding:0px; 154 | background:transparent; 155 | font-weight:bold 156 | } 157 | 158 | .error{ 159 | color:#c00 160 | } 161 | 162 | .message{ 163 | color:#090 164 | } 165 | 166 | #content{ 167 | margin:0px 0px 0px 320px; 168 | padding:50px 20px 40px 0px; 169 | height:100%; 170 | } 171 | 172 | #lang { 173 | background:#f2eee1; 174 | color:#808080; 175 | position:fixed; 176 | top:0px; 177 | left:0px; 178 | width:100%; 179 | padding:10px 20px; 180 | z-index:1; 181 | } 182 | 183 | #breadcrumb { 184 | position:fixed; 185 | top:0px; 186 | left:300px; 187 | background:#f2eee1; 188 | z-index:2; 189 | width:100%; 190 | padding:10px; 191 | } 192 | 193 | #menu { 194 | background:#fcfaf5; 195 | position:fixed; 196 | top:-10px; 197 | padding:20px; 198 | padding-top:40px; 199 | bottom:0px; 200 | overflow:auto; 201 | left:0px; 202 | width:240px; 203 | border-right:5px solid #f2eee1; 204 | } 205 | 206 | #schema .table { 207 | padding:5px; 208 | background:#fcfaf5; 209 | border:1px solid #d0cdc4; 210 | } 211 | 212 | #schema .table b { 213 | color:#006aeb; 214 | font-weight:bold; 215 | text-decoration:underline; 216 | } 217 | 218 | #schema .table b:hover { 219 | color:white; 220 | } 221 | 222 | #logout { 223 | color:#fce2e2; 224 | background:#d73e3e; 225 | } 226 | 227 | #logout:hover { 228 | background:#ea0202; 229 | } 230 | 231 | #logins a, #tables a { 232 | background:none; 233 | } 234 | 235 | #logins a:hover, #tables a:hover { 236 | background:#006aeb; 237 | } 238 | 239 | .logout { 240 | z-index: 5; 241 | background-color: #f2eee1; 242 | box-shadow: 0 0 4px 4px #f2eee1; 243 | } 244 | 245 | .js .column { 246 | background:#f2eee1; 247 | } 248 | 249 | #content table thead a.text:hover { 250 | text-decoration:none; 251 | } 252 | 253 | #version, .version { 254 | font-size:50%; 255 | } 256 | 257 | #h1:hover { 258 | color:white; 259 | } 260 | -------------------------------------------------------------------------------- /designs/nicu/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/nicu/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/pappu687/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/pappu687/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/paranoiq/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/paranoiq/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/pepa-linha/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/pepa-linha/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/pokorny/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/pokorny/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/price/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/price/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/rmsoft/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/rmsoft/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/rmsoft_blue-dark/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/rmsoft_blue-dark/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/rmsoft_blue/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/rmsoft_blue/screenshot.png) 3 | -------------------------------------------------------------------------------- /designs/win98/README.md: -------------------------------------------------------------------------------- 1 | ## Screenshot 2 | ![screenshot](https://www.adminer.org/static/designs/win98/screenshot.png) 3 | -------------------------------------------------------------------------------- /editor/db.inc.php: -------------------------------------------------------------------------------- 1 | homepage()) { 7 | echo "

\n"; 8 | echo "

" . lang('Search data in tables') . ": \n"; 9 | if ($_POST["query"] != "") { 10 | search_tables(); 11 | } 12 | echo "

\n"; 13 | echo "\n"; 14 | echo script("mixin(qsl('table'), {onclick: tableClick, ondblclick: partialArg(tableClick, true)});"); 15 | echo ''; 16 | echo '\n"; 20 | 21 | foreach (table_status() as $table => $row) { 22 | $name = adminer()->tableName($row); 23 | if ($name != "") { 24 | echo '
' . script("qs('#check-all').onclick = partial(formCheck, /^tables\[/);", ""); 17 | echo '' . lang('Table'); 18 | echo '' . lang('Rows'); 19 | echo "
' . checkbox("tables[]", $table, in_array($table, (array) $_POST["tables"], true)); 25 | echo "$name"; 26 | $val = format_number($row["Rows"]); 27 | echo "" . ($row["Engine"] == "InnoDB" && $val ? "~ $val" : $val) . ""; 28 | } 29 | } 30 | 31 | echo "
\n"; 32 | echo "
\n"; 33 | echo "
\n"; 34 | echo script("tableCheck();"); 35 | adminer()->pluginsLinks(); 36 | } 37 | -------------------------------------------------------------------------------- /editor/example.php: -------------------------------------------------------------------------------- 1 | $where) { 39 | if ($where["col"] == $field["field"] && ($key >= 0 || $where["val"] != "")) { 40 | return Adminer\h($field["comment"]); 41 | } 42 | } 43 | return ""; 44 | } 45 | } 46 | 47 | return new AdminerCds; 48 | } 49 | 50 | include "./index.php"; 51 | -------------------------------------------------------------------------------- /editor/include/connect.inc.php: -------------------------------------------------------------------------------- 1 | select_db(adminer()->database()); 5 | -------------------------------------------------------------------------------- /editor/include/editing.inc.php: -------------------------------------------------------------------------------- 1 | , type?:list, name?:list, tmp_name?:list} $files 16 | */ 17 | function send_mail(string $email, string $subject, string $message, string $from = "", array $files = array()): bool { 18 | $eol = PHP_EOL; 19 | $message = str_replace("\n", $eol, wordwrap(str_replace("\r", "", "$message\n"))); 20 | $boundary = uniqid("boundary"); 21 | $attachments = ""; 22 | foreach ((array) $files["error"] as $key => $val) { 23 | if (!$val) { 24 | $attachments .= "--$boundary$eol" 25 | . "Content-Type: " . str_replace("\n", "", $files["type"][$key]) . $eol 26 | . "Content-Disposition: attachment; filename=\"" . preg_replace('~["\n]~', '', $files["name"][$key]) . "\"$eol" 27 | . "Content-Transfer-Encoding: base64$eol$eol" 28 | . chunk_split(base64_encode(file_get_contents($files["tmp_name"][$key])), 76, $eol) . $eol 29 | ; 30 | } 31 | } 32 | $beginning = ""; 33 | $headers = "Content-Type: text/plain; charset=utf-8$eol" . "Content-Transfer-Encoding: 8bit"; 34 | if ($attachments) { 35 | $attachments .= "--$boundary--$eol"; 36 | $beginning = "--$boundary$eol$headers$eol$eol"; 37 | $headers = "Content-Type: multipart/mixed; boundary=\"$boundary\""; 38 | } 39 | $headers .= $eol . "MIME-Version: 1.0$eol" . "X-Mailer: Adminer Editor" 40 | . ($from ? $eol . "From: " . str_replace("\n", "", $from) : "") //! should escape display name 41 | ; 42 | return mail($email, email_header($subject), $beginning . $message . $attachments, $headers); 43 | } 44 | 45 | /** Check whether the column looks like boolean 46 | * @param Field $field single field returned from fields() 47 | */ 48 | function like_bool(array $field): bool { 49 | return preg_match("~bool|(tinyint|bit)\\(1\\)~", $field["full_type"]); 50 | } 51 | -------------------------------------------------------------------------------- /editor/index.php: -------------------------------------------------------------------------------- 1 | query("KILL " . number($_POST["kill"])); 6 | 7 | } elseif (list($table, $id, $name) = adminer()->_foreignColumn(column_foreign_keys($_GET["source"]), $_GET["field"])) { // complete 8 | $limit = 11; 9 | $result = connection()->query("SELECT $id, $name FROM " . table($table) . " WHERE " . (preg_match('~^[0-9]+$~', $_GET["value"]) ? "$id = $_GET[value] OR " : "") . "$name LIKE " . q("$_GET[value]%") . " ORDER BY 2 LIMIT $limit"); 10 | for ($i=1; ($row = $result->fetch_row()) && $i < $limit; $i++) { 11 | echo "" . h($row[1]) . "
\n"; 12 | } 13 | if ($row) { 14 | echo "...\n"; 15 | } 16 | } 17 | 18 | exit; // don't print footer 19 | -------------------------------------------------------------------------------- /editor/sqlite.php: -------------------------------------------------------------------------------- 1 | { 29 | if (xmlhttp.status && field.orig == field.value) { // ignore old responses 30 | field.nextSibling.innerHTML = xmlhttp.responseText; 31 | field.nextSibling.style.display = ''; 32 | const a = field.nextSibling.firstChild; 33 | if (a && a.firstChild.data == field.value) { 34 | field.previousSibling.value = decodeURIComponent(a.href.replace(/.*=/, '')); 35 | a.classList.add('active'); 36 | } 37 | } 38 | }); 39 | } 40 | 41 | /** Select typeahead value 42 | * @param MouseEvent 43 | * @return boolean false for success 44 | * @this HTMLDivElement 45 | */ 46 | function whisperClick(event) { 47 | const field = this.previousSibling; 48 | const el = event.target; 49 | if (isTag(el, 'a') && !(event.button || event.shiftKey || event.altKey || isCtrl(event))) { 50 | field.value = el.firstChild.data; 51 | field.previousSibling.value = decodeURIComponent(el.href.replace(/.*=/, '')); 52 | field.nextSibling.style.display = 'none'; 53 | return false; 54 | } 55 | } 56 | 57 | /** Add new attachment field 58 | * @this HTMLInputElement 59 | */ 60 | function emailFileChange() { 61 | const el = this.cloneNode(true); 62 | this.onchange = () => { }; 63 | el.value = ''; 64 | this.parentNode.appendChild(el); 65 | } 66 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // prepend adminer/include/functions.js to adminer/include/editing.js and editor/include/editing.js, then delete 2 | 3 | import { globalIgnores } from "eslint/config"; 4 | import js from "@eslint/js"; 5 | import globals from "globals"; 6 | 7 | export default [ 8 | globalIgnores(["externals/"]), 9 | js.configs.recommended, 10 | { 11 | languageOptions: { 12 | globals: { 13 | ...globals.browser, 14 | jush: false, jushLinks: false, 15 | offlineMessage: false, thousandsSeparator: false, // include/design.inc.php 16 | indexColumns: false, // select.inc.php 17 | tablePos: false, em: false, // schema.inc.php 18 | } 19 | }, 20 | rules: { 21 | "no-var": "error", 22 | "prefer-const": "error", 23 | "no-unused-vars": "off", //! we want this only on global level 24 | }, 25 | }, 26 | ]; 27 | -------------------------------------------------------------------------------- /lang.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | ]lang\\(('(?:[^\\\\']+|\\\\.)*')([),])~", $file, $matches)) { // lang() always uses apostrophes 18 | $messages_all += array_combine($matches[1], $matches[2]); 19 | } 20 | } 21 | 22 | foreach (glob(__DIR__ . "/adminer/lang/" . ($_SESSION["lang"] ?: "*") . ".inc.php") as $filename) { 23 | $lang = basename($filename, ".inc.php"); 24 | update_translations($lang, $messages_all, $filename, '~(\$translations = array\(\n)(.*\n)(?=\);)~sU'); 25 | if ($lang != "xx") { 26 | foreach (glob(__DIR__ . "/plugins/*.php") as $filename) { 27 | $file = file_get_contents($filename); 28 | if (preg_match('~extends Adminer\\\\Plugin~', $file)) { 29 | preg_match_all("~\\\$this->lang\\(('(?:[^\\\\']+|\\\\.)*')([),])~", $file, $matches); 30 | $messages = array("''" => "") + array_combine($matches[1], $matches[2]); 31 | $file = preg_replace("~(\\\$translations = array\\((?!.*'$lang').*?)\t\\);~s", "\\1\t\t'$lang' => array(\n\t\t),\n\t);", $file); 32 | file_put_contents($filename, $file); 33 | update_translations($lang, $messages, $filename, "~(\\\$translations = array\\(.*'$lang' => array\\(\n)(.*)(?=^\t\t\\),)~msU", "\t\t\t"); 34 | } 35 | } 36 | } 37 | } 38 | 39 | function update_translations($lang, $messages, $filename, $pattern, $tabs = "\t") { 40 | $file = file_get_contents($filename); 41 | $file = str_replace("\r", "", $file); 42 | $start = 0; 43 | $s = preg_replace_callback($pattern, function ($match) use ($lang, $messages, $filename, $file, $tabs, &$start) { 44 | $prefix = $match[1][0]; 45 | $start = $match[2][1]; 46 | preg_match_all("~^(\\s*(?:// [^'].*\\s+)?)(?:// )?(('(?:[^\\\\']+|\\\\.)*') => (.*[^,\n])),?~m", $match[2][0], $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); 47 | $s = ""; 48 | $fullstop = ($lang == 'bn' || $lang == 'hi' ? '।' : (preg_match('~^(ja|zh)~', $lang) ? '。' : ($lang == 'he' ? '[^.]' : '\.'))); 49 | foreach ($matches as $match) { 50 | list(, list($indent), list($line, $offset), list($en), list($translation)) = $match; 51 | if (isset($messages[$en])) { 52 | // keep current messages 53 | $s .= "$indent$line,\n"; 54 | unset($messages[$en]); 55 | $en_fullstop = (substr($en, -2, 1) == "."); 56 | //! check in array 57 | if ($en != "','" && ($en_fullstop xor preg_match("~$fullstop'\)?\$~", $line))) { 58 | if ($lang != ($en_fullstop ? "ja" : "he")) { // fullstop is optional in 'ja', forbidden in 'he' 59 | echo "$filename:" . (substr_count($file, "\n", 0, $start + $offset) + 1) . ":Not matching fullstop: $line\n"; 60 | } 61 | } 62 | if (preg_match('~%~', $en) xor preg_match('~%~', $translation)) { 63 | echo "$filename:" . (substr_count($file, "\n", 0, $start + $offset) + 1) . ":Not matching placeholder.\n"; 64 | } 65 | } else { 66 | // comment deprecated messages 67 | $s .= "$indent// $line,\n"; 68 | } 69 | } 70 | if ($messages) { 71 | $start += strlen($s); 72 | foreach ($messages as $idf => $val) { 73 | // add new messages 74 | if ($val == "," && strpos($idf, "%d")) { 75 | $s .= "$tabs$idf => array(),\n"; 76 | } elseif ($lang != "en") { 77 | $s .= "$tabs$idf => null,\n"; 78 | } 79 | } 80 | } 81 | return $prefix . $s; 82 | }, $file, -1, $count, PREG_OFFSET_CAPTURE); 83 | if ($s != $file) { 84 | $s = str_replace("array(\n\t\t\t'' => null,\n\t\t),", "array('' => null),", $s); 85 | file_put_contents($filename, $s); 86 | echo "$filename:" . (substr_count($s, "\n", 0, $start) + 1) . ":Updated.\n"; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 6 3 | checkNullables: true # level 8 4 | 5 | ignoreErrors: 6 | # need to fix 7 | - "~^Function Adminer\\\\fields_from_edit\\(\\) should return|Adminer\\\\Driver::\\$primary~" # Mongo and SimpleDB 8 | - "~Adminer\\\\Result.*mysqli_result~" # mysqli_result 9 | - "~Function Adminer\\\\queries\\(\\) never returns Adminer\\\\Result~" # mysqli_result 10 | 11 | # not real problems 12 | - identifier: include.fileNotFound # includes in include/ relative from index.php 13 | - identifier: includeOnce.fileNotFound # ./adminer-plugins.php 14 | - "~^Function (set_magic_quotes_runtime|mysql_)~" # PHP < 7 functions 15 | - "~an unknown class OCI-?Lob~" # this looks like PHPStan bug 16 | - "~^Variable \\$error might not be defined~" # declared in bootstrap.inc.php 17 | - "~^Constant LANG not found~" # defined in lang.inc.php 18 | - "~ an undefined \\w+ Adminer\\\\Db::~" # defined in that versions of Db 19 | - "~^Call to an undefined method Adminer\\\\Result::seek~" # defined in MS SQL 20 | - "~^Call to an undefined method Adminer\\\\Driver::setUserTypes~" # defined in PostgreSQL 21 | - "~expects int, float given~" # this will work 22 | - "~expects bool~" # truthy values 23 | - "~fread expects int<1, max>, 100000~" # 1e6 24 | - "~'strlen' given~" # used as a bool callback 25 | 26 | - 27 | message: "~ type specified~" # duplicate functions and methods 28 | paths: 29 | - adminer/include/pdo.inc.php 30 | - adminer/drivers/* 31 | 32 | # it probably doesn't like $ar[$key] instead of isset($ar[$key]) and thinks that $ar[$key] is always set 33 | - identifier: identical.alwaysFalse 34 | - identifier: notEqual.alwaysFalse 35 | - identifier: notIdentical.alwaysTrue 36 | - identifier: booleanNot.alwaysTrue 37 | - identifier: booleanNot.alwaysFalse 38 | - identifier: booleanAnd.alwaysFalse 39 | - identifier: booleanAnd.leftAlwaysTrue 40 | - identifier: booleanAnd.rightAlwaysTrue 41 | - identifier: booleanAnd.rightAlwaysFalse 42 | - identifier: ternary.alwaysTrue 43 | - identifier: if.alwaysTrue 44 | - identifier: while.alwaysTrue 45 | - identifier: isset.offset 46 | - identifier: deadCode.unreachable 47 | 48 | paths: 49 | - adminer/drivers/mysql.inc.php # other drivers inherit the annotations so we take them from here 50 | - adminer/ 51 | scanFiles: 52 | - compile.php # compile_file() 53 | excludePaths: 54 | - adminer/adminer-plugins* 55 | - adminer/designs.php 56 | - adminer/elastic.php 57 | - adminer/sqlite.php 58 | 59 | phpVersion: 60 | min: 70100 61 | max: 80499 62 | 63 | typeAliases: 64 | TableStatus: "array{Name:string, Engine?:?string, Comment?:string, Oid?:numeric-string, Rows?:?numeric-string, Collation?:string, Auto_increment?:?numeric-string, Data_length?:numeric-string, Index_length?:numeric-string, Data_free?:numeric-string, Create_options?:string, inherited?:numeric-string, nspname?:string}" 65 | Field: "array{field?:string, full_type:string, type:string, length:numeric-string, unsigned:string, default?:string, null:bool, auto_increment:bool, collation:string, privileges:int[], comment:string, primary:bool, generated:string, orig?:string, on_update?:string, on_delete?:string, default_constraint?: string}" 66 | FieldType: "array{type:string, length:numeric-string, unsigned:string, collation:string}" # subset of RoutineField and Field 67 | RoutineField: "array{field:string, type:string, length:numeric-string, unsigned:string, null:bool, full_type:string, collation:string, inout?:string}" 68 | Index: "array{type:string, columns:list, lengths:list, descs:list, algorithm?:string, partial?:string}" 69 | ForeignKey: "array{db?:string, ns?:string, table:string, source:list, target:list, on_delete:string, on_update?:string, definition?:string, deferrable?:string}" 70 | Trigger: "array{Trigger?:string, Timing?:string, Event?:string, Of?:string, Type?:string, Statement?:string}" 71 | Routine: "array{name?:string, fields:list, comment:string, returns?:FieldType, definition:string, language?:string}" 72 | Partitions: "array{partition_by?:string, partition?:string, partitions?:numeric-string, partition_names?:list, partition_values?:list}" 73 | BackwardKey: "array{name:string, keys:string[][]}" 74 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | Plugins directory including external plugins: https://www.adminer.org/plugins/ 2 | -------------------------------------------------------------------------------- /plugins/adminer.js.php: -------------------------------------------------------------------------------- 1 | array('' => 'Nahraje adminer.js'), 22 | 'de' => array('' => 'Laden Sie adminer.js'), 23 | 'pl' => array('' => 'Wczytuj adminer.js'), 24 | 'ro' => array('' => 'Încarcă adminer.js'), 25 | 'ja' => array('' => 'adminer.js を読込み'), 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /plugins/backward-keys.php: -------------------------------------------------------------------------------- 1 | $val) { 25 | $name = Adminer\adminer()->tableName(Adminer\table_status1($key, true)); 26 | if ($name != "") { 27 | $search = preg_quote($tableName); 28 | $separator = '(:|\s*-)?\s+'; 29 | $return[$key]["name"] = (preg_match("(^$search$separator(.+)|^(.+?)$separator$search\$)iu", $name, $match) ? $match[2] . $match[3] : $name); 30 | } else { 31 | unset($return[$key]); 32 | } 33 | } 34 | return $return; 35 | } 36 | 37 | function backwardKeysPrint($backwardKeys, $row) { 38 | foreach ($backwardKeys as $table => $backwardKey) { 39 | foreach ($backwardKey["keys"] as $cols) { 40 | $link = Adminer\ME . 'select=' . urlencode($table); 41 | $i = 0; 42 | foreach ($cols as $column => $val) { 43 | $link .= Adminer\where_link($i++, $column, $row[$val]); 44 | } 45 | echo "" . Adminer\h($backwardKey["name"]) . ""; 46 | $link = Adminer\ME . 'edit=' . urlencode($table); 47 | foreach ($cols as $column => $val) { 48 | $link .= "&set" . urlencode("[" . Adminer\bracket_escape($column) . "]") . "=" . urlencode($row[$val]); 49 | } 50 | echo "+ "; 51 | } 52 | } 53 | } 54 | 55 | function screenshot() { 56 | return "https://www.adminer.org/static/plugins/backward-keys.png"; 57 | } 58 | 59 | protected $translations = array( 60 | 'cs' => array('' => 'Zobrazí odkazy na tabulky odkazující aktuální řádek, stejně jako Adminer Editor'), 61 | 'de' => array('' => 'Links zu Tabellen anzeigen die auf die aktuelle Zeile verweisen, wie im Adminer Editor'), 62 | 'ja' => array('' => 'Adminer Editor と同様に、カレント行を参照しているテーブルへのリンクを表示'), 63 | 'pl' => array('' => 'Wyświetlaj linki do tabel odnoszących się do bieżącego wiersza, tak samo jak w Edytorze administratora'), 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /plugins/before-unload.php: -------------------------------------------------------------------------------- 1 | 13 | 31 | array('' => 'Zobrazí potvrzení před odnahráním stránky, pokud bylo změněno formulářové políčko'), 36 | 'de' => array('' => 'Zeigt eine Bestätigung an bevor die Seite neu geladen wird, wenn ein Formularfeld geändert wurde'), 37 | 'ja' => array('' => 'フォームの列が変更された時、ページを再読込みする前に確認を表示'), 38 | 'pl' => array('' => 'Wyświetlaj potwierdzenie przed rozładowaniem strony, jeśli pole formularza zostało zmienione'), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /plugins/codemirror.php: -------------------------------------------------------------------------------- 1 | including type-ahead of keywords and tables 4 | * @link https://codemirror.net/5/ 5 | * @link https://www.adminer.org/plugins/#use 6 | * @author Jakub Vrana, https://www.vrana.cz/ 7 | * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 8 | * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other) 9 | */ 10 | class AdminerCodemirror extends Adminer\Plugin { 11 | private $root; 12 | private $minified; 13 | 14 | function __construct($root = "https://cdn.jsdelivr.net/npm/codemirror@5", $minified = ".min") { 15 | $this->root = $root; 16 | $this->minified = $minified; 17 | } 18 | 19 | function syntaxHighlighting($tableStatuses) { 20 | ?> 21 | 26 | root/lib/codemirror$this->minified.js", true); 28 | echo Adminer\script_src("$this->root/addon/runmode/runmode$this->minified.js", true); 29 | echo Adminer\script_src("$this->root/addon/hint/show-hint$this->minified.js", true); 30 | echo Adminer\script_src("$this->root/mode/javascript/javascript$this->minified.js", true); 31 | $tables = array_fill_keys(array_keys($tableStatuses), array()); 32 | if (Adminer\support("sql")) { 33 | echo Adminer\script_src("$this->root/mode/sql/sql$this->minified.js", true); 34 | echo Adminer\script_src("$this->root/addon/hint/sql-hint$this->minified.js", true); 35 | if (isset($_GET["sql"]) || isset($_GET["trigger"]) || isset($_GET["check"])) { 36 | foreach (Adminer\driver()->allFields() as $table => $fields) { 37 | foreach ($fields as $field) { 38 | $tables[$table][] = $field["field"]; 39 | } 40 | } 41 | } 42 | } 43 | ?> 44 | 97 | array('' => 'Použít CodeMirror 5 pro zvýrazňování syntaxe a '; 14 | } 15 | } 16 | 17 | protected $translations = array( 18 | 'cs' => array('' => 'Použije "; 22 | } 23 | } 24 | 25 | function processInput($field, $value, $function = '') { 26 | if ($function === '') { 27 | $json = $this->testJson($value); 28 | if ($json !== $value) { 29 | return Adminer\q(json_encode($json)); 30 | } 31 | } 32 | } 33 | 34 | protected $translations = array( 35 | 'cs' => array('' => 'V editaci zobrazí syntaxi u JSONu'), 36 | 'de' => array('' => 'JSON-Werte in der Bearbeitung hübsch drucken'), 37 | 'pl' => array('' => 'Ładnie drukuj wartości JSON w edycji'), 38 | 'ro' => array('' => 'Afisare frumoasa a valorilor JSON în editare'), 39 | 'ja' => array('' => '編集時に JSON 文字列を見易く表示'), 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /plugins/prism.php: -------------------------------------------------------------------------------- 1 | 4 | * @link https://prism-code-editor.netlify.app/ 5 | * @link https://www.adminer.org/plugins/#use 6 | * @author Jakub Vrana, https://www.vrana.cz/ 7 | * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 8 | * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other) 9 | */ 10 | class AdminerPrism extends Adminer\Plugin { 11 | private $editorRoot; 12 | private $minified; 13 | private $theme; 14 | 15 | function __construct($editorRoot = "https://cdn.jsdelivr.net/npm/prism-code-editor@3/dist", $minified = ".min", $theme = "prism") { 16 | $this->editorRoot = $editorRoot; 17 | $this->minified = $minified; 18 | $this->theme = $theme; 19 | } 20 | 21 | function syntaxHighlighting($tableStatuses) { 22 | ?> 23 | 28 | 59 | array('' => 'Použije Prism Code Editor pro zvýrazňování syntaxe a \n"; 53 | ?> 54 |

55 | 91 | array( 101 | '' => 'Generování SQL příkazů pomocí umělé inteligence Google Gemini', 102 | 'Ask Gemini' => 'Zeptat se Gemini', 103 | 'Just a sec...' => 'Chviličku...', 104 | ), 105 | 'pl' => array( 106 | 'Ask Gemini' => 'Zapytaj Gemini', 107 | 'Just a sec...' => 'Chwileczkę...', 108 | ), 109 | 'de' => array( 110 | '' => 'KI-Eingabeaufforderung im SQL-Befehl zur Erstellung der Abfragen mit Google Gemini', 111 | 'Ask Gemini' => 'Gemini fragen', 112 | 'Just a sec...' => 'Einen Moment...', 113 | ), 114 | 'ja' => array( 115 | '' => 'Google Gemini AI を用いて SQL 文を生成', 116 | 'Ask Gemini' => 'Gemini に聞く', 117 | 'Just a sec...' => 'しばらくお待ち下さい...', 118 | ), 119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /plugins/sql-log.php: -------------------------------------------------------------------------------- 1 | filename = $filename; 17 | } 18 | 19 | function messageQuery($query, $time, $failed = false) { 20 | $this->log($query); 21 | } 22 | 23 | function sqlCommandQuery($query) { 24 | $this->log($query); 25 | } 26 | 27 | private function log($query) { 28 | if ($this->filename == "") { 29 | $this->filename = Adminer\adminer()->database() . ($_GET["ns"] != "" ? ".$_GET[ns]" : "") . ".sql"; // no database goes to ".sql" to avoid collisions 30 | } 31 | $fp = fopen($this->filename, "a"); 32 | flock($fp, LOCK_EX); 33 | fwrite($fp, $query); 34 | fwrite($fp, "\n\n"); 35 | flock($fp, LOCK_UN); 36 | fclose($fp); 37 | } 38 | 39 | protected $translations = array( 40 | 'cs' => array('' => 'Zaznamenává všechny příkazy do souboru SQL'), 41 | 'de' => array('' => 'Protokollieren Sie alle Abfragen in einer SQL-Datei'), 42 | 'pl' => array('' => 'Rejestruj wszystkie zapytania do pliku SQL'), 43 | 'ro' => array('' => 'Logați toate interogările în fișierul SQL'), 44 | 'ja' => array('' => '全クエリを SQL ファイルに記録'), 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /plugins/table-indexes-structure.php: -------------------------------------------------------------------------------- 1 | \n"; 13 | echo "" . Adminer\lang('Name') . "" . Adminer\lang('Type') . "" . Adminer\lang('Algorithm') . "" . Adminer\lang('Columns') . "\n"; 14 | foreach ($indexes as $name => $index) { 15 | echo "" . Adminer\h($name) . "$index[type]$index[algorithm]"; 16 | ksort($index["columns"]); // enforce correct columns order 17 | $print = array(); 18 | foreach ($index["columns"] as $key => $val) { 19 | $print[] = "" . Adminer\h($val) . "" 20 | . ($index["lengths"][$key] ? "(" . $index["lengths"][$key] . ")" : "") 21 | . ($index["descs"][$key] ? " DESC" : "") 22 | ; 23 | } 24 | echo "" . implode(", ", $print) . "\n"; 25 | } 26 | echo "\n"; 27 | return true; 28 | } 29 | 30 | protected $translations = array( 31 | 'cs' => array('' => 'Rozšířené informace o indexech'), 32 | 'de' => array('' => 'Erweiterte Ausgabe der Tabellenindize'), 33 | 'pl' => array('' => 'Rozszerzona tabela wyników struktury indeksów'), 34 | 'ro' => array('' => 'Ieșirea expandată a structurii indecsilor tabelului'), 35 | 'ja' => array('' => 'テーブルのインデックス構造を拡張表示'), 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /plugins/table-structure.php: -------------------------------------------------------------------------------- 1 | \n"; 16 | echo "\n"; 17 | echo "" 18 | . "\n" 25 | ; 26 | foreach ($fields as $field) { 27 | echo "
" . Adminer\lang('Column') 19 | . "" . Adminer\lang('Type') 20 | . "" . Adminer\lang('Collation') 21 | . "" . Adminer\lang('Nullable') 22 | . "" . Adminer\lang('Default') 23 | . (Adminer\support("comment") ? "" . Adminer\lang('Comment') : "") 24 | . "
" . Adminer\h($field["field"]) . ($field["primary"] ? " (PRIMARY)" : ""); 28 | echo "" . Adminer\h($field["full_type"]) . ""; 29 | echo ($field["auto_increment"] ? " " . Adminer\lang('Auto Increment') . "" : ""); 30 | echo "" . ($field["collation"] ? " " . Adminer\h($field["collation"]) . "" : ""); 31 | echo "" . ($field["null"] ? Adminer\lang('Yes') : Adminer\lang('No')); 32 | echo "" . Adminer\h($field["default"]); 33 | echo (Adminer\support("comment") ? "" . Adminer\h($field["comment"]) : ""); 34 | echo "\n"; 35 | } 36 | echo "
\n"; 37 | echo "\n"; 38 | return true; 39 | } 40 | 41 | protected $translations = array( 42 | 'cs' => array('' => 'Rozšířené informace o tabulkách'), 43 | 'de' => array('' => 'Erweiterte Ausgabe der Tabellenstruktur'), 44 | 'pl' => array('' => 'Rozszerzone wyjście struktury tabeli'), 45 | 'ro' => array('' => 'Ieșirea expandată a structurii tabelei'), 46 | 'ja' => array('' => 'テーブル構造を拡張表示'), 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /plugins/tables-filter.php: -------------------------------------------------------------------------------- 1 | 12 | > 13 | let tablesFilterTimeout = null; 14 | let tablesFilterValue = ''; 15 | 16 | function tablesFilter() { 17 | const value = qs('#filter-field').value.toLowerCase(); 18 | if (value == tablesFilterValue) { 19 | return; 20 | } 21 | tablesFilterValue = value; 22 | let reg; 23 | if (value != '') { 24 | reg = (value + '').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1'); 25 | reg = new RegExp('('+ reg + ')', 'gi'); 26 | } 27 | if (sessionStorage) { 28 | sessionStorage.setItem('adminer_tables_filter', value); 29 | } 30 | for (const table of qsa('li', qs('#tables'))) { 31 | let a = null; 32 | let text = table.getAttribute('data-table-name'); 33 | if (text == null) { 34 | a = qsa('a', table)[1]; 35 | text = a.innerHTML.trim(); 36 | 37 | table.setAttribute('data-table-name', text); 38 | a.setAttribute('data-link', 'main'); 39 | } else { 40 | a = qs('a[data-link="main"]', table); 41 | } 42 | if (value == '') { 43 | table.className = ''; 44 | a.innerHTML = text; 45 | } else { 46 | table.className = (text.toLowerCase().indexOf(value) == -1 ? 'hidden' : ''); 47 | a.innerHTML = text.replace(reg, '$1'); 48 | } 49 | } 50 | } 51 | 52 | function tablesFilterInput() { 53 | window.clearTimeout(tablesFilterTimeout); 54 | tablesFilterTimeout = window.setTimeout(tablesFilter, 200); 55 | } 56 | 57 | sessionStorage && document.addEventListener('DOMContentLoaded', () => { 58 | let db = qs('#dbs').querySelector('select'); 59 | db = db.options[db.selectedIndex].text; 60 | if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){ 61 | qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter'); 62 | tablesFilter(); 63 | } 64 | sessionStorage.setItem('adminer_tables_filter_db', db); 65 | }); 66 | 67 |

68 | array('' => 'Filtruje názvy v seznamu tabulek'), 73 | 'de' => array('' => 'Filtern Sie Namen in der Tabellenliste'), 74 | 'pl' => array('' => 'Filtruj nazwy na liście tabel'), 75 | 'ro' => array('' => 'Nume de filtre în lista de tabele'), 76 | 'ja' => array('' => 'テーブル一覧をテーブル名でフィルタリング'), 77 | ); 78 | } 79 | -------------------------------------------------------------------------------- /plugins/tinymce.php: -------------------------------------------------------------------------------- 1 | path = $path; 15 | } 16 | 17 | function head($dark = null) { 18 | $lang = Adminer\LANG; 19 | $lang = ($lang == "zh" ? "zh-cn" : ($lang == "zh-tw" ? "zh" : $lang)); 20 | if (!file_exists(dirname($this->path) . "/langs/$lang.js")) { 21 | $lang = "en"; 22 | } 23 | echo Adminer\script_src($this->path); 24 | ?> 25 | > 26 | tinyMCE.init({ 27 | entity_encoding: 'raw', 28 | language: '' 29 | }); // learn how to customize here: https://www.tinymce.com/docs/configure/ 30 | 31 | …"; 37 | $length = strlen($ellipsis); 38 | $shortened = (substr($val, -$length) == $ellipsis); 39 | if ($shortened) { 40 | $val = substr($val, 0, -$length); 41 | } 42 | //! shorten with regard to HTML tags - http://php.vrana.cz/zkraceni-textu-s-xhtml-znackami.php 43 | $val = preg_replace('~<[^>]*$~', '', html_entity_decode($val, ENT_QUOTES)); // remove ending incomplete tag (text can be shortened) 44 | if ($shortened) { 45 | $val .= $ellipsis; 46 | } 47 | if (class_exists('DOMDocument')) { // close all opened tags 48 | $dom = new DOMDocument; 49 | if (@$dom->loadHTML("$val")) { // @ - $val can contain errors 50 | $val = preg_replace('~.*]*>(.*).*~is', '\1', $dom->saveHTML()); 51 | } 52 | } 53 | } 54 | } 55 | 56 | function editInput($table, $field, $attrs, $value) { 57 | if (preg_match("~text~", $field["type"]) && preg_match("~_html~", $field["field"])) { 58 | return "" . Adminer\h($value) . "" . Adminer\script(" 59 | tinyMCE.remove(tinyMCE.get('fields-" . Adminer\js_escape($field["field"]) . "') || { }); 60 | tinyMCE.EditorManager.execCommand('mceAddControl', true, 'fields-" . Adminer\js_escape($field["field"]) . "'); 61 | qs('#form').onsubmit = () => { 62 | tinyMCE.each(tinyMCE.editors, ed => { 63 | ed.remove(); 64 | }); 65 | }; 66 | "); 67 | } 68 | } 69 | 70 | protected $translations = array( 71 | 'cs' => array('' => 'Upravuje všechna políčka obsahující "_html" pomocí HTML editoru TinyMCE a zobrazuje výsledné HTML ve výpisu'), 72 | 'de' => array('' => 'Bearbeiten Sie alle Felder, die "_html" enthalten, mit dem HTML-Editor TinyMCE und zeigen Sie den HTML-Code in Select an'), 73 | 'pl' => array('' => 'Edytuj wszystkie pola zawierające "_html" za pomocą edytora HTML TinyMCE i wyświetl kod HTML w wybranych'), 74 | 'ro' => array('' => 'Editați toate câmpurile care conțin "_html" cu ajutorul editorului HTML TinyMCE și afișați HTML-ul în select'), 75 | 'ja' => array('' => '列名が "_html" を含む列を TinyMCE の HTML エディタで編集し、編集結果の HTML コードを "選択" 画面に表示'), 76 | ); 77 | } 78 | -------------------------------------------------------------------------------- /plugins/translation.php: -------------------------------------------------------------------------------- 1 | query("INSERT INTO translation (language_id, idf, translation) VALUES (" . Adminer\q($lang) . ", " . Adminer\q($idf) . ", " . Adminer\q($idf) . ")"); 36 | } 37 | return $return; 38 | } 39 | 40 | function tableName(&$tableStatus) { 41 | $tableStatus["Comment"] = $this->translate($tableStatus["Comment"]); 42 | } 43 | 44 | function fieldName(&$field, $order = 0) { 45 | $field["comment"] = $this->translate($field["comment"]); 46 | } 47 | 48 | function editVal(&$val, $field) { 49 | if ($field["type"] == "enum") { 50 | $val = $this->translate($val); 51 | } 52 | } 53 | 54 | protected $translations = array( 55 | 'cs' => array('' => 'Přeloží všechny komentáře tabulek a sloupců, hodnoty políček enum a set pomocí tabulky "translation" (automaticky vkládá nové překlady)'), 56 | 'de' => array('' => 'Übersetzen Sie alle Tabellen- und Feldkommentare, enum- und set-Werte aus der "translation"-Tabelle (fügt automatisch neue Übersetzungen ein)'), 57 | 'pl' => array('' => 'Przetłumacz wszystkie komentarze do tabeli i pól, wartości enum i set z tabeli "translation" (automatycznie wstawia nowe tłumaczenia)'), 58 | 'ro' => array('' => 'Traduceți toate comentariile tabelelor și câmpurilor, valorile enum și set din tabelul "translation" (inserează automat noi traduceri)'), 59 | 'ja' => array('' => 'テーブル "translation" を用いてすべてのテーブルや列のコメント、列挙型、セット値を翻訳 (自動的に翻訳文で更新)'), 60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /plugins/version-github.php: -------------------------------------------------------------------------------- 1 | 13 | 26 | array('' => 'Kontrola nových verzí z GitHubu'), 35 | 'de' => array('' => 'Neue Versionen von GitHub verifizieren'), 36 | 'ja' => array('' => 'GitHub の新版を管理'), 37 | 'pl' => array('' => 'Weryfikuj nowe wersje z GitHuba'), 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /plugins/version-noverify.php: -------------------------------------------------------------------------------- 1 | { };"); 13 | } 14 | 15 | protected $translations = array( 16 | 'cs' => array('' => 'Zakáže kontrolu nových verzí'), 17 | 'de' => array('' => 'Deaktivieren Sie die Versionsprüfung'), 18 | 'pl' => array('' => 'Wyłącz sprawdzanie wersji'), 19 | 'ro' => array('' => 'Dezactivați verificatorul de versiuni'), 20 | 'ja' => array('' => 'バージョンチェックを無効化'), 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | Transactions in export 2 | Create view and routine options 3 | Variables editation 4 | Blob download and image display in edit form (important for Editor with hidden fields in select and SQL command) 5 | Add title to Logout and edit (in select) for style "hever" 6 | Export by GET parameters 7 | Draggable columns in alter table (thanks to Michal Manak) 8 |