1
0
mirror of https://github.com/vrana/adminer.git synced 2025-08-06 14:46:36 +02:00

Db: Unify connection error handling

This commit is contained in:
Jakub Vrana
2025-03-28 22:00:53 +01:00
parent d5bba383ea
commit 29339c5223
13 changed files with 95 additions and 123 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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 '

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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");
}