mirror of
https://github.com/vrana/adminer.git
synced 2025-09-04 03:35:41 +02:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3f0bc24e01 | ||
|
4863f48d33 | ||
|
9ea8f44919 | ||
|
fa791b5461 | ||
|
203162b203 | ||
|
e4e76b6384 | ||
|
353cd452a3 | ||
|
5bc4ac6c18 | ||
|
aec8275502 | ||
|
7d5077e687 | ||
|
91d0d8538f | ||
|
2439369143 | ||
|
d5bce9b3e9 | ||
|
b42762e4dc | ||
|
695a720403 | ||
|
e6fdf2b400 | ||
|
b542b6613c | ||
|
374b8ed6a6 | ||
|
58cca3f951 | ||
|
5eecb8e6a3 | ||
|
0d0936550c | ||
|
c4ed9500a1 | ||
|
0863766970 | ||
|
146a24efad | ||
|
00b9fbda08 | ||
|
8ea329538f | ||
|
a3428cc7ff | ||
|
2a01969c96 | ||
|
9b8d14c3ee | ||
|
2ce88d9bdc | ||
|
593c8e5bcc |
20
.editorconfig
Normal file
20
.editorconfig
Normal file
@@ -0,0 +1,20 @@
|
||||
# https://editorconfig.org/
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{php,css,js}]
|
||||
indent_style = tab
|
||||
|
||||
[*.json]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
trim_trailing_whitespace = false
|
||||
max_line_length = 120
|
@@ -630,6 +630,13 @@ WHERE sys1.xtype = 'TR' AND sys2.name = " . q($table)
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function is_strict_mode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function show_status() {
|
||||
return array();
|
||||
}
|
||||
|
@@ -16,10 +16,17 @@ if (!defined("DRIVER")) {
|
||||
global $adminer;
|
||||
mysqli_report(MYSQLI_REPORT_OFF); // stays between requests, not required since PHP 5.3.4
|
||||
list($host, $port) = explode(":", $server, 2); // part after : is used for port or socket
|
||||
|
||||
$ssl = $adminer->connectSsl();
|
||||
if ($ssl) {
|
||||
$this->ssl_set($ssl['key'], $ssl['cert'], $ssl['ca'], '', '');
|
||||
if (isset($ssl['key']) || isset($ssl['cert']) || isset($ssl['ca'])) {
|
||||
$this->ssl_set(
|
||||
isset($ssl['key']) ? $ssl['key'] : null,
|
||||
isset($ssl['cert']) ? $ssl['cert'] : null,
|
||||
isset($ssl['ca']) ? $ssl['ca'] : null,
|
||||
null, null
|
||||
);
|
||||
}
|
||||
|
||||
$return = @$this->real_connect(
|
||||
($server != "" ? $host : ini_get("mysqli.default_host")),
|
||||
($server . $username != "" ? $username : ini_get("mysqli.default_user")),
|
||||
@@ -234,25 +241,23 @@ if (!defined("DRIVER")) {
|
||||
|
||||
function connect($server, $username, $password) {
|
||||
global $adminer;
|
||||
$options = array(PDO::MYSQL_ATTR_LOCAL_INFILE => false);
|
||||
|
||||
$dsn = "mysql:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server));
|
||||
|
||||
$options = [PDO::MYSQL_ATTR_LOCAL_INFILE => false];
|
||||
$ssl = $adminer->connectSsl();
|
||||
if ($ssl) {
|
||||
if (!empty($ssl['key'])) {
|
||||
$options[PDO::MYSQL_ATTR_SSL_KEY] = $ssl['key'];
|
||||
}
|
||||
if (!empty($ssl['cert'])) {
|
||||
$options[PDO::MYSQL_ATTR_SSL_CERT] = $ssl['cert'];
|
||||
}
|
||||
if (!empty($ssl['ca'])) {
|
||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $ssl['ca'];
|
||||
}
|
||||
if (isset($ssl['key'])) {
|
||||
$options[PDO::MYSQL_ATTR_SSL_KEY] = $ssl['key'];
|
||||
}
|
||||
$this->dsn(
|
||||
"mysql:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)),
|
||||
$username,
|
||||
$password,
|
||||
$options
|
||||
);
|
||||
if (isset($ssl['cert'])) {
|
||||
$options[PDO::MYSQL_ATTR_SSL_CERT] = $ssl['cert'];
|
||||
}
|
||||
if (isset($ssl['ca'])) {
|
||||
$options[PDO::MYSQL_ATTR_SSL_CA] = $ssl['ca'];
|
||||
}
|
||||
|
||||
$this->dsn($dsn, $username, $password, $options);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -316,8 +321,8 @@ if (!defined("DRIVER")) {
|
||||
}
|
||||
}
|
||||
|
||||
function convertSearch($idf, $val, $field) {
|
||||
return (preg_match('~char|text|enum|set~', $field["type"]) && !preg_match("~^utf8~", $field["collation"]) && preg_match('~[\x80-\xFF]~', $val['val'])
|
||||
function convertSearch($idf, array $where, array $field) {
|
||||
return (preg_match('~char|text|enum|set~', $field["type"]) && !preg_match("~^utf8~", $field["collation"]) && preg_match('~[\x80-\xFF]~', $where['val'])
|
||||
? "CONVERT($idf USING " . charset($this->_conn) . ")"
|
||||
: $idf
|
||||
);
|
||||
@@ -1056,6 +1061,19 @@ if (!defined("DRIVER")) {
|
||||
return get_key_vals("SHOW VARIABLES");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function is_strict_mode() {
|
||||
static $strictMode = null;
|
||||
|
||||
if ($strictMode === null) {
|
||||
$strictMode = (bool)preg_match('~STRICT_(TRANS|ALL)_TABLES~', get_key_vals("SHOW VARIABLES LIKE 'sql_mode'")["sql_mode"]);
|
||||
}
|
||||
|
||||
return $strictMode;
|
||||
}
|
||||
|
||||
/** Get process list
|
||||
* @return array ($row)
|
||||
*/
|
||||
@@ -1160,7 +1178,7 @@ if (!defined("DRIVER")) {
|
||||
'structured_types' => $structured_types,
|
||||
'unsigned' => array("unsigned", "zerofill", "unsigned zerofill"), ///< @var array number variants
|
||||
'operators' => array("=", "<", ">", "<=", ">=", "!=", "LIKE", "LIKE %%", "REGEXP", "IN", "FIND_IN_SET", "IS NULL", "NOT LIKE", "NOT REGEXP", "NOT IN", "IS NOT NULL", "SQL"), ///< @var array operators used in select
|
||||
'functions' => array("char_length", "date", "from_unixtime", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper"), ///< @var array functions used in select
|
||||
'functions' => array("char_length", "date", "from_unixtime", "unix_timestamp", "lower", "round", "floor", "ceil", "sec_to_time", "time_to_sec", "upper"), ///< @var array functions used in select
|
||||
'grouping' => array("avg", "count", "count distinct", "group_concat", "max", "min", "sum"), ///< @var array grouping functions used in select
|
||||
'edit_functions' => array( ///< @var array of array("$type|$type2" => "$function/$function2") functions used in editing, [0] - edit and insert, [1] - edit only
|
||||
array(
|
||||
|
@@ -486,6 +486,13 @@ AND c_src.TABLE_NAME = " . q($table);
|
||||
return get_key_vals('SELECT name, display_value FROM v$parameter');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function is_strict_mode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function process_list() {
|
||||
return get_rows('SELECT sess.process AS "process", sess.username AS "user", sess.schemaname AS "schema", sess.status AS "status", sess.wait_class AS "wait_class", sess.seconds_in_wait AS "seconds_in_wait", sql.sql_text AS "sql_text", sess.machine AS "machine", sess.port AS "port"
|
||||
FROM v$session sess LEFT OUTER JOIN v$sql sql
|
||||
|
@@ -19,7 +19,14 @@ if (isset($_GET["pgsql"])) {
|
||||
global $adminer;
|
||||
$db = $adminer->database();
|
||||
set_error_handler(array($this, '_error'));
|
||||
|
||||
$this->_string = "host='" . str_replace(":", "' port='", addcslashes($server, "'\\")) . "' user='" . addcslashes($username, "'\\") . "' password='" . addcslashes($password, "'\\") . "'";
|
||||
|
||||
$ssl = $adminer->connectSsl();
|
||||
if (isset($ssl["mode"])) {
|
||||
$this->_string .= " sslmode='" . $ssl["mode"] . "'";
|
||||
}
|
||||
|
||||
$this->_link = @pg_connect("$this->_string dbname='" . ($db != "" ? addcslashes($db, "'\\") : "postgres") . "'", PGSQL_CONNECT_FORCE_NEW);
|
||||
if (!$this->_link && $db != "") {
|
||||
// try to connect directly with database for performance
|
||||
@@ -36,7 +43,7 @@ if (isset($_GET["pgsql"])) {
|
||||
}
|
||||
|
||||
function quote($string) {
|
||||
return "'" . pg_escape_string($this->_link, $string) . "'";
|
||||
return pg_escape_literal($this->_link, $string);
|
||||
}
|
||||
|
||||
function value($val, $field) {
|
||||
@@ -148,9 +155,19 @@ if (isset($_GET["pgsql"])) {
|
||||
|
||||
function connect($server, $username, $password) {
|
||||
global $adminer;
|
||||
|
||||
$db = $adminer->database();
|
||||
$this->dsn("pgsql:host='" . str_replace(":", "' port='", addcslashes($server, "'\\")) . "' client_encoding=utf8 dbname='" . ($db != "" ? addcslashes($db, "'\\") : "postgres") . "'", $username, $password); //! client_encoding is supported since 9.1 but we can't yet use min_version here
|
||||
//! connect without DB in case of an error
|
||||
|
||||
//! client_encoding is supported since 9.1, but we can't yet use min_version here
|
||||
$dsn = "pgsql:host='" . str_replace(":", "' port='", addcslashes($server, "'\\")) . "' client_encoding=utf8 dbname='" . ($db != "" ? addcslashes($db, "'\\") : "postgres") . "'";
|
||||
|
||||
$ssl = $adminer->connectSsl();
|
||||
if (isset($ssl["mode"])) {
|
||||
$dsn .= " sslmode='" . $ssl["mode"] . "'";
|
||||
}
|
||||
|
||||
$this->dsn($dsn, $username, $password);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -212,13 +229,13 @@ if (isset($_GET["pgsql"])) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
function convertSearch($idf, $val, $field) {
|
||||
return (preg_match('~char|text'
|
||||
. (!preg_match('~LIKE~', $val["op"]) ? '|date|time(stamp)?|boolean|uuid|' . number_type() : '')
|
||||
. '~', $field["type"])
|
||||
? $idf
|
||||
: "CAST($idf AS text)"
|
||||
);
|
||||
function convertSearch($idf, array $where, array $field) {
|
||||
$textTypes = "char|text";
|
||||
if (strpos($where["op"], "LIKE") === false) {
|
||||
$textTypes .= "|date|time(stamp)?|boolean|uuid|inet|cidr|macaddr|" . number_type();
|
||||
}
|
||||
|
||||
return (preg_match("~$textTypes~", $field["type"]) ? $idf : "CAST($idf AS text)");
|
||||
}
|
||||
|
||||
function quoteBinary($s) {
|
||||
@@ -274,7 +291,9 @@ if (isset($_GET["pgsql"])) {
|
||||
}
|
||||
|
||||
function get_databases() {
|
||||
return get_vals("SELECT datname FROM pg_database WHERE has_database_privilege(datname, 'CONNECT') ORDER BY datname");
|
||||
return get_vals("SELECT d.datname FROM pg_database d JOIN pg_roles r ON d.datdba = r.oid
|
||||
WHERE d.datallowconn = TRUE AND has_database_privilege(d.datname, 'CONNECT') AND pg_has_role(r.rolname, 'USAGE')
|
||||
ORDER BY d.datname");
|
||||
}
|
||||
|
||||
function limit($query, $where, $limit, $offset = 0, $separator = " ") {
|
||||
@@ -322,7 +341,7 @@ ORDER BY 1";
|
||||
|
||||
function table_status($name = "") {
|
||||
$return = array();
|
||||
foreach (get_rows("SELECT c.relname AS \"Name\", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'm' THEN 'materialized view' ELSE 'view' END AS \"Engine\", pg_relation_size(c.oid) AS \"Data_length\", pg_total_relation_size(c.oid) - pg_relation_size(c.oid) AS \"Index_length\", obj_description(c.oid, 'pg_class') AS \"Comment\", " . (min_version(12) ? "''" : "CASE WHEN c.relhasoids THEN 'oid' ELSE '' END") . " AS \"Oid\", c.reltuples as \"Rows\", n.nspname
|
||||
foreach (get_rows("SELECT c.relname AS \"Name\", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'm' THEN 'materialized view' ELSE 'view' END AS \"Engine\", pg_table_size(c.oid) AS \"Data_length\", pg_indexes_size(c.oid) AS \"Index_length\", obj_description(c.oid, 'pg_class') AS \"Comment\", " . (min_version(12) ? "''" : "CASE WHEN c.relhasoids THEN 'oid' ELSE '' END") . " AS \"Oid\", c.reltuples as \"Rows\", n.nspname
|
||||
FROM pg_class c
|
||||
JOIN pg_namespace n ON(n.nspname = current_schema() AND n.oid = c.relnamespace)
|
||||
WHERE relkind IN ('r', 'm', 'v', 'f', 'p')
|
||||
@@ -376,7 +395,7 @@ ORDER BY a.attnum"
|
||||
}
|
||||
$row["null"] = !$row["attnotnull"];
|
||||
$row["auto_increment"] = $row['attidentity'] || preg_match('~^nextval\(~i', $row["default"]);
|
||||
$row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1);
|
||||
$row["privileges"] = array("insert" => 1, "select" => 1, "update" => 1, "where" => 1, "order" => 1);
|
||||
if (preg_match('~(.+)::[^,)]+(.*)~', $row["default"], $match)) {
|
||||
$row["default"] = ($match[1] == "NULL" ? null : idf_unescape($match[1]) . $match[2]);
|
||||
}
|
||||
@@ -773,7 +792,7 @@ AND typelem = 0"
|
||||
$return = "CREATE TABLE " . idf_escape($status['nspname']) . "." . idf_escape($status['Name']) . " (\n ";
|
||||
|
||||
// fields' definitions
|
||||
foreach ($fields as $field_name => $field) {
|
||||
foreach ($fields as $field) {
|
||||
$part = idf_escape($field['field']) . ' ' . $field['full_type']
|
||||
. default_value($field)
|
||||
. ($field['attnotnull'] ? " NOT NULL" : "");
|
||||
@@ -782,10 +801,11 @@ AND typelem = 0"
|
||||
// sequences for fields
|
||||
if (preg_match('~nextval\(\'([^\']+)\'\)~', $field['default'], $matches)) {
|
||||
$sequence_name = $matches[1];
|
||||
$sq = reset(get_rows(min_version(10)
|
||||
? "SELECT *, cache_size AS cache_value FROM pg_sequences WHERE schemaname = current_schema() AND sequencename = " . q($sequence_name)
|
||||
$rows = get_rows(min_version(10)
|
||||
? "SELECT *, cache_size AS cache_value FROM pg_sequences WHERE schemaname = current_schema() AND sequencename = " . q(idf_unescape($sequence_name))
|
||||
: "SELECT * FROM $sequence_name"
|
||||
));
|
||||
);
|
||||
$sq = reset($rows);
|
||||
$sequences[] = ($style == "DROP+CREATE" ? "DROP SEQUENCE IF EXISTS $sequence_name;\n" : "")
|
||||
. "CREATE SEQUENCE $sequence_name INCREMENT $sq[increment_by] MINVALUE $sq[min_value] MAXVALUE $sq[max_value]" . ($auto_increment && $sq['last_value'] ? " START $sq[last_value]" : "") . " CACHE $sq[cache_value];";
|
||||
}
|
||||
@@ -858,6 +878,13 @@ AND typelem = 0"
|
||||
return get_key_vals("SHOW ALL");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function is_strict_mode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function process_list() {
|
||||
return get_rows("SELECT * FROM pg_stat_activity ORDER BY " . (min_version(9.2) ? "pid" : "procpid"));
|
||||
}
|
||||
@@ -897,7 +924,7 @@ AND typelem = 0"
|
||||
lang('Date and time') => array("date" => 13, "time" => 17, "timestamp" => 20, "timestamptz" => 21, "interval" => 0),
|
||||
lang('Strings') => array("character" => 0, "character varying" => 0, "text" => 0, "tsquery" => 0, "tsvector" => 0, "uuid" => 0, "xml" => 0),
|
||||
lang('Binary') => array("bit" => 0, "bit varying" => 0, "bytea" => 0),
|
||||
lang('Network') => array("cidr" => 43, "inet" => 43, "macaddr" => 17, "txid_snapshot" => 0),
|
||||
lang('Network') => array("cidr" => 43, "inet" => 43, "macaddr" => 17, "macaddr8" => 23, "txid_snapshot" => 0),
|
||||
lang('Geometry') => array("box" => 0, "circle" => 0, "line" => 0, "lseg" => 0, "path" => 0, "point" => 0, "polygon" => 0),
|
||||
) as $key => $val) { //! can be retrieved from pg_type
|
||||
$types += $val;
|
||||
|
@@ -764,6 +764,13 @@ if (isset($_GET["sqlite"]) || isset($_GET["sqlite2"])) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function is_strict_mode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function show_status() {
|
||||
$return = array();
|
||||
foreach (get_vals("PRAGMA compile_options") as $option) {
|
||||
|
@@ -537,50 +537,60 @@ class Adminer {
|
||||
* @return array expressions to join by AND
|
||||
*/
|
||||
function selectSearchProcess($fields, $indexes) {
|
||||
global $connection, $driver;
|
||||
$return = array();
|
||||
global $driver;
|
||||
|
||||
$return = [];
|
||||
|
||||
foreach ($indexes as $i => $index) {
|
||||
if ($index["type"] == "FULLTEXT" && $_GET["fulltext"][$i] != "") {
|
||||
$return[] = "MATCH (" . implode(", ", array_map('idf_escape', $index["columns"])) . ") AGAINST (" . q($_GET["fulltext"][$i]) . (isset($_GET["boolean"][$i]) ? " IN BOOLEAN MODE" : "") . ")";
|
||||
}
|
||||
}
|
||||
foreach ((array) $_GET["where"] as $key => $val) {
|
||||
if ("$val[col]$val[val]" != "" && in_array($val["op"], $this->operators)) {
|
||||
|
||||
foreach ((array) $_GET["where"] as $where) {
|
||||
$col = $where["col"];
|
||||
$op = $where["op"];
|
||||
$val = $where["val"];
|
||||
|
||||
if ("$col$val" != "" && in_array($op, $this->operators)) {
|
||||
$prefix = "";
|
||||
$cond = " $val[op]";
|
||||
if (preg_match('~IN$~', $val["op"])) {
|
||||
$in = process_length($val["val"]);
|
||||
$cond = " $op";
|
||||
|
||||
if (preg_match('~IN$~', $op)) {
|
||||
$in = process_length($val);
|
||||
$cond .= " " . ($in != "" ? $in : "(NULL)");
|
||||
} elseif ($val["op"] == "SQL") {
|
||||
$cond = " $val[val]"; // SQL injection
|
||||
} elseif ($val["op"] == "LIKE %%") {
|
||||
$cond = " LIKE " . $this->processInput($fields[$val["col"]], "%$val[val]%");
|
||||
} elseif ($val["op"] == "ILIKE %%") {
|
||||
$cond = " ILIKE " . $this->processInput($fields[$val["col"]], "%$val[val]%");
|
||||
} elseif ($val["op"] == "FIND_IN_SET") {
|
||||
$prefix = "$val[op](" . q($val["val"]) . ", ";
|
||||
} elseif ($op == "SQL") {
|
||||
$cond = " $val"; // SQL injection
|
||||
} elseif ($op == "LIKE %%") {
|
||||
$cond = " LIKE " . $this->processInput($fields[$col], "%$val%");
|
||||
} elseif ($op == "ILIKE %%") {
|
||||
$cond = " ILIKE " . $this->processInput($fields[$col], "%$val%");
|
||||
} elseif ($op == "FIND_IN_SET") {
|
||||
$prefix = "$op(" . q($val) . ", ";
|
||||
$cond = ")";
|
||||
} elseif (!preg_match('~NULL$~', $val["op"])) {
|
||||
$cond .= " " . $this->processInput($fields[$val["col"]], $val["val"]);
|
||||
} elseif (!preg_match('~NULL$~', $op)) {
|
||||
$cond .= " " . $this->processInput($fields[$col], $val);
|
||||
}
|
||||
if ($val["col"] != "") {
|
||||
$return[] = $prefix . $driver->convertSearch(idf_escape($val["col"]), $val, $fields[$val["col"]]) . $cond;
|
||||
|
||||
if ($col != "") {
|
||||
$return[] = $prefix . $driver->convertSearch(idf_escape($col), $where, $fields[$col]) . $cond;
|
||||
} else {
|
||||
// find anywhere
|
||||
$cols = array();
|
||||
foreach ($fields as $name => $field) {
|
||||
if (isset($field["privileges"]["where"])
|
||||
&& (preg_match('~^[-\d.' . (preg_match('~IN$~', $val["op"]) ? ',' : '') . ']+$~', $val["val"]) || !preg_match('~' . number_type() . '|bit~', $field["type"]))
|
||||
&& (!preg_match("~[\x80-\xFF]~", $val["val"]) || preg_match('~char|text|enum|set~', $field["type"]))
|
||||
&& (!preg_match('~date|timestamp~', $field["type"]) || preg_match('~^\d+-\d+-\d+~', $val["val"]))
|
||||
&& (preg_match('~^[-\d.' . (preg_match('~IN$~', $op) ? ',' : '') . ']+$~', $val) || !preg_match('~' . number_type() . '|bit~', $field["type"]))
|
||||
&& (!preg_match("~[\x80-\xFF]~", $val) || preg_match('~char|text|enum|set~', $field["type"]))
|
||||
&& (!preg_match('~date|timestamp~', $field["type"]) || preg_match('~^\d+-\d+-\d+~', $val))
|
||||
) {
|
||||
$cols[] = $prefix . $driver->convertSearch(idf_escape($name), $val, $field) . $cond;
|
||||
$cols[] = $prefix . $driver->convertSearch(idf_escape($name), $where, $field) . $cond;
|
||||
}
|
||||
}
|
||||
$return[] = ($cols ? "(" . implode(" OR ", $cols) . ")" : "1 = 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
function adminer_errors($errno, $errstr) {
|
||||
return !!preg_match('~^(Trying to access array offset on value of type null|Undefined array key)~', $errstr);
|
||||
return (bool)preg_match('~^(Trying to access array offset on( value of type)? null|Undefined array key)~', $errstr);
|
||||
}
|
||||
|
||||
error_reporting(6135); // errors and warnings
|
||||
|
@@ -11,6 +11,15 @@ function add_driver($id, $name) {
|
||||
$drivers[$id] = $name;
|
||||
}
|
||||
|
||||
/** Get driver name
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
function get_driver($id) {
|
||||
global $drivers;
|
||||
return $drivers[$id];
|
||||
}
|
||||
|
||||
/*abstract*/ class Min_SQL {
|
||||
var $_conn;
|
||||
|
||||
@@ -138,7 +147,7 @@ function add_driver($id, $name) {
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
function convertSearch($idf, $val, $field) {
|
||||
function convertSearch($idf, array $where, array $field) {
|
||||
return $idf;
|
||||
}
|
||||
|
||||
|
@@ -21,11 +21,11 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
|
||||
echo "<table cellspacing='0' class='nowrap'>\n";
|
||||
echo "<thead><tr>";
|
||||
for ($j=0; $j < count($row); $j++) {
|
||||
$field = $result->fetch_field();
|
||||
$name = $field->name;
|
||||
$orgtable = $field->orgtable;
|
||||
$orgname = $field->orgname;
|
||||
$return[$field->table] = $orgtable;
|
||||
$field = (array)$result->fetch_field();
|
||||
$name = $field["name"];
|
||||
$orgtable = $field["orgtable"];
|
||||
$orgname = $field["orgname"];
|
||||
$return[$field["table"]] = $orgtable;
|
||||
if ($orgtables && $jush == "sql") { // MySQL EXPLAIN
|
||||
$links[$j] = ($name == "table" ? "table=" : ($name == "possible_keys" ? "indexes=" : null));
|
||||
} elseif ($orgtable != "") {
|
||||
@@ -46,11 +46,11 @@ function select($result, $connection2 = null, $orgtables = array(), $limit = 0)
|
||||
$links[$j] = $orgtable;
|
||||
}
|
||||
}
|
||||
if ($field->charsetnr == 63) { // 63 - binary
|
||||
if ($field["charsetnr"] == 63) { // 63 - binary
|
||||
$blobs[$j] = true;
|
||||
}
|
||||
$types[$j] = $field->type;
|
||||
echo "<th" . ($orgtable != "" || $field->name != $orgname ? " title='" . h(($orgtable != "" ? "$orgtable." : "") . $orgname) . "'" : "") . ">" . h($name)
|
||||
$types[$j] = $field["type"];
|
||||
echo "<th" . ($orgtable != "" || $field["name"] != $orgname ? " title='" . h(($orgtable != "" ? "$orgtable." : "") . $orgname) . "'" : "") . ">" . h($name)
|
||||
. ($orgtables ? doc_link(array(
|
||||
'sql' => "explain-output.html#explain_" . strtolower($name),
|
||||
'mariadb' => "explain/#the-columns-in-explain-select",
|
||||
@@ -238,7 +238,15 @@ function process_field($field, $type_field) {
|
||||
*/
|
||||
function default_value($field) {
|
||||
$default = $field["default"];
|
||||
return ($default === null ? "" : " DEFAULT " . (preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default) ? q($default) : $default));
|
||||
if ($default === null) return "";
|
||||
|
||||
if (preg_match('~^GENERATED ~i', $default)) {
|
||||
return " $default";
|
||||
}
|
||||
|
||||
$quote = preg_match('~char|binary|text|enum|set~', $field["type"]) || preg_match('~^(?![a-z])~i', $default);
|
||||
|
||||
return " DEFAULT " . ($quote ? q($default) : $default);
|
||||
}
|
||||
|
||||
/** Get type class to use in CSS
|
||||
@@ -279,11 +287,11 @@ function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = arra
|
||||
<td><?php echo lang('Options'); /* no label required, options have their own label */ ?>
|
||||
<?php if ($type == "TABLE") { ?>
|
||||
<td id="label-null">NULL
|
||||
<td><input type="radio" name="auto_increment_col" value=""><acronym id="label-ai" title="<?php echo lang('Auto Increment'); ?>">AI</acronym><?php echo doc_link(array(
|
||||
<td><input type="radio" name="auto_increment_col" value=""><abbr id="label-ai" title="<?php echo lang('Auto Increment'); ?>">AI</abbr><?php echo doc_link(array(
|
||||
'sql' => "example-auto-increment.html",
|
||||
'mariadb' => "auto_increment/",
|
||||
'sqlite' => "autoinc.html",
|
||||
'pgsql' => "datatype.html#DATATYPE-SERIAL",
|
||||
'pgsql' => "datatype-numeric.html#DATATYPE-SERIAL",
|
||||
'mssql' => "ms186775.aspx",
|
||||
)); ?>
|
||||
<td id="label-default"<?php echo $default_class; ?>><?php echo lang('Default value'); ?>
|
||||
|
@@ -914,13 +914,16 @@ function column_foreign_keys($table) {
|
||||
*/
|
||||
function enum_input($type, $attrs, $field, $value, $empty = null) {
|
||||
global $adminer;
|
||||
|
||||
$return = ($empty !== null && !is_strict_mode() ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === 0) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
|
||||
|
||||
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
|
||||
$return = ($empty !== null ? "<label><input type='$type'$attrs value='$empty'" . ((is_array($value) ? in_array($empty, $value) : $value === 0) ? " checked" : "") . "><i>" . lang('empty') . "</i></label>" : "");
|
||||
foreach ($matches[1] as $i => $val) {
|
||||
$val = stripcslashes(str_replace("''", "'", $val));
|
||||
$checked = (is_int($value) ? $value == $i+1 : (is_array($value) ? in_array($i+1, $value) : $value === $val));
|
||||
$return .= " <label><input type='$type'$attrs value='" . ($i+1) . "'" . ($checked ? ' checked' : '') . '>' . h($adminer->editVal($val, $field)) . '</label>';
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -978,7 +981,7 @@ function input($field, $value, $function) {
|
||||
$attrs .= " cols='50' rows='12'";
|
||||
} else {
|
||||
$rows = min(12, substr_count($value, "\n") + 1);
|
||||
$attrs .= " cols='30' rows='$rows'" . ($rows == 1 ? " style='height: 1.2em;'" : ""); // 1.2em - line-height
|
||||
$attrs .= " cols='30' rows='$rows'";
|
||||
}
|
||||
echo "<textarea$attrs>" . h($value) . '</textarea>';
|
||||
} elseif ($function == "json" || preg_match('~^jsonb?$~', $field["type"])) {
|
||||
|
@@ -1,2 +1,2 @@
|
||||
<?php
|
||||
$VERSION = "4.9";
|
||||
$VERSION = "4.9.2";
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Да',
|
||||
'No' => 'Не',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Da',
|
||||
'No' => 'Ne',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -346,4 +346,13 @@ $translations = array(
|
||||
'Type has been dropped.' => 'Typ byl odstraněn.',
|
||||
'Type has been created.' => 'Typ byl vytvořen.',
|
||||
'Alter type' => 'Pozměnit typ',
|
||||
|
||||
// Plugins
|
||||
'Columns' => 'Sloupce',
|
||||
'Nullable' => 'Povoleno null',
|
||||
'Default' => 'Výchozí',
|
||||
'Yes' => 'Ano',
|
||||
'No' => 'Ne',
|
||||
'One Time Password' => 'Jednorázové heslo',
|
||||
'Invalid OTP code.' => 'Neplatný kód OTP.',
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Ja',
|
||||
'No' => 'Nej',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Ja',
|
||||
'No' => 'Nein',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => 'Tuntematon virhe.',
|
||||
'Database does not support password.' => 'Tietokanta ei tue salasanaa.',
|
||||
'Disable %s or enable %s or %s extensions.' => 'Poista käytöstä %s tai ota käyttöön laajennus %s tai %s.',
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Kyllä',
|
||||
'No' => 'Ei',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Unknown error.' => 'Erreur inconnue',
|
||||
'Database does not support password.' => 'La base de données ne support pas les mots de passe',
|
||||
'Disable %s or enable %s or %s extensions.' => 'Désactiver %s ou activer %s or %s extensions.',
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Oui',
|
||||
'No' => 'Non',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Si',
|
||||
'No' => 'Non',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => 'Disabilita %s o abilita %s oppure %s estensioni.',
|
||||
'yes' => 'si',
|
||||
'no' => 'no',
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Si',
|
||||
'No' => 'No',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => 'გათიშეთ %s ან ჩართეთ %s ან %s გაფართოება.',
|
||||
|
||||
'overwrite' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -285,10 +285,10 @@ $translations = array(
|
||||
'Size' => 'Izmērs',
|
||||
'Compute' => 'Izskaitļot',
|
||||
'You are offline.' => 'Jūs est bezsasaistē.',
|
||||
'You have no privileges to update this table.' => 'jums nav pieejas labot šo tabulu.',
|
||||
'You have no privileges to update this table.' => 'Jums nav pieejas labot šo tabulu.',
|
||||
'Saving' => 'Saglabāšana',
|
||||
'yes' => 'Jā',
|
||||
'no' => 'Nē',
|
||||
'yes' => 'jā',
|
||||
'no' => 'nē',
|
||||
'Drop %s?' => 'Dzēst %s?',
|
||||
'overwrite' => 'pārrakstīt',
|
||||
'DB' => 'DB',
|
||||
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Database does not support password.' => 'Datubāze neatbalsta paroli.',
|
||||
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Jā',
|
||||
'No' => 'Nē',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Ya',
|
||||
'No' => 'Tidak',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => 'Schakel %s uit or schakel extensies %s of %s in.',
|
||||
'yes' => 'ja',
|
||||
'no' => 'neen',
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Ja',
|
||||
'No' => 'Neen',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Ja',
|
||||
'No' => 'Nei',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Tak',
|
||||
'No' => 'Nie',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
'HH:MM:SS' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
'HH:MM:SS' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -287,8 +287,8 @@ $translations = array(
|
||||
'You are offline.' => 'Вы не выполнили вход.',
|
||||
'You have no privileges to update this table.' => 'У вас нет прав на обновление этой таблицы.',
|
||||
'Saving' => 'Сохранение',
|
||||
'yes' => 'Да',
|
||||
'no' => 'Нет',
|
||||
'yes' => 'да',
|
||||
'no' => 'нет',
|
||||
'Drop %s?' => 'Удалить %s?',
|
||||
'overwrite' => 'перезаписать',
|
||||
'DB' => 'DB',
|
||||
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Database does not support password.' => 'База данных не поддерживает пароль.',
|
||||
|
||||
'Disable %s or enable %s or %s extensions.' => 'Отключите %s или включите расширения %s или %s.',
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Да',
|
||||
'No' => 'Нет',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -265,7 +265,6 @@ $translations = array(
|
||||
'Permanent link' => 'Permanentný odkaz',
|
||||
'Edit all' => 'Upraviť všetko',
|
||||
'HH:MM:SS' => 'HH:MM:SS',
|
||||
|
||||
'Drop %s?' => 'Odstrániť %s?',
|
||||
'Tables have been optimized.' => 'Tabuľky boli optimalizované.',
|
||||
'Materialized view' => 'Materializovaný pohľad',
|
||||
@@ -302,4 +301,11 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => 'Zakážte %s alebo povoľte rozšírenie %s alebo %s.',
|
||||
'yes' => 'áno',
|
||||
'no' => 'nie',
|
||||
'Yes' => 'Áno',
|
||||
'No' => 'Nie',
|
||||
'Columns' => 'Stĺpce',
|
||||
'Nullable' => 'Povolené null',
|
||||
'Default' => 'Predvolené',
|
||||
'One Time Password' => 'Jednorázové heslo',
|
||||
'Invalid OTP code.' => 'Neplatný kód OTP.',
|
||||
);
|
||||
|
@@ -344,4 +344,12 @@ $translations = array(
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
'HH:MM:SS' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Да',
|
||||
'No' => 'Не',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -346,4 +346,12 @@ $translations = array(
|
||||
'Type has been dropped.' => 'Typ har, typ, tagits bort.',
|
||||
'Type has been created.' => 'Typ har skapats.',
|
||||
'Alter type' => 'Ändra typ',
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Ja',
|
||||
'No' => 'Nej',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -302,4 +302,12 @@ $translations = array(
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
'yes' => null,
|
||||
'no' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Evet',
|
||||
'No' => 'Hayır',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -347,4 +347,12 @@ $translations = array(
|
||||
'Vacuum' => null,
|
||||
'%d / ' => array(),
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Так',
|
||||
'No' => 'Ні',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -346,4 +346,12 @@ $translations = array(
|
||||
'Unknown error.' => null,
|
||||
'Database does not support password.' => null,
|
||||
'Disable %s or enable %s or %s extensions.' => null,
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => 'Có',
|
||||
'No' => 'Không',
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -346,4 +346,13 @@ $translations = array(
|
||||
'Type has been dropped.' => 'Xx.',
|
||||
'Type has been created.' => 'Xx.',
|
||||
'Alter type' => 'Xx',
|
||||
|
||||
// Plugins
|
||||
'Columns' => 'Xx',
|
||||
'Nullable' => 'Xx',
|
||||
'Default' => 'Xx',
|
||||
'Yes' => 'Xx',
|
||||
'No' => 'Xx',
|
||||
'One Time Password' => 'Xx',
|
||||
'Invalid OTP code.' => 'Xx.',
|
||||
);
|
||||
|
@@ -346,4 +346,13 @@ $translations = array(
|
||||
'Type has been dropped.' => '已刪除類型。',
|
||||
'Type has been created.' => '已建立類型。',
|
||||
'Alter type' => '修改類型',
|
||||
|
||||
// Plugins
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -346,4 +346,12 @@ $translations = array(
|
||||
'Type has been dropped.' => '已删除类型。',
|
||||
'Type has been created.' => '已创建类型。',
|
||||
'Alter type' => '修改类型',
|
||||
|
||||
'Columns' => null,
|
||||
'Nullable' => null,
|
||||
'Default' => null,
|
||||
'Yes' => null,
|
||||
'No' => null,
|
||||
'One Time Password' => null,
|
||||
'Invalid OTP code.' => null,
|
||||
);
|
||||
|
@@ -123,7 +123,7 @@ if (!$error && $_POST) {
|
||||
|
||||
if ($connection->error) {
|
||||
echo ($_POST["only_errors"] ? $print : "");
|
||||
echo "<p class='error'>" . lang('Error in query') . ($connection->errno ? " ($connection->errno)" : "") . ": " . error() . "\n";
|
||||
echo "<p class='error'>" . lang('Error in query') . (!empty($connection->errno) ? " ($connection->errno)" : "") . ": " . error() . "\n";
|
||||
$errors[] = " <a href='#sql-$commands'>$commands</a>";
|
||||
if ($_POST["error_stops"]) {
|
||||
break 2;
|
||||
|
@@ -69,7 +69,7 @@ input.wayoff { left: -1000px; position: absolute; }
|
||||
#menu p, #logins, #tables { padding: .8em 1em; margin: 0; border-bottom: 1px solid #ccc; }
|
||||
#logins li, #tables li { list-style: none; }
|
||||
#dbs { overflow: hidden; }
|
||||
#logins, #tables { white-space: nowrap; overflow: auto; }
|
||||
#logins, #tables { white-space: nowrap; overflow: hidden; }
|
||||
#logins a, #tables a, #tables span { background: #fff; }
|
||||
#content { margin: 2em 0 0 21em; padding: 10px 20px 20px 0; }
|
||||
#lang { position: absolute; top: 0; left: 0; line-height: 1.8em; padding: .3em 1em; }
|
||||
|
@@ -54,7 +54,7 @@ function bodyLoad(version, maria) {
|
||||
function formField(form, name) {
|
||||
// required in IE < 8, form.elements[name] doesn't work
|
||||
for (var i=0; i < form.length; i++) {
|
||||
if (form[i].name == name) {
|
||||
if (form[i].name === name) {
|
||||
return form[i];
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ var dbPrevious = {};
|
||||
*/
|
||||
function dbMouseDown(event) {
|
||||
dbCtrl = isCtrl(event);
|
||||
if (dbPrevious[this.name] == undefined) {
|
||||
if (dbPrevious[this.name] === undefined) {
|
||||
dbPrevious[this.name] = this.value;
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ function dbChange() {
|
||||
}
|
||||
this.form.submit();
|
||||
this.form.target = '';
|
||||
if (dbCtrl && dbPrevious[this.name] != undefined) {
|
||||
if (dbCtrl && dbPrevious[this.name] !== undefined) {
|
||||
this.value = dbPrevious[this.name];
|
||||
dbPrevious[this.name] = undefined;
|
||||
}
|
||||
@@ -145,23 +145,23 @@ function selectFieldChange() {
|
||||
for (var i=0; i < selects.length; i++) {
|
||||
var select = selects[i];
|
||||
var col = selectValue(select);
|
||||
var match = /^(where.+)col\]/.exec(select.name);
|
||||
var match = /^(where.+)col]/.exec(select.name);
|
||||
if (match) {
|
||||
var op = selectValue(form[match[1] + 'op]']);
|
||||
var val = form[match[1] + 'val]'].value;
|
||||
if (col in indexColumns && (!/LIKE|REGEXP/.test(op) || (op == 'LIKE' && val.charAt(0) != '%'))) {
|
||||
if (col in indexColumns && (!/LIKE|REGEXP/.test(op) || (op === 'LIKE' && val.charAt(0) !== '%'))) {
|
||||
return true;
|
||||
} else if (col || val) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if ((match = /^(columns.+)fun\]/.exec(select.name))) {
|
||||
if ((match = /^(columns.+)fun]/.exec(select.name))) {
|
||||
if (/^(avg|count|count distinct|group_concat|max|min|sum)$/.test(col)) {
|
||||
group = true;
|
||||
}
|
||||
var val = selectValue(form[match[1] + 'col]']);
|
||||
if (val) {
|
||||
columns[col && col != 'count' ? '' : val] = 1;
|
||||
columns[col && col !== 'count' ? '' : val] = 1;
|
||||
}
|
||||
}
|
||||
if (col && /^order/.test(select.name)) {
|
||||
@@ -194,7 +194,7 @@ var added = '.', rowCount;
|
||||
* @return boolean
|
||||
*/
|
||||
function delimiterEqual(val, a, b) {
|
||||
return (val == a + '_' + b || val == a + b || val == a + b.charAt(0).toUpperCase() + b.substr(1));
|
||||
return (val === a + '_' + b || val === a + b || val === a + b.charAt(0).toUpperCase() + b.substr(1));
|
||||
}
|
||||
|
||||
/** Escape string to use as identifier
|
||||
@@ -255,7 +255,7 @@ function editingClick(event) {
|
||||
} else if (/^drop_col\[/.test(name)) {
|
||||
editingRemoveRow.call(el, 'fields\$1[field]');
|
||||
} else {
|
||||
if (name == 'auto_increment_col') {
|
||||
if (name === 'auto_increment_col') {
|
||||
var field = el.form['fields[' + el.value + '][field]'];
|
||||
if (!field.value) {
|
||||
field.value = 'id';
|
||||
@@ -273,7 +273,7 @@ function editingClick(event) {
|
||||
*/
|
||||
function editingInput(event) {
|
||||
var el = getTarget(event);
|
||||
if (/\[default\]$/.test(el.name)) {
|
||||
if (/\[default]$/.test(el.name)) {
|
||||
el.previousSibling.checked = true;
|
||||
}
|
||||
}
|
||||
@@ -290,7 +290,7 @@ function editingNameChange() {
|
||||
for (var i = opts.length; i--; ) {
|
||||
var match = /(.+)`(.+)/.exec(opts[i].value);
|
||||
if (!match) { // common type
|
||||
if (candidate && i == opts.length - 2 && val == opts[candidate].value.replace(/.+`/, '') && name == 'fields[1]') { // single target table, link to column, first field - probably `id`
|
||||
if (candidate && i === opts.length - 2 && val === opts[candidate].value.replace(/.+`/, '') && name === 'fields[1]') { // single target table, link to column, first field - probably `id`
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -300,7 +300,7 @@ function editingNameChange() {
|
||||
var tables = [ table, table.replace(/s$/, ''), table.replace(/es$/, '') ];
|
||||
for (var j=0; j < tables.length; j++) {
|
||||
table = tables[j];
|
||||
if (val == column || val == table || delimiterEqual(val, table, column) || delimiterEqual(val, column, table)) {
|
||||
if (val === column || val === table || delimiterEqual(val, table, column) || delimiterEqual(val, column, table)) {
|
||||
if (candidate) {
|
||||
return;
|
||||
}
|
||||
@@ -335,7 +335,7 @@ function editingAddRow(focus) {
|
||||
tags2 = qsa('input', row2);
|
||||
var input = tags2[0]; // IE loose tags2 after insertBefore()
|
||||
for (var i=0; i < tags.length; i++) {
|
||||
if (tags[i].name == 'auto_increment_col') {
|
||||
if (tags[i].name === 'auto_increment_col') {
|
||||
tags2[i].value = x;
|
||||
tags2[i].checked = false;
|
||||
}
|
||||
@@ -397,7 +397,7 @@ function editingTypeChange() {
|
||||
var text = selectValue(type);
|
||||
for (var i=0; i < type.form.elements.length; i++) {
|
||||
var el = type.form.elements[i];
|
||||
if (el.name == name + '[length]') {
|
||||
if (el.name === name + '[length]') {
|
||||
if (!(
|
||||
(/(char|binary)$/.test(lastType) && /(char|binary)$/.test(text))
|
||||
|| (/(enum|set)$/.test(lastType) && /(enum|set)$/.test(text))
|
||||
@@ -406,19 +406,19 @@ function editingTypeChange() {
|
||||
}
|
||||
el.oninput.apply(el);
|
||||
}
|
||||
if (lastType == 'timestamp' && el.name == name + '[has_default]' && /timestamp/i.test(formField(type.form, name + '[default]').value)) {
|
||||
if (lastType === 'timestamp' && el.name == name + '[has_default]' && /timestamp/i.test(formField(type.form, name + '[default]').value)) {
|
||||
el.checked = false;
|
||||
}
|
||||
if (el.name == name + '[collation]') {
|
||||
if (el.name === name + '[collation]') {
|
||||
alterClass(el, 'hidden', !/(char|text|enum|set)$/.test(text));
|
||||
}
|
||||
if (el.name == name + '[unsigned]') {
|
||||
if (el.name === name + '[unsigned]') {
|
||||
alterClass(el, 'hidden', !/(^|[^o])int(?!er)|numeric|real|float|double|decimal|money/.test(text));
|
||||
}
|
||||
if (el.name == name + '[on_update]') {
|
||||
if (el.name === name + '[on_update]') {
|
||||
alterClass(el, 'hidden', !/timestamp|datetime/.test(text)); // MySQL supports datetime since 5.6.5
|
||||
}
|
||||
if (el.name == name + '[on_delete]') {
|
||||
if (el.name === name + '[on_delete]') {
|
||||
alterClass(el, 'hidden', !/`/.test(text));
|
||||
}
|
||||
}
|
||||
@@ -457,13 +457,13 @@ function enumValues(s) {
|
||||
var offset = 0;
|
||||
var match;
|
||||
while (match = re.exec(s)) {
|
||||
if (offset != match.index) {
|
||||
if (offset !== match.index) {
|
||||
break;
|
||||
}
|
||||
result.push(match[2].replace(/'(')|\\(.)/g, '$1$2'));
|
||||
offset += match[0].length;
|
||||
}
|
||||
return (offset == s.length ? result.join('\n') : s);
|
||||
return (offset === s.length ? result.join('\n') : s);
|
||||
}
|
||||
|
||||
/** Finish editing of enum or set
|
||||
@@ -531,7 +531,7 @@ function dumpClick(event) {
|
||||
var el = parentTag(getTarget(event), 'label');
|
||||
if (el) {
|
||||
el = qs('input', el);
|
||||
var match = /(.+)\[\]$/.exec(el.name);
|
||||
var match = /(.+)\[]$/.exec(el.name);
|
||||
if (match) {
|
||||
checkboxClick.call(el, event);
|
||||
formUncheck('check-' + match[1]);
|
||||
@@ -549,7 +549,7 @@ function foreignAddRow() {
|
||||
this.onchange = function () { };
|
||||
var selects = qsa('select', row);
|
||||
for (var i=0; i < selects.length; i++) {
|
||||
selects[i].name = selects[i].name.replace(/\]/, '1$&');
|
||||
selects[i].name = selects[i].name.replace(']', '1]');
|
||||
selects[i].selectedIndex = 0;
|
||||
}
|
||||
parentTag(this, 'table').appendChild(row);
|
||||
@@ -585,7 +585,7 @@ function indexesChangeColumn(prefix) {
|
||||
for (var tag in { 'select': 1, 'input': 1 }) {
|
||||
var columns = qsa(tag, parentTag(this, 'td'));
|
||||
for (var i=0; i < columns.length; i++) {
|
||||
if (/\[columns\]/.test(columns[i].name)) {
|
||||
if (/\[columns]/.test(columns[i].name)) {
|
||||
var value = selectValue(columns[i]);
|
||||
if (value) {
|
||||
names.push(value);
|
||||
@@ -593,7 +593,7 @@ function indexesChangeColumn(prefix) {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.form[this.name.replace(/\].*/, '][name]')].value = prefix + names.join('_');
|
||||
this.form[this.name.replace(/].*/, '][name]')].value = prefix + names.join('_');
|
||||
}
|
||||
|
||||
/** Add column for index
|
||||
@@ -602,9 +602,9 @@ function indexesChangeColumn(prefix) {
|
||||
*/
|
||||
function indexesAddColumn(prefix) {
|
||||
var field = this;
|
||||
var select = field.form[field.name.replace(/\].*/, '][type]')];
|
||||
var select = field.form[field.name.replace(/].*/, '][type]')];
|
||||
if (!select.selectedIndex) {
|
||||
while (selectValue(select) != "INDEX" && select.selectedIndex < select.options.length) {
|
||||
while (selectValue(select) !== "INDEX" && select.selectedIndex < select.options.length) {
|
||||
select.selectedIndex++;
|
||||
}
|
||||
select.onchange();
|
||||
@@ -613,15 +613,15 @@ function indexesAddColumn(prefix) {
|
||||
var selects = qsa('select', column);
|
||||
for (var i = 0; i < selects.length; i++) {
|
||||
select = selects[i];
|
||||
select.name = select.name.replace(/\]\[\d+/, '$&1');
|
||||
select.name = select.name.replace(/]\[\d+/, '$&1');
|
||||
select.selectedIndex = 0;
|
||||
}
|
||||
field.onchange = partial(indexesChangeColumn, prefix);
|
||||
var inputs = qsa('input', column);
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
var input = inputs[i];
|
||||
input.name = input.name.replace(/\]\[\d+/, '$&1');
|
||||
if (input.type != 'checkbox') {
|
||||
input.name = input.name.replace(/]\[\d+/, '$&1');
|
||||
if (input.type !== 'checkbox') {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
@@ -670,7 +670,7 @@ var that, x, y; // em and tablePos defined in schema.inc.php
|
||||
* @this HTMLElement
|
||||
*/
|
||||
function schemaMousedown(event) {
|
||||
if ((event.which ? event.which : event.button) == 1) {
|
||||
if ((event.which ? event.which : event.button) === 1) {
|
||||
that = this;
|
||||
x = event.clientX - this.offsetLeft;
|
||||
y = event.clientY - this.offsetTop;
|
||||
@@ -687,12 +687,12 @@ function schemaMousemove(event) {
|
||||
var divs = qsa('div', that);
|
||||
var lineSet = { };
|
||||
for (var i=0; i < divs.length; i++) {
|
||||
if (divs[i].className == 'references') {
|
||||
if (divs[i].className === 'references') {
|
||||
var div2 = qs('[id="' + (/^refs/.test(divs[i].id) ? 'refd' : 'refs') + divs[i].id.substr(4) + '"]');
|
||||
var ref = (tablePos[divs[i].title] ? tablePos[divs[i].title] : [ div2.parentNode.offsetTop / em, 0 ]);
|
||||
var left1 = -1;
|
||||
var id = divs[i].id.replace(/^ref.(.+)-.+/, '$1');
|
||||
if (divs[i].parentNode != div2.parentNode) {
|
||||
if (divs[i].parentNode !== div2.parentNode) {
|
||||
left1 = Math.min(0, ref[1] - left) - 1;
|
||||
divs[i].style.left = left1 + 'em';
|
||||
divs[i].querySelector('div').style.width = -left1 + 'em';
|
||||
@@ -704,7 +704,7 @@ function schemaMousemove(event) {
|
||||
var line = qs('[id="' + divs[i].id.replace(/^....(.+)-.+$/, 'refl$1') + '"]');
|
||||
var top1 = top + divs[i].offsetTop / em;
|
||||
var top2 = top + div2.offsetTop / em;
|
||||
if (divs[i].parentNode != div2.parentNode) {
|
||||
if (divs[i].parentNode !== div2.parentNode) {
|
||||
top2 += ref[0] - top;
|
||||
line.querySelector('div').style.height = Math.abs(top1 - top2) + 'em';
|
||||
}
|
||||
@@ -752,7 +752,7 @@ function helpMouseover(event, text, side) {
|
||||
var target = getTarget(event);
|
||||
if (!text) {
|
||||
helpClose();
|
||||
} else if (window.jush && (!helpIgnore || this != target)) {
|
||||
} else if (window.jush && (!helpIgnore || this !== target)) {
|
||||
helpOpen = 1;
|
||||
var help = qs('#help');
|
||||
help.innerHTML = text;
|
||||
@@ -771,7 +771,7 @@ function helpMouseover(event, text, side) {
|
||||
*/
|
||||
function helpMouseout(event) {
|
||||
helpOpen = 0;
|
||||
helpIgnore = (this != getTarget(event));
|
||||
helpIgnore = (this !== getTarget(event));
|
||||
setTimeout(function () {
|
||||
if (!helpOpen) {
|
||||
helpClose();
|
||||
|
@@ -4,7 +4,7 @@
|
||||
* @param [HTMLElement] defaults to document
|
||||
* @return HTMLElement
|
||||
*/
|
||||
function qs(selector, context) {
|
||||
function qs(selector, context = null) {
|
||||
return (context || document).querySelector(selector);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ function qs(selector, context) {
|
||||
* @param [HTMLElement] defaults to document
|
||||
* @return HTMLElement
|
||||
*/
|
||||
function qsl(selector, context) {
|
||||
function qsl(selector, context = null) {
|
||||
var els = qsa(selector, context);
|
||||
return els[els.length - 1];
|
||||
}
|
||||
@@ -23,7 +23,7 @@ function qsl(selector, context) {
|
||||
* @param [HTMLElement] defaults to document
|
||||
* @return NodeList
|
||||
*/
|
||||
function qsa(selector, context) {
|
||||
function qsa(selector, context = null) {
|
||||
return (context || document).querySelectorAll(selector);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ function alterClass(el, className, enable) {
|
||||
*/
|
||||
function toggle(id) {
|
||||
var el = qs('#' + id);
|
||||
el.className = (el.className == 'hidden' ? '' : 'hidden');
|
||||
el.className = (el.className === 'hidden' ? '' : 'hidden');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ function verifyVersion(current, url, token) {
|
||||
if (window.postMessage && window.addEventListener) {
|
||||
iframe.style.display = 'none';
|
||||
addEventListener('message', function (event) {
|
||||
if (event.origin == 'https://www.adminer.org') {
|
||||
if (event.origin === 'https://www.adminer.org') {
|
||||
var match = /version=(.+)/.exec(event.data);
|
||||
if (match) {
|
||||
cookie('adminer_version=' + match[1], 1);
|
||||
@@ -139,7 +139,7 @@ function selectValue(select) {
|
||||
/** Verify if element has a specified tag name
|
||||
* @param HTMLElement
|
||||
* @param string regular expression
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
function isTag(el, tag) {
|
||||
var re = new RegExp('^(' + tag + ')$', 'i');
|
||||
@@ -181,8 +181,8 @@ function selectCount(id, count) {
|
||||
var inputs = qsa('input', el.parentNode.parentNode);
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
var input = inputs[i];
|
||||
if (input.type == 'submit') {
|
||||
input.disabled = (count == '0');
|
||||
if (input.type === 'submit') {
|
||||
input.disabled = (count === '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +252,7 @@ function tableClick(event, click) {
|
||||
var el = getTarget(event);
|
||||
while (!isTag(el, 'tr')) {
|
||||
if (isTag(el, 'table|a|input|textarea')) {
|
||||
if (el.type != 'checkbox') {
|
||||
if (el.type !== 'checkbox') {
|
||||
return;
|
||||
}
|
||||
checkboxClick.call(el, event);
|
||||
@@ -268,7 +268,7 @@ function tableClick(event, click) {
|
||||
el.checked = !el.checked;
|
||||
el.onclick && el.onclick();
|
||||
}
|
||||
if (el.name == 'check[]') {
|
||||
if (el.name === 'check[]') {
|
||||
el.form['all'].checked = false;
|
||||
formUncheck('all-page');
|
||||
}
|
||||
@@ -288,7 +288,7 @@ function checkboxClick(event) {
|
||||
if (!this.name) {
|
||||
return;
|
||||
}
|
||||
if (event.shiftKey && (!lastChecked || lastChecked.name == this.name)) {
|
||||
if (event.shiftKey && (!lastChecked || lastChecked.name === this.name)) {
|
||||
var checked = (lastChecked ? lastChecked.checked : true);
|
||||
var inputs = qsa('input', parentTag(this, 'table'));
|
||||
var checking = !lastChecked;
|
||||
@@ -333,7 +333,7 @@ function setHtml(id, html) {
|
||||
*/
|
||||
function nodePosition(el) {
|
||||
var pos = 0;
|
||||
while (el = el.previousSibling) {
|
||||
while ((el = el.previousSibling)) {
|
||||
pos++;
|
||||
}
|
||||
return pos;
|
||||
@@ -345,7 +345,7 @@ function nodePosition(el) {
|
||||
*/
|
||||
function pageClick(href, page) {
|
||||
if (!isNaN(page) && page) {
|
||||
location.href = href + (page != 1 ? '&page=' + (page - 1) : '');
|
||||
location.href = href + (page !== 1 ? '&page=' + (page - 1) : '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ function menuOver(event) {
|
||||
* @this HTMLElement
|
||||
*/
|
||||
function menuOut() {
|
||||
this.style.overflow = 'auto';
|
||||
this.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
|
||||
@@ -388,7 +388,7 @@ function selectAddRow() {
|
||||
for (var i=0; i < inputs.length; i++) {
|
||||
inputs[i].name = inputs[i].name.replace(/[a-z]\[\d+/, '$&1');
|
||||
inputs[i].className = '';
|
||||
if (inputs[i].type == 'checkbox') {
|
||||
if (inputs[i].type === 'checkbox') {
|
||||
inputs[i].checked = false;
|
||||
} else {
|
||||
inputs[i].value = '';
|
||||
@@ -402,7 +402,7 @@ function selectAddRow() {
|
||||
* @this HTMLInputElement
|
||||
*/
|
||||
function selectSearchKeydown(event) {
|
||||
if (event.keyCode == 13 || event.keyCode == 10) {
|
||||
if (event.keyCode === 13 || event.keyCode === 10) {
|
||||
this.onsearch = function () {
|
||||
};
|
||||
}
|
||||
@@ -445,11 +445,11 @@ function selectSearch(name) {
|
||||
for (var i=0; i < divs.length; i++) {
|
||||
var div = divs[i];
|
||||
var el = qs('[name$="[col]"]', div);
|
||||
if (el && selectValue(el) == name) {
|
||||
if (el && selectValue(el) === name) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == divs.length) {
|
||||
if (i === divs.length) {
|
||||
div.firstChild.value = name;
|
||||
div.firstChild.onchange();
|
||||
}
|
||||
@@ -487,7 +487,7 @@ function bodyKeydown(event, button) {
|
||||
if (target.jushTextarea) {
|
||||
target = target.jushTextarea;
|
||||
}
|
||||
if (isCtrl(event) && (event.keyCode == 13 || event.keyCode == 10) && isTag(target, 'select|textarea|input')) { // 13|10 - Enter
|
||||
if (isCtrl(event) && (event.keyCode === 13 || event.keyCode === 10) && isTag(target, 'select|textarea|input')) { // 13|10 - Enter
|
||||
target.blur();
|
||||
if (button) {
|
||||
target.form[button].click();
|
||||
@@ -508,7 +508,7 @@ function bodyKeydown(event, button) {
|
||||
*/
|
||||
function bodyClick(event) {
|
||||
var target = getTarget(event);
|
||||
if ((isCtrl(event) || event.shiftKey) && target.type == 'submit' && isTag(target, 'input')) {
|
||||
if ((isCtrl(event) || event.shiftKey) && target.type === 'submit' && isTag(target, 'input')) {
|
||||
target.form.target = '_blank';
|
||||
setTimeout(function () {
|
||||
// if (isCtrl(event)) { focus(); } doesn't work
|
||||
@@ -524,9 +524,9 @@ function bodyClick(event) {
|
||||
* @return boolean
|
||||
*/
|
||||
function editingKeydown(event) {
|
||||
if ((event.keyCode == 40 || event.keyCode == 38) && isCtrl(event)) { // 40 - Down, 38 - Up
|
||||
if ((event.keyCode === 40 || event.keyCode === 38) && isCtrl(event)) { // 40 - Down, 38 - Up
|
||||
var target = getTarget(event);
|
||||
var sibling = (event.keyCode == 40 ? 'nextSibling' : 'previousSibling');
|
||||
var sibling = (event.keyCode === 40 ? 'nextSibling' : 'previousSibling');
|
||||
var el = target.parentNode.parentNode[sibling];
|
||||
if (el && (isTag(el, 'tr') || (el = el[sibling])) && isTag(el, 'tr') && (el = el.childNodes[nodePosition(target.parentNode)]) && (el = el.childNodes[nodePosition(target)])) {
|
||||
el.focus();
|
||||
@@ -614,7 +614,7 @@ function ajax(url, callback, data, message) {
|
||||
}
|
||||
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
if (request.readyState === 4) {
|
||||
if (/^2/.test(request.status)) {
|
||||
callback(request);
|
||||
} else {
|
||||
@@ -656,7 +656,7 @@ function ajaxForm(form, message, button) {
|
||||
if (/^file$/i.test(el.type) && el.value) {
|
||||
return false;
|
||||
}
|
||||
if (!/^(checkbox|radio|submit|file)$/i.test(el.type) || el.checked || el == button) {
|
||||
if (!/^(checkbox|radio|submit|file)$/i.test(el.type) || el.checked || el === button) {
|
||||
data.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(isTag(el, 'select') ? selectValue(el) : el.value));
|
||||
}
|
||||
}
|
||||
@@ -703,7 +703,7 @@ function selectClick(event, text, warning) {
|
||||
if (!event) {
|
||||
event = window.event;
|
||||
}
|
||||
if (event.keyCode == 27 && !event.shiftKey && !event.altKey && !isCtrl(event)) { // 27 - Esc
|
||||
if (event.keyCode === 27 && !event.shiftKey && !event.altKey && !isCtrl(event)) { // 27 - Esc
|
||||
inputBlur.apply(input);
|
||||
td.innerHTML = original;
|
||||
}
|
||||
@@ -733,7 +733,7 @@ function selectClick(event, text, warning) {
|
||||
td.appendChild(input);
|
||||
setupSubmitHighlight(td);
|
||||
input.focus();
|
||||
if (text == 2) { // long text
|
||||
if (text === 2) { // long text
|
||||
return ajax(location.href + '&' + encodeURIComponent(td.id) + '=', function (request) {
|
||||
if (request.responseText) {
|
||||
input.value = request.responseText;
|
||||
@@ -855,7 +855,7 @@ function findDefaultSubmit(el) {
|
||||
var inputs = qsa('input', el.form);
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
var input = inputs[i];
|
||||
if (input.type == 'submit' && !input.style.zIndex) {
|
||||
if (input.type === 'submit' && !input.style.zIndex) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
28
changes.txt
28
changes.txt
@@ -1,3 +1,31 @@
|
||||
Adminer 4.9.2 (released 2024-09-18):
|
||||
- Fix textarea height for single-line inputs (used typically for SQLite text field).
|
||||
- Fix undefined property in error message if driver does not support error number (e.g. PostgreSQL).
|
||||
- PostgreSQL: Fix search fields configuration (regression from 4.9).
|
||||
- PostgreSQL: Fix search condition for network address types, add macaddr8 type.
|
||||
- PostgreSQL: Fix exporting CREATE TABLE query with GENERATED default values.
|
||||
- PostgreSQL: Fix exporting CREATE TABLE query with sequence default value.
|
||||
- PostgreSQL: Allow to set connection's sslmode with AdminerLoginSsl plugin.
|
||||
- MySQL: Do not show 'empty' enum value in strict mode.
|
||||
- Editor: Fix searching in tables.
|
||||
- Function to retrieve driver name that can be used in plugins.
|
||||
|
||||
Adminer 4.9.1 (released 2024-09-09):
|
||||
- Compatibility with PHP 8.3.
|
||||
- Fix compiling jush external files.
|
||||
- Improved displaying of long table names in menu.
|
||||
- Replace deprecated <acronym> with <abbr>.
|
||||
- Add support for translations in plugins.
|
||||
- Add .editorconfig file.
|
||||
- MySQL: Add unix_timestamp to functions.
|
||||
- PostgreSQL: Show only accessible databases.
|
||||
- PostgreSQL: Make data length calculation more accurate.
|
||||
- PostgreSQL: Fix documentation link for SERIAL type.
|
||||
- PostgreSQL: Fix undefined properties on PHP 8.
|
||||
- Elasticsearch: Fix field selection.
|
||||
- AdminerEditForeign: Refactor and fix the plugin.
|
||||
- AdminerLoginOtp: Autocomplete hints for OTP input field, code refactoring.
|
||||
|
||||
Adminer 4.9 (released 2024-08-19):
|
||||
- Validate server input in login form.
|
||||
- Validate connection to server in HTTP based drivers.
|
||||
|
10
compile.php
10
compile.php
@@ -418,7 +418,7 @@ if ($driver) {
|
||||
if (count($drivers) == 1) {
|
||||
$file = str_replace('<?php echo html_select("auth[driver]", $drivers, DRIVER) . "\n"; ?>', "<input type='hidden' name='auth[driver]' value='" . ($driver == "mysql" ? "server" : $driver) . "'>" . reset($drivers), $file);
|
||||
}
|
||||
$file = preg_replace('(;../vendor/vrana/jush/modules/jush-(?!textarea\.|txt\.|js\.|' . preg_quote($driver == "mysql" ? "sql" : $driver) . '\.)[^.]+.js)', '', $file);
|
||||
$file = preg_replace('(;\.\./vendor/vrana/jush/modules/jush-(?!textarea\.|txt\.|js\.|' . preg_quote($driver == "mysql" ? "sql" : $driver) . '\.)[^.]+.js)', '', $file);
|
||||
$file = preg_replace_callback('~doc_link\(array\((.*)\)\)~sU', function ($match) use ($driver) {
|
||||
list(, $links) = $match;
|
||||
$links = preg_replace("~'(?!(" . ($driver == "mysql" ? "sql|mariadb" : $driver) . ")')[^']*' => [^,]*,?~", '', $links);
|
||||
@@ -427,8 +427,8 @@ if ($driver) {
|
||||
//! strip doc_link() definition
|
||||
}
|
||||
if ($project == "editor") {
|
||||
$file = preg_replace('~;.\.\/externals/jush/jush\.css~', '', $file);
|
||||
$file = preg_replace('~compile_file\(\'\.\./(externals/jush/modules/jush\.js|adminer/static/[^.]+\.gif)[^)]+\)~', "''", $file);
|
||||
$file = preg_replace('~;\.\./vendor/vrana/jush/jush\.css~', '', $file);
|
||||
$file = preg_replace('~compile_file\(\'\.\./(vendor/vrana/jush/modules/jush\.js|adminer/static/[^.]+\.gif)[^)]+\)~', "''", $file);
|
||||
}
|
||||
$file = preg_replace_callback("~lang\\('((?:[^\\\\']+|\\\\.)*)'([,)])~s", 'lang_ids', $file);
|
||||
$file = preg_replace_callback('~\b(include|require) "([^"]*\$LANG.inc.php)";~', 'put_file_lang', $file);
|
||||
@@ -440,14 +440,14 @@ if ($_SESSION["lang"]) {
|
||||
$file = str_replace('<?php echo $LANG; ?>', $_SESSION["lang"], $file);
|
||||
}
|
||||
$file = str_replace('<?php echo script_src("static/editing.js"); ?>' . "\n", "", $file);
|
||||
$file = preg_replace('~\s+echo script_src\("\.\./externals/jush/modules/jush-(textarea|txt|js|\$jush)\.js"\);~', '', $file);
|
||||
$file = preg_replace('~\s+echo script_src\("\.\./vendor/vrana/jush/modules/jush-(textarea|txt|js|\$jush)\.js"\);~', '', $file);
|
||||
$file = str_replace('<link rel="stylesheet" type="text/css" href="../vendor/vrana/jush/jush.css">' . "\n", "", $file);
|
||||
$file = preg_replace_callback("~compile_file\\('([^']+)'(?:, '([^']*)')?\\)~", 'compile_file', $file); // integrate static files
|
||||
$replace = 'preg_replace("~\\\\\\\\?.*~", "", ME) . "?file=\1&version=' . substr(md5(microtime()), 0, 8) . '"';
|
||||
$file = preg_replace('~\.\./adminer/static/(default\.css|favicon\.ico)~', '<?php echo h(' . $replace . '); ?>', $file);
|
||||
$file = preg_replace('~"\.\./adminer/static/(functions\.js)"~', $replace, $file);
|
||||
$file = preg_replace('~\.\./adminer/static/([^\'"]*)~', '" . h(' . $replace . ') . "', $file);
|
||||
$file = preg_replace('~"\.\./externals/jush/modules/(jush\.js)"~', $replace, $file);
|
||||
$file = preg_replace('~"\.\./vendor/vrana/jush/modules/(jush\.js)"~', $replace, $file);
|
||||
$file = preg_replace("~<\\?php\\s*\\?>\n?|\\?>\n?<\\?php~", '', $file);
|
||||
$file = php_shrink($file);
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
"GPL-2.0-only"
|
||||
],
|
||||
"require": {
|
||||
"php": "5.6 - 8.1",
|
||||
"php": "5.6 - 8.3",
|
||||
"ext-pdo": "*",
|
||||
"ext-json": "*",
|
||||
"vrana/jush": "@dev",
|
||||
|
@@ -374,7 +374,7 @@ thead td, thead th {
|
||||
padding: 7px 2px;
|
||||
}
|
||||
|
||||
thead td acronym, thead td sup, thead th acronym, thead th sup {
|
||||
thead td abbr, thead td sup, thead th acronym, thead th sup {
|
||||
color: #cdf
|
||||
}
|
||||
|
||||
|
@@ -136,7 +136,7 @@ thead th, thead td {
|
||||
color:#FFFFFF;
|
||||
padding-right:10px;
|
||||
}
|
||||
thead th acronym, thead td acronym, thead th sup, thead td sup{
|
||||
thead th abbr, thead td acronym, thead th sup, thead td sup{
|
||||
color:#CCDDFF;
|
||||
}
|
||||
|
||||
|
@@ -342,35 +342,44 @@ ORDER BY ORDINAL_POSITION", null, "") as $row) { //! requires MySQL 5
|
||||
|
||||
function selectSearchProcess($fields, $indexes) {
|
||||
global $driver;
|
||||
$return = array();
|
||||
|
||||
$return = [];
|
||||
|
||||
foreach ((array) $_GET["where"] as $key => $where) {
|
||||
$col = $where["col"];
|
||||
$op = $where["op"];
|
||||
$val = $where["val"];
|
||||
|
||||
if (($key < 0 ? "" : $col) . $val != "") {
|
||||
$conds = array();
|
||||
|
||||
foreach (($col != "" ? array($col => $fields[$col]) : $fields) as $name => $field) {
|
||||
if ($col != "" || is_numeric($val) || !preg_match(number_type(), $field["type"])) {
|
||||
$name = idf_escape($name);
|
||||
|
||||
if ($col != "" && $field["type"] == "enum") {
|
||||
$conds[] = (in_array(0, $val) ? "$name IS NULL OR " : "") . "$name IN (" . implode(", ", array_map('intval', $val)) . ")";
|
||||
} else {
|
||||
$text_type = preg_match('~char|text|enum|set~', $field["type"]);
|
||||
$value = $this->processInput($field, (!$op && $text_type && preg_match('~^[^%]+$~', $val) ? "%$val%" : $val));
|
||||
$conds[] = $driver->convertSearch($name, $val, $field) . ($value == "NULL" ? " IS" . ($op == ">=" ? " NOT" : "") . " $value"
|
||||
|
||||
$conds[] = $driver->convertSearch($name, $where, $field) . ($value == "NULL" ? " IS" . ($op == ">=" ? " NOT" : "") . " $value"
|
||||
: (in_array($op, $this->operators) || $op == "=" ? " $op $value"
|
||||
: ($text_type ? " LIKE $value"
|
||||
: " IN (" . str_replace(",", "', '", $value) . ")"
|
||||
)));
|
||||
|
||||
if ($key < 0 && $val == "0") {
|
||||
$conds[] = "$name IS NULL";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$return[] = ($conds ? "(" . implode(" OR ", $conds) . ")" : "1 = 0");
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
6
lang.php
6
lang.php
@@ -2,7 +2,7 @@
|
||||
<?php
|
||||
error_reporting(6135); // errors and warnings
|
||||
unset($_COOKIE["adminer_lang"]);
|
||||
$_SESSION["lang"] = $_SERVER["argv"][1]; // Adminer functions read language from session
|
||||
$_SESSION["lang"] = isset($_SERVER["argv"][1]) ? $_SERVER["argv"][1] : null; // Adminer functions read language from session
|
||||
if (isset($_SESSION["lang"])) {
|
||||
include dirname(__FILE__) . "/adminer/include/lang.inc.php";
|
||||
if (isset($_SERVER["argv"][2]) || (!isset($langs[$_SESSION["lang"]]) && $_SESSION["lang"] != "xx")) {
|
||||
@@ -17,7 +17,9 @@ foreach (array_merge(
|
||||
glob(dirname(__FILE__) . "/adminer/include/*.php"),
|
||||
glob(dirname(__FILE__) . "/adminer/drivers/*.php"),
|
||||
glob(dirname(__FILE__) . "/editor/*.php"),
|
||||
glob(dirname(__FILE__) . "/editor/include/*.php")
|
||||
glob(dirname(__FILE__) . "/editor/include/*.php"),
|
||||
glob(dirname(__FILE__) . "/plugins/*.php"),
|
||||
glob(dirname(__FILE__) . "/plugins/drivers/*.php")
|
||||
) as $filename) {
|
||||
$file = file_get_contents($filename);
|
||||
if (preg_match_all("~lang\\(('(?:[^\\\\']+|\\\\.)*')([),])~", $file, $matches)) { // lang() always uses apostrophes
|
||||
|
@@ -133,7 +133,7 @@ if (isset($_GET["elastic"])) {
|
||||
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
|
||||
$data = array();
|
||||
if ($select != array("*")) {
|
||||
$data["fields"] = $select;
|
||||
$data["fields"] = array_values($select);
|
||||
}
|
||||
|
||||
if ($order) {
|
||||
|
@@ -132,7 +132,7 @@ if (isset($_GET["elastic5"])) {
|
||||
function select($table, $select, $where, $group, $order = array(), $limit = 1, $page = 0, $print = false) {
|
||||
$data = array();
|
||||
if ($select != array("*")) {
|
||||
$data["fields"] = $select;
|
||||
$data["fields"] = array_values($select);
|
||||
}
|
||||
|
||||
if ($order) {
|
||||
|
@@ -1,43 +1,75 @@
|
||||
<?php
|
||||
|
||||
/** Select foreign key in edit form
|
||||
* @link https://www.adminer.org/plugins/#use
|
||||
* @author Jakub Vrana, https://www.vrana.cz/
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
||||
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
||||
*/
|
||||
class AdminerEditForeign {
|
||||
var $_limit;
|
||||
* @link https://www.adminer.org/plugins/#use
|
||||
* @author Jakub Vrana, https://www.vrana.cz/
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
||||
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
||||
*/
|
||||
class AdminerEditForeign
|
||||
{
|
||||
private $limit;
|
||||
private $foreignTables = [];
|
||||
private $foreignOptions = [];
|
||||
|
||||
function __construct($limit = 0) {
|
||||
$this->_limit = $limit;
|
||||
/**
|
||||
* @param int $limit
|
||||
*/
|
||||
function __construct($limit = 0)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
function editInput($table, $field, $attrs, $value) {
|
||||
static $foreignTables = array();
|
||||
static $values = array();
|
||||
$foreignKeys = &$foreignTables[$table];
|
||||
if ($foreignKeys === null) {
|
||||
$foreignKeys = column_foreign_keys($table);
|
||||
/**
|
||||
* @param string $table
|
||||
* @param array $field
|
||||
* @param string $attrs
|
||||
* @param string|null $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function editInput($table, array $field, $attrs, $value)
|
||||
{
|
||||
if (!isset($this->foreignTables[$table])) {
|
||||
$this->foreignTables[$table] = column_foreign_keys($table);
|
||||
}
|
||||
foreach ((array) $foreignKeys[$field["field"]] as $foreignKey) {
|
||||
if (count($foreignKey["source"]) == 1) {
|
||||
$target = $foreignKey["table"];
|
||||
$id = $foreignKey["target"][0];
|
||||
$options = &$values[$target][$id];
|
||||
if (!$options) {
|
||||
$column = idf_escape($id);
|
||||
if (preg_match('~binary~', $field["type"])) {
|
||||
$column = "HEX($column)";
|
||||
}
|
||||
$options = array("" => "") + get_vals("SELECT $column FROM " . table($target) . " ORDER BY 1" . ($this->_limit ? " LIMIT " . ($this->_limit + 1) : ""));
|
||||
if ($this->_limit && count($options) - 1 > $this->_limit) {
|
||||
return;
|
||||
}
|
||||
$foreignKeys = $this->foreignTables[$table];
|
||||
|
||||
if (empty($foreignKeys[$field["field"]])) {
|
||||
return "";
|
||||
}
|
||||
|
||||
foreach ($foreignKeys[$field["field"]] as $foreignKey) {
|
||||
if (count($foreignKey["source"]) != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$target = $foreignKey["table"];
|
||||
$id = $foreignKey["target"][0];
|
||||
|
||||
if (!isset($this->foreignOptions[$target][$id])) {
|
||||
$column = idf_escape($id);
|
||||
if (preg_match('~binary~', $field["type"])) {
|
||||
$column = "HEX($column)";
|
||||
}
|
||||
|
||||
$values = get_vals("SELECT $column FROM " . table($target) . " ORDER BY 1" .
|
||||
($this->limit ? " LIMIT " . ($this->limit + 1) : ""));
|
||||
|
||||
if ($this->limit && count($values) > $this->limit) {
|
||||
$this->foreignOptions[$target][$id] = false;
|
||||
} else {
|
||||
$this->foreignOptions[$target][$id] = ["" => ""] + $values;
|
||||
}
|
||||
}
|
||||
|
||||
if ($options = $this->foreignOptions[$target][$id]) {
|
||||
return "<select$attrs>" . optionlist($options, $value) . "</select>";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ class AdminerEditTextarea {
|
||||
|
||||
function editInput($table, $field, $attrs, $value) {
|
||||
if (preg_match('~char~', $field["type"])) {
|
||||
return "<textarea cols='30' rows='1' style='height: 1.2em;'$attrs>" . h($value) . '</textarea>';
|
||||
return "<textarea cols='30' rows='1' $attrs>" . h($value) . '</textarea>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,9 @@ class AdminerEnumOption {
|
||||
$selected = "";
|
||||
}
|
||||
}
|
||||
$options[0] = lang('empty');
|
||||
if (!is_strict_mode()) {
|
||||
$options[0] = lang('empty');
|
||||
}
|
||||
preg_match_all("~'((?:[^']|'')*)'~", $field["length"], $matches);
|
||||
foreach ($matches[1] as $i => $val) {
|
||||
$val = stripcslashes(str_replace("''", "'", $val));
|
||||
|
@@ -1,54 +1,79 @@
|
||||
<?php
|
||||
|
||||
/** Require One-Time Password at login
|
||||
* @link https://www.adminer.org/plugins/otp/
|
||||
* @author Jakub Vrana, https://www.vrana.cz/
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
||||
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
||||
*/
|
||||
class AdminerLoginOtp {
|
||||
/** @access protected */
|
||||
var $secret;
|
||||
* @link https://www.adminer.org/plugins/otp/
|
||||
* @author Jakub Vrana, https://www.vrana.cz/
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
||||
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
||||
*/
|
||||
class AdminerLoginOtp
|
||||
{
|
||||
/** @var string */
|
||||
private $secret;
|
||||
|
||||
/**
|
||||
* @param string decoded secret, e.g. base32_decode("SECRET")
|
||||
*/
|
||||
function __construct($secret) {
|
||||
* @param string $secret Decoded secret, e.g. base64_decode("ENCODED_SECRET").
|
||||
*/
|
||||
public function __construct($secret) {
|
||||
$this->secret = $secret;
|
||||
if ($_POST["auth"]) {
|
||||
$_SESSION["otp"] = (string) $_POST["auth"]["otp"];
|
||||
|
||||
if (isset($_POST["auth"])) {
|
||||
$_SESSION["otp"] = (string)$_POST["auth"]["otp"];
|
||||
}
|
||||
}
|
||||
|
||||
function loginFormField($name, $heading, $value) {
|
||||
if ($name == 'password') {
|
||||
return $heading . $value
|
||||
. "<tr><th><acronym title='One Time Password' lang='en'>OTP</acronym>"
|
||||
. "<td><input type='number' name='auth[otp]' value='" . h($_SESSION["otp"]) . "' size='6' autocomplete='off'>\n"
|
||||
;
|
||||
}
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $heading
|
||||
* @param string $value
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function loginFormField($name, $heading, $value) {
|
||||
if ($name != "password") return null;
|
||||
|
||||
return $heading . $value .
|
||||
"<tr><th><abbr title='" . lang('One Time Password') . "' lang='en'>OTP</abbr></th>" .
|
||||
"<td><input type='text' name='auth[otp]' value='" . h($_SESSION["otp"]) . "' " .
|
||||
"size='6' autocomplete='one-time-code' inputmode='numeric' maxlength='6' pattern='\d{6}'/></td>" .
|
||||
"</tr>\n";
|
||||
}
|
||||
|
||||
function login($login, $password) {
|
||||
if (isset($_SESSION["otp"])) {
|
||||
$timeSlot = floor(time() / 30);
|
||||
foreach (array(0, -1, 1) as $skew) {
|
||||
if ($_SESSION["otp"] == $this->getOtp($timeSlot + $skew)) {
|
||||
restart_session();
|
||||
unset($_SESSION["otp"]);
|
||||
stop_session();
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* @param string $login
|
||||
* @param string $password
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function login($login, $password) {
|
||||
if (!isset($_SESSION["otp"])) return null;
|
||||
|
||||
$timeSlot = floor(time() / 30);
|
||||
|
||||
foreach (array(0, -1, 1) as $skew) {
|
||||
if ($_SESSION["otp"] == $this->getOtp($timeSlot + $skew)) {
|
||||
restart_session();
|
||||
unset($_SESSION["otp"]);
|
||||
stop_session();
|
||||
|
||||
return null;
|
||||
}
|
||||
return 'Invalid OTP.';
|
||||
}
|
||||
|
||||
return lang('Invalid OTP code.');
|
||||
}
|
||||
|
||||
function getOtp($timeSlot) {
|
||||
$data = str_pad(pack('N', $timeSlot), 8, "\0", STR_PAD_LEFT);
|
||||
$hash = hash_hmac('sha1', $data, $this->secret, true);
|
||||
/**
|
||||
* @param int $timeSlot
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getOtp($timeSlot) {
|
||||
$data = str_pad(pack("N", $timeSlot), 8, "\0", STR_PAD_LEFT);
|
||||
$hash = hash_hmac("sha1", $data, $this->secret, true);
|
||||
$offset = ord(substr($hash, -1)) & 0xF;
|
||||
$unpacked = unpack('N', substr($hash, $offset, 4));
|
||||
$unpacked = unpack("N", substr($hash, $offset, 4));
|
||||
|
||||
return ($unpacked[1] & 0x7FFFFFFF) % 1e6;
|
||||
}
|
||||
}
|
||||
|
@@ -1,24 +1,28 @@
|
||||
<?php
|
||||
|
||||
/** Connect to MySQL using SSL
|
||||
* @link https://www.adminer.org/plugins/#use
|
||||
* @author Jakub Vrana, https://www.vrana.cz/
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
||||
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
||||
*/
|
||||
class AdminerLoginSsl {
|
||||
/** @access protected */
|
||||
var $ssl;
|
||||
/**
|
||||
* Connect to MySQL using SSL
|
||||
*
|
||||
* @link https://www.adminer.org/plugins/#use
|
||||
* @author Jakub Vrana, https://www.vrana.cz/
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
||||
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
||||
*/
|
||||
class AdminerLoginSsl
|
||||
{
|
||||
private var $ssl;
|
||||
|
||||
/**
|
||||
* @param array array("key" => filename, "cert" => filename, "ca" => filename)
|
||||
*/
|
||||
function __construct($ssl) {
|
||||
* MySQL: ["key" => filename, "cert" => filename, "ca" => filename]
|
||||
* PostgresSQL: ["mode" => sslmode] (https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLMODE)
|
||||
*/
|
||||
function __construct(array $ssl)
|
||||
{
|
||||
$this->ssl = $ssl;
|
||||
}
|
||||
|
||||
function connectSsl() {
|
||||
function connectSsl()
|
||||
{
|
||||
return $this->ssl;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user