diff --git a/adminer/drivers/mssql.inc.php b/adminer/drivers/mssql.inc.php index 1dc24043..b0075f36 100644 --- a/adminer/drivers/mssql.inc.php +++ b/adminer/drivers/mssql.inc.php @@ -25,7 +25,7 @@ if (isset($_GET["mssql"])) { $this->error = rtrim($this->error); } - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { global $adminer; $connection_info = array("UID" => $username, "PWD" => $password, "CharacterSet" => "UTF-8"); $ssl = $adminer->connectSsl(); @@ -46,7 +46,7 @@ if (isset($_GET["mssql"])) { } else { $this->get_error(); } - return (bool) $this->link; + return ($this->link ? '' : $this->error); } function quote(string $string): string { @@ -182,9 +182,8 @@ if (isset($_GET["mssql"])) { class Db extends MssqlDb { public string $extension = "PDO_SQLSRV"; - function connect(string $server, string $username, string $password): bool { - $this->dsn("sqlsrv:Server=" . str_replace(":", ",", $server), $username, $password); - return true; + function attach(?string $server, string $username, string $password): string { + return $this->dsn("sqlsrv:Server=" . str_replace(":", ",", $server), $username, $password); } } @@ -192,9 +191,8 @@ if (isset($_GET["mssql"])) { class Db extends MssqlDb { public string $extension = "PDO_DBLIB"; - function connect(string $server, string $username, string $password): bool { - $this->dsn("dblib:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)), $username, $password); - return true; + function attach(?string $server, string $username, string $password): string { + return $this->dsn("dblib:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)), $username, $password); } } } @@ -298,10 +296,7 @@ if (isset($_GET["mssql"])) { if ($credentials[0] == "") { $credentials[0] = "localhost:1433"; } - if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { - return $connection; - } - return $connection->error; + return ($connection->attach($credentials[0], $credentials[1], $credentials[2]) ?: $connection); } function get_databases($flush) { diff --git a/adminer/drivers/mysql.inc.php b/adminer/drivers/mysql.inc.php index e9789b77..b2ed036b 100644 --- a/adminer/drivers/mysql.inc.php +++ b/adminer/drivers/mysql.inc.php @@ -14,8 +14,7 @@ if (!defined('Adminer\DRIVER')) { parent::init(); } - /** @see https://php.net/mysqli.construct */ - function connect($server = "", $username = "", $password = "", $database = null, $port = null, $socket = null) { + function attach(?string $server, string $username, string $password): string { 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 @@ -27,13 +26,13 @@ if (!defined('Adminer\DRIVER')) { ($server != "" ? $host : null), ($server . $username != "" ? $username : null), ($server . $username . $password != "" ? $password : null), - $database, + null, + (is_numeric($port) ? $port : ini_get("mysqli.default_port")), (is_numeric($port) ? intval($port) : null), - (!is_numeric($port) ? $port : $socket), ($ssl ? ($ssl['verify'] !== false ? 2048 : 64) : 0) // 2048 - MYSQLI_CLIENT_SSL, 64 - MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT (not available before PHP 5.6.16) ); $this->options(MYSQLI_OPT_LOCAL_INFILE, false); - return $return; + return ($return ? '' : $this->error); } function set_charset($charset) { @@ -67,10 +66,9 @@ if (!defined('Adminer\DRIVER')) { class Db extends SqlDb { /** @var resource */ private $link; - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { if (ini_bool("mysql.allow_local_infile")) { - $this->error = lang('Disable %s or enable %s or %s extensions.', "'mysql.allow_local_infile'", "MySQLi", "PDO_MySQL"); - return false; + return lang('Disable %s or enable %s or %s extensions.', "'mysql.allow_local_infile'", "MySQLi", "PDO_MySQL"); } $this->link = @mysql_connect( ($server != "" ? $server : ini_get("mysql.default_host")), @@ -79,12 +77,11 @@ if (!defined('Adminer\DRIVER')) { true, 131072 // CLIENT_MULTI_RESULTS for CALL ); - if ($this->link) { - $this->server_info = mysql_get_server_info($this->link); - } else { - $this->error = mysql_error(); + if (!$this->link) { + return mysql_error(); } - return (bool) $this->link; + $this->server_info = mysql_get_server_info($this->link); + return ''; } /** Set the client character set */ @@ -169,7 +166,7 @@ if (!defined('Adminer\DRIVER')) { class Db extends PdoDb { public string $extension = "PDO_MySQL"; - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { global $adminer; $options = array(\PDO::MYSQL_ATTR_LOCAL_INFILE => false); $ssl = $adminer->connectSsl(); @@ -187,13 +184,12 @@ if (!defined('Adminer\DRIVER')) { $options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $ssl['verify']; } } - $this->dsn( + return $this->dsn( "mysql:charset=utf8;host=" . str_replace(":", ";unix_socket=", preg_replace('~:(\d)~', ';port=\1', $server)), $username, $password, $options ); - return true; } function set_charset($charset) { @@ -366,24 +362,24 @@ if (!defined('Adminer\DRIVER')) { } /** Connect to the database - * @param array{string, string, string} $credentials [$server, $username, $password] + * @param array{?string, string, string} $credentials [$server, $username, $password] * @return string|Db string for error */ function connect(array $credentials) { global $drivers; $connection = new Db; - if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { - $connection->set_charset(charset($connection)); - $connection->query("SET sql_quote_show_create = 1, autocommit = 1"); - $connection->flavor = (preg_match('~MariaDB~', $connection->server_info) ? 'maria' : 'mysql'); - $drivers[DRIVER] = ($connection->flavor == 'maria' ? "MariaDB" : "MySQL"); - return $connection; + $error = $connection->attach($credentials[0], $credentials[1], $credentials[2]); + if ($error) { + if (function_exists('iconv') && !is_utf8($error) && strlen($s = iconv("windows-1250", "utf-8", $error)) > strlen($error)) { // windows-1250 - most common Windows encoding + $error = $s; + } + return $error; } - $return = $connection->error; - if (function_exists('iconv') && !is_utf8($return) && strlen($s = iconv("windows-1250", "utf-8", $return)) > strlen($return)) { // windows-1250 - most common Windows encoding - $return = $s; - } - return $return; + $connection->set_charset(charset($connection)); + $connection->query("SET sql_quote_show_create = 1, autocommit = 1"); + $connection->flavor = (preg_match('~MariaDB~', $connection->server_info) ? 'maria' : 'mysql'); + $drivers[DRIVER] = ($connection->flavor == 'maria' ? "MariaDB" : "MySQL"); + return $connection; } /** Get cached list of databases diff --git a/adminer/drivers/oracle.inc.php b/adminer/drivers/oracle.inc.php index 61b1134c..63a6534c 100644 --- a/adminer/drivers/oracle.inc.php +++ b/adminer/drivers/oracle.inc.php @@ -19,15 +19,14 @@ if (isset($_GET["oracle"])) { $this->error = $error; } - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { $this->link = @oci_new_connect($username, $password, $server, "AL32UTF8"); if ($this->link) { $this->server_info = oci_server_version($this->link); - return true; + return ''; } $error = oci_error(); - $this->error = $error["message"]; - return false; + return $error["message"]; } function quote(string $string): string { @@ -106,9 +105,8 @@ if (isset($_GET["oracle"])) { public string $extension = "PDO_OCI"; public $_current_db; - function connect(string $server, string $username, string $password): bool { - $this->dsn("oci:dbname=//$server;charset=AL32UTF8", $username, $password); - return true; + function attach(?string $server, string $username, string $password): string { + return $this->dsn("oci:dbname=//$server;charset=AL32UTF8", $username, $password); } function select_db(string $database): bool { @@ -193,10 +191,7 @@ if (isset($_GET["oracle"])) { function connect($credentials) { $connection = new Db; - if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { - return $connection; - } - return $connection->error; + return ($connection->attach($credentials[0], $credentials[1], $credentials[2]) ?: $connection); } function get_databases($flush) { diff --git a/adminer/drivers/pgsql.inc.php b/adminer/drivers/pgsql.inc.php index a6010ca1..d12c2769 100644 --- a/adminer/drivers/pgsql.inc.php +++ b/adminer/drivers/pgsql.inc.php @@ -19,7 +19,7 @@ if (isset($_GET["pgsql"])) { $this->error = $error; } - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { global $adminer; $db = $adminer->database(); set_error_handler(array($this, '_error')); @@ -38,7 +38,7 @@ if (isset($_GET["pgsql"])) { if ($this->link) { pg_set_client_encoding($this->link, "UTF8"); } - return (bool) $this->link; + return ($this->link ? '' : $this->error); } function quote(string $string): string { @@ -129,7 +129,7 @@ if (isset($_GET["pgsql"])) { public string $extension = "PDO_PgSQL"; public int $timeout; - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { global $adminer; $db = $adminer->database(); //! client_encoding is supported since 9.1, but we can't yet use min_version here @@ -138,8 +138,7 @@ if (isset($_GET["pgsql"])) { if (isset($ssl["mode"])) { $dsn .= " sslmode='" . $ssl["mode"] . "'"; } - $this->dsn($dsn, $username, $password); - return true; + return $this->dsn($dsn, $username, $password); } function select_db(string $database): bool { @@ -304,19 +303,20 @@ if (isset($_GET["pgsql"])) { function connect($credentials) { global $drivers; $connection = new Db; - if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { - if (min_version(9, 0, $connection)) { - $connection->query("SET application_name = 'Adminer'"); - } - $version = get_val("SELECT version()", 0, $connection); - $connection->flavor = (preg_match('~CockroachDB~', $version) ? 'cockroach' : ''); - $connection->server_info = preg_replace('~^\D*([\d.]+[-\w]*).*~', '\1', $version); - if ($connection->flavor == 'cockroach') { // we don't use "PostgreSQL / CockroachDB" by default because it's too long - $drivers[DRIVER] = "CockroachDB"; - } - return $connection; + $error = $connection->attach($credentials[0], $credentials[1], $credentials[2]); + if ($error) { + return $error; } - return $connection->error; + if (min_version(9, 0, $connection)) { + $connection->query("SET application_name = 'Adminer'"); + } + $version = get_val("SELECT version()", 0, $connection); + $connection->flavor = (preg_match('~CockroachDB~', $version) ? 'cockroach' : ''); + $connection->server_info = preg_replace('~^\D*([\d.]+[-\w]*).*~', '\1', $version); + if ($connection->flavor == 'cockroach') { // we don't use "PostgreSQL / CockroachDB" by default because it's too long + $drivers[DRIVER] = "CockroachDB"; + } + return $connection; } function get_databases($flush) { diff --git a/adminer/drivers/sqlite.inc.php b/adminer/drivers/sqlite.inc.php index 04518a50..9954b940 100644 --- a/adminer/drivers/sqlite.inc.php +++ b/adminer/drivers/sqlite.inc.php @@ -11,11 +11,11 @@ if (isset($_GET["sqlite"])) { public string $extension = "SQLite3"; private $link; - function connect(string $filename, string $username = '', string $password = ''): bool { + function attach(?string $filename, string $username, string $password): string { $this->link = new \SQLite3($filename); $version = $this->link->version(); $this->server_info = $version["versionString"]; - return true; + return ''; } function query(string $query, bool $unbuffered = false) { @@ -75,11 +75,11 @@ if (isset($_GET["sqlite"])) { abstract class SqliteDb extends PdoDb { public string $extension = "PDO_SQLite"; - function connect(string $filename, string $username = '', string $password = ''): bool { + function attach(?string $filename, string $username, string $password): string { $this->dsn(DRIVER . ":$filename", "", ""); $this->query("PRAGMA foreign_keys = 1"); $this->query("PRAGMA busy_timeout = 500"); - return true; + return ''; } } @@ -87,16 +87,16 @@ if (isset($_GET["sqlite"])) { if (class_exists('Adminer\SqliteDb')) { class Db extends SqliteDb { - function connect(string $filename, string $username = '', string $password = ''): bool { - parent::connect($filename); + function attach(?string $filename, string $username, string $password): string { + parent::attach($filename, $username, $password); $this->query("PRAGMA foreign_keys = 1"); $this->query("PRAGMA busy_timeout = 500"); - return true; + return ''; } function select_db(string $filename): bool { if (is_readable($filename) && $this->query("ATTACH " . $this->quote(preg_match("~(^[/\\\\]|:)~", $filename) ? $filename : dirname($_SERVER["SCRIPT_FILENAME"]) . "/$filename") . " AS a")) { - return self::connect($filename); + return !self::attach($filename, '', ''); } return false; } @@ -172,8 +172,7 @@ if (isset($_GET["sqlite"])) { return lang('Database does not support password.'); } $connection = new Db; - $connection->connect(":memory:", "", ""); - return $connection; + return ($connection->attach(":memory:", "", "") ?: $connection); } function get_databases($flush) { @@ -369,7 +368,7 @@ if (isset($_GET["sqlite"])) { } try { $link = new Db(); - $link->connect($db); + $link->attach($db, '', ''); } catch (\Exception $ex) { $connection->error = $ex->getMessage(); return false; @@ -382,7 +381,7 @@ if (isset($_GET["sqlite"])) { function drop_databases($databases) { global $connection; - $connection->connect(":memory:"); // to unlock file, doesn't work in PDO on Windows + $connection->attach(":memory:", '', ''); // to unlock file, doesn't work in PDO on Windows foreach ($databases as $db) { if (!@unlink($db)) { $connection->error = lang('File exists.'); @@ -397,7 +396,7 @@ if (isset($_GET["sqlite"])) { if (!check_sqlite_name($name)) { return false; } - $connection->connect(":memory:"); + $connection->attach(":memory:", '', ''); $connection->error = lang('File exists.'); return @rename(DB, $name); } diff --git a/adminer/include/db.inc.php b/adminer/include/db.inc.php index bd352e2a..76832c0d 100644 --- a/adminer/include/db.inc.php +++ b/adminer/include/db.inc.php @@ -13,8 +13,10 @@ abstract class SqlDb { public string $error; // last error message /** @var Result|bool */ protected $multi; // used for multiquery - /** Connect to server */ - abstract function connect(string $server, string $username, string $password): bool; + /** Connect to server + * @return string error message + */ + abstract function attach(?string $server, string $username, string $password): string; /** Quote string to use in SQL * @return string escaped string enclosed in ' diff --git a/adminer/include/pdo.inc.php b/adminer/include/pdo.inc.php index 30e6dda9..149a04c2 100644 --- a/adminer/include/pdo.inc.php +++ b/adminer/include/pdo.inc.php @@ -8,16 +8,18 @@ if (extension_loaded('pdo')) { /** Connect to server using DSN * @param mixed[] $options + * @return string error message */ - function dsn(string $dsn, string $username, string $password, array $options = array()): void { + function dsn(string $dsn, string $username, string $password, array $options = array()): string { $options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_SILENT; $options[\PDO::ATTR_STATEMENT_CLASS] = array('Adminer\PdoResult'); try { $this->pdo = new \PDO($dsn, $username, $password, $options); } catch (\Exception $ex) { - auth_error(h($ex->getMessage())); + return $ex->getMessage(); } $this->server_info = @$this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION); + return ''; } function quote(string $string): string { diff --git a/plugins/drivers/clickhouse.php b/plugins/drivers/clickhouse.php index 6b94e8cf..45d8904a 100644 --- a/plugins/drivers/clickhouse.php +++ b/plugins/drivers/clickhouse.php @@ -56,11 +56,11 @@ if (isset($_GET["clickhouse"])) { return $this->rootQuery($this->_db, $query); } - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { preg_match('~^(https?://)?(.*)~', $server, $match); $this->url = ($match[1] ?: "http://") . urlencode($username) . ":" . urlencode($password) . "@$match[2]"; $return = $this->query('SELECT 1'); - return (bool) $return; + return ($return ? '' : $this->error); } function select_db(string $database): bool { @@ -230,10 +230,7 @@ if (isset($_GET["clickhouse"])) { if (!preg_match('~^(https?://)?[-a-z\d.]+(:\d+)?$~', $server)) { return lang('Invalid server.'); } - if ($connection->connect($server, $username, $password)) { - return $connection; - } - return $connection->error; + return ($connection->attach($server, $username, $password) ?: $connection); } function get_databases($flush) { diff --git a/plugins/drivers/elastic.php b/plugins/drivers/elastic.php index b1ed0f84..f7dca161 100644 --- a/plugins/drivers/elastic.php +++ b/plugins/drivers/elastic.php @@ -61,14 +61,14 @@ if (isset($_GET["elastic"])) { } } - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { preg_match('~^(https?://)?(.*)~', $server, $match); $this->url = ($match[1] ?: "http://") . urlencode($username) . ":" . urlencode($password) . "@$match[2]"; $return = $this->rootQuery(''); if ($return) { $this->server_info = $return['version']['number']; } - return (bool) $return; + return ($return ? '' : $this->error); } function select_db(string $database): bool { @@ -290,15 +290,11 @@ if (isset($_GET["elastic"])) { if (!preg_match('~^(https?://)?[-a-z\d.]+(:\d+)?$~', $server)) { return lang('Invalid server.'); } - if ($password != "" && $connection->connect($server, $username, "")) { + if ($password != "" && $connection->attach($server, $username, "")) { return lang('Database does not support password.'); } - if ($connection->connect($server, $username, $password)) { - return $connection; - } - - return $connection->error; + return ($connection->attach($server, $username, $password) ?: $connection); } function support($feature) { diff --git a/plugins/drivers/firebird.php b/plugins/drivers/firebird.php index 36c86296..4bef5a0a 100644 --- a/plugins/drivers/firebird.php +++ b/plugins/drivers/firebird.php @@ -14,17 +14,15 @@ if (isset($_GET["firebird"])) { class Db extends SqlDb { public string $extension = "Firebird", $_link; - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { $this->_link = ibase_connect($server, $username, $password); if ($this->_link) { $url_parts = explode(':', $server); $service_link = ibase_service_attach($url_parts[0], $username, $password); $this->server_info = ibase_server_info($service_link, IBASE_SVC_SERVER_VERSION); - } else { - $this->errno = ibase_errcode(); - $this->error = ibase_errmsg(); + return ''; } - return (bool) $this->_link; + return ibase_errmsg(); } function quote(string $string): string { @@ -105,10 +103,7 @@ if (isset($_GET["firebird"])) { function connect($credentials) { $connection = new Db; - if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { - return $connection; - } - return $connection->error; + return ($connection->attach($credentials[0], $credentials[1], $credentials[2]) ?: $connection); } function get_databases($flush) { diff --git a/plugins/drivers/imap.php b/plugins/drivers/imap.php index b30791a0..17e5d73d 100644 --- a/plugins/drivers/imap.php +++ b/plugins/drivers/imap.php @@ -24,13 +24,10 @@ if (isset($_GET["imap"])) { private $mailbox; private $imap; - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { $this->mailbox = "{" . "$server:993/ssl}"; // Adminer disallows specifying privileged port in server name $this->imap = @imap_open($this->mailbox, $username, $password, OP_HALFOPEN, 1); - if (!$this->imap) { - $this->error = imap_last_error(); - } - return $this->imap; + return ($this->imap ? '' : imap_last_error()); } function select_db(string $database): bool { @@ -275,10 +272,7 @@ if (isset($_GET["imap"])) { function connect($credentials) { $connection = new Db; - if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) { - return $connection; - } - return $connection->error; + return ($connection->attach($credentials[0], $credentials[1], $credentials[2]) ?: $connection); } function support($feature) { diff --git a/plugins/drivers/mongo.php b/plugins/drivers/mongo.php index fefcdb09..6988258d 100644 --- a/plugins/drivers/mongo.php +++ b/plugins/drivers/mongo.php @@ -12,7 +12,7 @@ if (isset($_GET["mongo"])) { public \MongoDB\Driver\Manager $_link; public $_db, $_db_name; - function connect(string $server, string $username, string $password): bool { + function attach(?string $server, string $username, string $password): string { $options = array(); if ($username . $password != "") { $options["username"] = $username; @@ -27,6 +27,7 @@ if (isset($_GET["mongo"])) { } $this->_link = new \MongoDB\Driver\Manager("mongodb://$server", $options); $this->executeDbCommand($options["db"], array('ping' => 1)); + return ''; } function executeCommand($command) { @@ -435,11 +436,7 @@ if (isset($_GET["mongo"])) { if ($server == "") { $server = "localhost:27017"; } - $connection->connect($server, $username, $password); - if ($connection->error) { - return $connection->error; - } - return $connection; + return ($connection->attach($server, $username, $password) ?: $connection); } function alter_indexes($table, $alter) { diff --git a/plugins/drivers/simpledb.php b/plugins/drivers/simpledb.php index 1d6630c6..f1a36917 100644 --- a/plugins/drivers/simpledb.php +++ b/plugins/drivers/simpledb.php @@ -10,6 +10,10 @@ if (isset($_GET["simpledb"])) { class Db extends SqlDb { public string $extension = "SimpleXML", $server_info = '2009-04-15', $timeout, $next; + function attach(?string $server, string $username, string $password): string { + return ''; + } + function select_db(string $database): bool { return ($database == "domain"); }