diff --git a/adminer/drivers/mysql.inc.php b/adminer/drivers/mysql.inc.php index 68726ecc..7c52f6e7 100644 --- a/adminer/drivers/mysql.inc.php +++ b/adminer/drivers/mysql.inc.php @@ -316,8 +316,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 ); diff --git a/adminer/drivers/pgsql.inc.php b/adminer/drivers/pgsql.inc.php index 3f215a41..3886ef3c 100644 --- a/adminer/drivers/pgsql.inc.php +++ b/adminer/drivers/pgsql.inc.php @@ -212,9 +212,9 @@ if (isset($_GET["pgsql"])) { return $query; } - function convertSearch($idf, $val, $field) { + function convertSearch($idf, array $where, array $field) { $textTypes = "char|text"; - if (strpos($val["op"], "LIKE") === false) { + if (strpos($where["op"], "LIKE") === false) { $textTypes .= "|date|time(stamp)?|boolean|uuid|inet|cidr|macaddr|" . number_type(); } diff --git a/adminer/include/adminer.inc.php b/adminer/include/adminer.inc.php index 157727e1..b1707089 100644 --- a/adminer/include/adminer.inc.php +++ b/adminer/include/adminer.inc.php @@ -39,7 +39,7 @@ class Adminer { function bruteForceKey() { return $_SERVER["REMOTE_ADDR"]; } - + /** Get server name displayed in breadcrumbs * @param string * @return string HTML code or null @@ -128,7 +128,7 @@ class Adminer { echo "
\n"; echo checkbox("auth[permanent]", 1, $_COOKIE["adminer_permanent"], lang('Permanent login')) . "\n"; } - + /** Get login form field * @param string * @param string HTML @@ -488,7 +488,7 @@ class Adminer { echo "\n"; echo "\n"; } - + /** Print command box in select * @return bool whether to print default commands */ @@ -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; } diff --git a/adminer/include/driver.inc.php b/adminer/include/driver.inc.php index bdee7a8d..2de83b58 100644 --- a/adminer/include/driver.inc.php +++ b/adminer/include/driver.inc.php @@ -13,14 +13,14 @@ function add_driver($id, $name) { /*abstract*/ class Min_SQL { var $_conn; - + /** Create object for performing database operations * @param Min_DB */ function __construct($connection) { $this->_conn = $connection; } - + /** Select data from table * @param string * @param array result of $adminer->selectColumnsProcess()[0] @@ -52,7 +52,7 @@ function add_driver($id, $name) { } return $return; } - + /** Delete data from table * @param string * @param string " WHERE ..." @@ -63,7 +63,7 @@ function add_driver($id, $name) { $query = "FROM " . table($table); return queries("DELETE" . ($limit ? limit1($table, $query, $queryWhere) : " $query$queryWhere")); } - + /** Update data in table * @param string * @param array escaped columns in keys, quoted data in values @@ -80,7 +80,7 @@ function add_driver($id, $name) { $query = table($table) . " SET$separator" . implode(",$separator", $values); return queries("UPDATE" . ($limit ? limit1($table, $query, $queryWhere, $separator) : " $query$queryWhere")); } - + /** Insert data into table * @param string * @param array escaped columns in keys, quoted data in values @@ -92,7 +92,7 @@ function add_driver($id, $name) { : " DEFAULT VALUES" )); } - + /** Insert or update data in table * @param string * @param array @@ -102,28 +102,28 @@ function add_driver($id, $name) { /*abstract*/ function insertUpdate($table, $rows, $primary) { return false; } - + /** Begin transaction * @return bool */ function begin() { return queries("BEGIN"); } - + /** Commit transaction * @return bool */ function commit() { return queries("COMMIT"); } - + /** Rollback transaction * @return bool */ function rollback() { return queries("ROLLBACK"); } - + /** Return query with a timeout * @param string * @param int seconds @@ -131,14 +131,14 @@ function add_driver($id, $name) { */ function slowQuery($query, $timeout) { } - + /** Convert column to be searchable * @param string escaped column name * @param array array("op" => , "val" => ) * @param array * @return string */ - function convertSearch($idf, $val, $field) { + function convertSearch($idf, array $where, array $field) { return $idf; } @@ -169,19 +169,19 @@ function add_driver($id, $name) { function quoteBinary($s) { return q($s); } - + /** Get warnings about the last command * @return string HTML */ function warnings() { return ''; } - + /** Get help link for table * @param string * @return string relative URL or null */ function tableHelp($name) { } - + } diff --git a/editor/include/adminer.inc.php b/editor/include/adminer.inc.php index 6ed2001d..d71cdbd0 100644 --- a/editor/include/adminer.inc.php +++ b/editor/include/adminer.inc.php @@ -23,7 +23,7 @@ class Adminer { function bruteForceKey() { return $_SERVER["REMOTE_ADDR"]; } - + function serverName($server) { } @@ -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; }