if (isset($_GET["mssql"])) {
define('Adminer\DRIVER', "mssql");
if (extension_loaded("sqlsrv") && $_GET["ext"] != "pdo") {
- class Db {
- public $extension = "sqlsrv", $flavor = '', $server_info, $affected_rows, $errno, $error;
+ class Db extends SqlDb {
+ public $extension = "sqlsrv";
private $link, $result;
private function get_error() {
function next_result() {
return $this->result ? sqlsrv_next_result($this->result) : null;
}
-
- function result($query, $field = 0) {
- $result = $this->query($query);
- if (!is_object($result)) {
- return false;
- }
- $row = $result->fetch_row();
- return $row[$field];
- }
}
class Result {
}
} else {
- class MssqlDb extends PdoDb {
+ abstract class MssqlDb extends PdoDb {
function select_db($database) {
// database selection is separated from the connection so dbname in DSN can't be used
return $this->query(use_sql($database));
function result($query, $field = 0) {
$result = $this->query($query);
- if (!$result) {
+ if (!is_object($result)) {
return false;
}
$row = $result->fetch_array();
}
} elseif (extension_loaded("mysql") && !((ini_bool("sql.safe_mode") || ini_bool("mysql.allow_local_infile")) && extension_loaded("pdo_mysql"))) {
- class Db {
- /** @var string */ public $extension = "MySQL"; // extension name
- /** @var string */ public $flavor = ''; // different vendor with the same API; e.g. MariaDB; usually stays empty
- /** @var string */ public $server_info; // server version
- /** @var int */ public $affected_rows; // number of affected rows
- /** @var string */ public $info; // see https://php.net/mysql_info
- /** @var int */ public $errno; // last error code
- /** @var string */ public $error; // last error message
-
- /** @var \mysqli */ private $link;
- /** @var Result */ private $result;
-
- /** Connect to server
- * @param string
- * @param string
- * @param string
- * @return bool
- */
+ class Db extends SqlDb {
+ /** @var resource */ private $link;
+
function connect($server, $username, $password) {
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 $this->query("SET NAMES $charset");
}
- /** Quote string to use in SQL
- * @param string
- * @return string escaped string enclosed in '
- */
function quote($string) {
return "'" . mysql_real_escape_string($string, $this->link) . "'";
}
- /** Select database
- * @param string
- * @return bool
- */
function select_db($database) {
return mysql_select_db($database, $this->link);
}
- /** Send query
- * @param string
- * @param bool
- * @return Result|bool
- */
function query($query, $unbuffered = false) {
$result = @($unbuffered ? mysql_unbuffered_query($query, $this->link) : mysql_query($query, $this->link)); // @ - mute mysql.trace_mode
$this->error = "";
}
return new Result($result);
}
-
- /** Send query with more resultsets
- * @param string
- * @return Result|bool
- */
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
- /** Get current resultset
- * @return Result
- */
- function store_result() {
- return $this->result;
- }
-
- /** Fetch next resultset
- * @return bool
- */
- function next_result() {
- // MySQL extension doesn't support multiple results
- return false;
- }
-
- /** Get single field from result
- * @param string
- * @param int
- * @return string
- */
- function result($query, $field = 0) {
- $result = $this->query($query);
- return ($result ? $result->fetch_column($field) : false);
- }
}
class Result {
}
/** Fetch next row as associative array
- * @return string[]
+ * @return array<?string>
*/
function fetch_assoc() {
return mysql_fetch_assoc($this->result);
}
/** Fetch next row as numbered array
- * @return list<string>
+ * @return list<?string>
*/
function fetch_row() {
return mysql_fetch_row($this->result);
}
- /** Fetch a single column
- * @param int
- * @return string or false if there are no rows
- */
- function fetch_column($field) {
- return ($this->num_rows ? mysql_result($this->result, 0, $field) : false);
- }
-
/** Fetch next field
* @return object properties: name, type (0 number, 15 varchar, 254 char), charsetnr (63 binary); optionally: table, orgtable, orgname
*/
}
function set_charset($charset) {
- $this->query("SET NAMES $charset"); // charset in DSN is ignored before PHP 5.3.6
+ return $this->query("SET NAMES $charset"); // charset in DSN is ignored before PHP 5.3.6
}
function select_db($database) {
}
/** Check whether a feature is supported
- * @param string "check|comment|copy|database|descidx|drop_col|dump|event|indexes|kill|materializedview|partitioning|privileges|procedure|processlist|routine|scheme|sequence|status|table|trigger|type|variables|view|view_trigger"
+ * @param literal-string "check|comment|copy|database|descidx|drop_col|dump|event|indexes|kill|materializedview|partitioning|privileges|procedure|processlist|routine|scheme|sequence|status|table|trigger|type|variables|view|view_trigger"
* @return bool
*/
function support($feature) {
if (isset($_GET["oracle"])) {
define('Adminer\DRIVER', "oracle");
if (extension_loaded("oci8") && $_GET["ext"] != "pdo") {
- class Db {
- public $extension = "oci8", $flavor = '', $server_info, $affected_rows, $errno, $error;
+ class Db extends SqlDb {
+ public $extension = "oci8";
public $_current_db;
- private $link, $result;
+ private $link;
function _error($errno, $error) {
if (ini_bool("html_errors")) {
}
return $return;
}
-
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
- function store_result() {
- return $this->result;
- }
-
- function next_result() {
- return false;
- }
-
- function result($query, $field = 0) {
- $result = $this->query($query);
- return (is_object($result) ? $result->fetch_column($field) : false);
- }
}
class Result {
return $this->convert(oci_fetch_row($this->result));
}
- function fetch_column($field) {
- return (oci_fetch($this->result) ? oci_result($this->result, $field + 1) : false);
- }
-
function fetch_field() {
$column = $this->offset++;
$return = new \stdClass;
if (isset($_GET["pgsql"])) {
define('Adminer\DRIVER', "pgsql");
if (extension_loaded("pgsql") && $_GET["ext"] != "pdo") {
- class Db {
- public $extension = "PgSQL", $flavor = '', $server_info, $affected_rows, $error, $timeout;
- private $link, $result, $string, $database = true;
+ class Db extends SqlDb {
+ public $extension = "PgSQL", $timeout;
+ private $link, $string, $database = true;
function _error($errno, $error) {
if (ini_bool("html_errors")) {
return $return;
}
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
- function store_result() {
- return $this->result;
- }
-
- function next_result() {
- // PgSQL extension doesn't support multiple results
- return false;
- }
-
- function result($query, $field = 0) {
- $result = $this->query($query);
- return ($result ? $result->fetch_column($field) : false);
- }
-
function warnings() {
return h(pg_last_notice($this->link)); // second parameter is available since PHP 7.1.0
}
return pg_fetch_row($this->result);
}
- function fetch_column($field) {
- return ($this->num_rows ? pg_fetch_result($this->result, 0, $field) : false);
- }
-
function fetch_field() {
$column = $this->offset++;
$return = new \stdClass;
return $return;
}
- // warnings() not implemented in PDO_PgSQL as of PHP 7.2.1
+ function warnings() {
+ // not implemented in PDO_PgSQL as of PHP 7.2.1
+ }
function close() {
}
define('Adminer\DRIVER', "sqlite");
if (class_exists("SQLite3") && $_GET["ext"] != "pdo") {
- class SqliteDb {
- public $extension = "SQLite3", $flavor = '', $server_info, $affected_rows, $errno, $error;
- private $link, $result;
+ abstract class SqliteDb extends SqlDb {
+ public $extension = "SQLite3";
+ private $link;
- function __construct($filename) {
+ function connect($filename, $username = '', $password = '') {
$this->link = new \SQLite3($filename);
$version = $this->link->version();
$this->server_info = $version["versionString"];
+ return true;
}
- function query($query) {
+ function query($query, $unbuffered = false) {
$result = @$this->link->query($query);
$this->error = "";
if (!$result) {
: "x'" . first(unpack('H*', $string)) . "'"
);
}
-
-
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
- function store_result() {
- return $this->result;
- }
-
- function next_result() {
- return false;
- }
-
- function result($query, $field = 0) {
- $result = $this->query($query);
- if (!is_object($result)) {
- return false;
- }
- $row = $result->fetch_row();
- return $row ? $row[$field] : false;
- }
}
class Result {
}
} elseif (extension_loaded("pdo_sqlite")) {
- class SqliteDb extends PdoDb {
+ abstract class SqliteDb extends PdoDb {
public $extension = "PDO_SQLite";
- function __construct($filename) {
+ function connect($filename, $username = '', $password = '') {
$this->dsn(DRIVER . ":$filename", "", "");
- }
-
- function select_db($db) {
- return false;
+ $this->query("PRAGMA foreign_keys = 1");
+ $this->query("PRAGMA busy_timeout = 500");
+ return true;
}
}
if (class_exists('Adminer\SqliteDb')) {
class Db extends SqliteDb {
- function __construct() {
- parent::__construct(":memory:");
+ function connect($filename, $username = '', $password = '') {
+ parent::connect($filename);
$this->query("PRAGMA foreign_keys = 1");
+ $this->query("PRAGMA busy_timeout = 500");
+ return true;
}
function select_db($filename) {
- if (is_readable($filename) && $this->query("ATTACH " . $this->quote(preg_match("~(^[/\\\\]|:)~", $filename) ? $filename : dirname($_SERVER["SCRIPT_FILENAME"]) . "/$filename") . " AS a")) { // is_readable - SQLite 3
- parent::__construct($filename);
- $this->query("PRAGMA foreign_keys = 1");
- $this->query("PRAGMA busy_timeout = 500");
- return true;
+ 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 false;
}
if ($password != "") {
return lang('Database does not support password.');
}
- return new Db;
+ $connection = new Db;
+ $connection->connect(":memory:", "", "");
+ return $connection;
}
function get_databases($flush) {
return false;
}
try {
- $link = new SqliteDb($db);
+ $link = new Db();
+ $link->connect($db);
} catch (\Exception $ex) {
$connection->error = $ex->getMessage();
return false;
* @param string new name
* @param list<list<string>> [process_field()], empty to preserve
* @param string[] [$original => idf_escape($new_column)], empty to preserve
- * @param string [format_foreign_key()], empty to preserve
+ * @param string[] [format_foreign_key()], empty to preserve
* @param int set auto_increment to this value, 0 to preserve
* @param list<array{string, string, list<string>|'DROP'}> [[$type, $name, $columns]], empty to preserve
* @param string CHECK constraint to drop
include "../adminer/include/lang.inc.php";
include "../adminer/lang/$LANG.inc.php";
+include "../adminer/include/db.inc.php";
include "../adminer/include/pdo.inc.php";
include "../adminer/include/driver.inc.php";
include "../adminer/drivers/sqlite.inc.php";
--- /dev/null
+<?php
+namespace Adminer;
+
+// this could be interface when "Db extends \mysqli" can have compatible type declarations (PHP 7)
+// interfaces can include properties only since PHP 8.4
+abstract class SqlDb {
+ /** @var string */ public $extension; // extension name
+ /** @var string */ public $flavor; // different vendor with the same API, e.g. MariaDB; usually stays empty
+ /** @var string */ public $server_info; // server version
+ /** @var int */ public $affected_rows; // number of affected rows
+ /** @var string */ public $info; // see https://php.net/mysql_info
+ /** @var int */ public $errno; // last error code
+ /** @var string */ public $error; // last error message
+ /** @var Result|bool */ protected $multi; // used for multiquery
+
+ /** Connect to server
+ * @param string
+ * @param string
+ * @param string
+ * @return bool
+ */
+ abstract function connect($server, $username, $password);
+
+ /** Quote string to use in SQL
+ * @param string
+ * @return string escaped string enclosed in '
+ */
+ abstract function quote($string);
+
+ /** Select database
+ * @param string
+ * @return bool
+ */
+ abstract function select_db($database);
+
+ /** Send query
+ * @param string
+ * @param bool
+ * @return Result|bool
+ */
+ abstract function query($query, $unbuffered = false);
+
+ /** Send query with more resultsets
+ * @param string
+ * @return Result|bool
+ */
+ function multi_query($query) {
+ return $this->multi = $this->query($query);
+ }
+
+ /** Get current resultset
+ * @return Result|bool
+ */
+ function store_result() {
+ return $this->multi;
+ }
+
+ /** Fetch next resultset
+ * @return bool
+ */
+ function next_result() {
+ return false;
+ }
+
+ /** Get single field from result
+ * @param string
+ * @param int
+ * @return string|bool
+ */
+ function result($query, $field = 0) {
+ $result = $this->query($query);
+ if (!is_object($result)) {
+ return false;
+ }
+ $row = $result->fetch_row();
+ return ($row ? $row[$field] : false);
+ }
+}
* @param list<string> result of $adminer->selectSearchProcess()
* @param list<string> result of $adminer->selectColumnsProcess()[1]
* @param list<string> result of $adminer->selectOrderProcess()
- * @param int result of $adminer->selectLimitProcess()
+ * @param int|numeric-string result of $adminer->selectLimitProcess()
* @param int index of page starting at zero
* @param bool whether to print the query
* @return Result|false
* @param float|string
* @return string
*/
-// this is matched by compile.php
function lang($idf, $number = null) {
+ // this is matched by compile.php
global $LANG, $translations;
$translation = ($translations[$idf] ?: $idf);
if (is_array($translation)) {
// PDO can be used in several database drivers
if (extension_loaded('pdo')) {
- abstract class PdoDb {
- public $flavor = '', $server_info, $affected_rows, $errno, $error;
- protected $pdo;
- private $result;
+ abstract class PdoDb extends SqlDb {
+ /** @var \PDO */ protected $pdo;
+ /** Connect to server using DSN
+ * @param string
+ * @param string
+ * @param string
+ * @param mixed[]
+ * @return void
+ */
function dsn($dsn, $username, $password, $options = array()) {
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_SILENT;
- $options[\PDO::ATTR_STATEMENT_CLASS] = array('Adminer\PdoDbStatement');
+ $options[\PDO::ATTR_STATEMENT_CLASS] = array('Adminer\PdoResult');
try {
$this->pdo = new \PDO($dsn, $username, $password, $options);
} catch (\Exception $ex) {
$this->server_info = @$this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION);
}
- abstract function select_db($database);
-
function quote($string) {
return $this->pdo->quote($string);
}
function query($query, $unbuffered = false) {
+ /** @var Result|bool */
$result = $this->pdo->query($query);
$this->error = "";
if (!$result) {
return $result;
}
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
function store_result($result = null) {
if (!$result) {
- $result = $this->result;
+ $result = $this->multi;
if (!$result) {
return false;
}
}
function next_result() {
- if (!$this->result) {
- return false;
- }
- $this->result->_offset = 0;
- return @$this->result->nextRowset(); // @ - PDO_PgSQL doesn't support it
- }
-
- function result($query, $field = 0) {
- $result = $this->query($query);
- if (!$result) {
+ if (!is_object($this->multi)) {
return false;
}
- $row = $result->fetch();
- return $row ? $row[$field] : false;
+ $this->multi->_offset = 0;
+ return @$this->multi->nextRowset(); // @ - PDO_PgSQL doesn't support it
}
}
- class PdoDbStatement extends \PDOStatement {
+ class PdoResult extends \PDOStatement {
public $_offset = 0, $num_rows;
function fetch_assoc() {
return $this->fetch(\PDO::FETCH_NUM);
}
- function fetch_column($field) {
- return $this->fetchColumn($field);
- }
-
function fetch_field() {
$row = (object) $this->getColumnMeta($this->_offset++);
$type = $row->pdo_type;
exit(1);
}
+include __DIR__ . "/adminer/include/db.inc.php";
include __DIR__ . "/adminer/include/pdo.inc.php";
include __DIR__ . "/adminer/include/driver.inc.php";
$connection = (object) array('flavor' => ''); // used in support()
- identifier: include.fileNotFound # relative includes
- identifier: includeOnce.fileNotFound # ./adminer-plugins.php
- "~^Function (set_magic_quotes_runtime|mysql_)~" # PHP < 7 functions
- - "~^Function (foreign_keys_sql|recreate_table) not found~" # defined by other drivers
+ - "~an unknown class OCI-?Lob~" # this looks like PHPStan bug
- "~^Variable \\$(adminer|connection|driver|drivers|error|HTTPS|LANG|langs|permanent|has_token|token|translations|VERSION) might not be defined~" # declared in bootstrap.inc.php
- "~^Method Adminer\\\\Plugins::\\w+\\(\\) with return type void~" # we use the same pattern for all methods
- "~Call to function is_object\\(\\) with Adminer\\\\Db\\|string will always evaluate to false~" # is_object(Db) is true
- "~^Comparison operation \"==\" between \\(array\\|float\\|int\\) and 1~" # it thinks that $affected could be an array
- - "~^Parameter #2 \\$newvalue of function ini_set expects string~" # it expects string|int|float|bool|null
+ - "~^Parameter #2 \\$newvalue of function ini_set expects string~" # it expects string|int|float|bool|null since PHP 8.1
- "~expects int, float given~" # this will work
- "~expects bool~" # truthy values
- "~fread expects int<1, max>, 100000~" # 1e6
- "~'strlen' given~" # used as a bool callback
- - "~Adminer\\\\(Db|PdoDb).* type specified~" # duplicate methods
+
+ -
+ message: "~ type specified~" # duplicate functions and methods
+ paths:
+ - adminer/include/pdo.inc.php
+ - adminer/drivers/*
# it probably doesn't like $ar[$key] instead of isset($ar[$key]) and thinks that $ar[$key] is always set
- identifier: identical.alwaysFalse
- identifier: deadCode.unreachable
paths:
+ - adminer/drivers/mysql.inc.php # other drivers inherit the annotations so we take them from here
- adminer/
scanFiles:
- compile.php # compile_file()
excludePaths:
+ - adminer/lang/
- adminer/adminer-plugins.php
- adminer/designs.php
- adminer/elastic.php
- adminer/sqlite.php
- - adminer/drivers/mssql.inc.php
- - adminer/drivers/oracle.inc.php
- - adminer/drivers/pgsql.inc.php
- - adminer/drivers/sqlite.inc.php
phpVersion:
min: 70100
define('Adminer\DRIVER', "clickhouse");
if (ini_bool('allow_url_fopen')) {
- class Db {
- public $extension = "JSON", $flavor = '', $server_info, $errno, $error;
+ class Db extends SqlDb {
+ public $extension = "JSON";
public $_db = 'default';
- private $result, $url;
+ private $url;
function rootQuery($db, $query) {
$file = @file_get_contents("$this->url/?database=$db", false, stream_context_create(array('http' => array(
return (bool) preg_match('~^(select|show)~i', $query);
}
- function query($query) {
+ function query($query, $unbuffered = false) {
return $this->rootQuery($this->_db, $query);
}
function quote($string) {
return "'" . addcslashes($string, "\\'") . "'";
}
-
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
- function store_result() {
- return $this->result;
- }
-
- function next_result() {
- return false;
- }
-
- function result($query, $field = 0) {
- $result = $this->query($query);
- return $result['data'];
- }
}
class Result {
if (ini_bool('allow_url_fopen')) {
- class Db {
- public $extension = "JSON", $flavor = '', $server_info, $errno, $error;
+ class Db extends SqlDb {
+ public $extension = "JSON";
private $url;
/**
$where = explode(" AND ", $matches[2]);
- return $driver->select($matches[1], array("*"), $where, null, array(), $matches[3]);
+ return $driver->select($matches[1], array("*"), $where, array(), array(), $matches[3]);
}
return $this->rootQuery($path, $content, $method);
define('Adminer\DRIVER', "firebird");
if (extension_loaded("interbase")) {
- class Db {
- public
- $extension = "Firebird",
- $flavor = '',
- $server_info,
- $affected_rows,
- $errno,
- $error,
- $_link
- ;
- private $result;
+ class Db extends SqlDb {
+ public $extension = "Firebird", $_link;
function connect($server, $username, $password) {
$this->_link = ibase_connect($server, $username, $password);
}
function query($query, $unbuffered = false) {
- $result = ibase_query($query, $this->_link);
+ $result = ibase_query($this->_link, $query);
if (!$result) {
$this->errno = ibase_errcode();
$this->error = ibase_errmsg();
}
return new Result($result);
}
-
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
- function store_result() {
- return $this->result;
- }
-
- function next_result() {
- return false;
- }
-
- function result($query, $field = 0) {
- $result = $this->query($query);
- if (!$result || !$result->num_rows) {
- return false;
- }
- $row = $result->fetch_row();
- return $row[$field];
- }
}
class Result {
define('Adminer\DRIVER', "imap");
if (extension_loaded("imap")) {
- class Db {
+ class Db extends SqlDb {
public $extension = "IMAP";
- public $flavor = '';
- public $error;
public $server_info = "?"; // imap_mailboxmsginfo() or imap_check() don't return anything useful
private $mailbox;
private $imap;
define('Adminer\DRIVER', "mongo");
if (class_exists('MongoDB\Driver\Manager')) {
- class Db {
- public $extension = "MongoDB", $flavor = '', $server_info = MONGODB_VERSION, $affected_rows, $error, $last_id;
+ class Db extends SqlDb {
+ public $extension = "MongoDB", $server_info = MONGODB_VERSION, $last_id;
/** @var \MongoDB\Driver\Manager */
public $_link;
public $_db, $_db_name;
}
}
- function query($query) {
+ function query($query, $unbuffered = false) {
return false;
}
$driver = driver();
$fields = fields_from_edit();
if (!$fields) {
- $result = $driver->select($table, array("*"), null, null, array(), 10);
+ $result = $driver->select($table, array("*"), array(), array(), array(), 10);
if ($result) {
while ($row = $result->fetch_assoc()) {
foreach ($row as $key => $val) {
define('Adminer\DRIVER', "simpledb");
if (class_exists('SimpleXMLElement') && ini_bool('allow_url_fopen')) {
- class Db {
- public $extension = "SimpleXML", $flavor = '', $server_info = '2009-04-15', $error, $timeout, $next, $affected_rows;
- private $result;
+ class Db extends SqlDb {
+ public $extension = "SimpleXML", $server_info = '2009-04-15', $timeout, $next;
function select_db($database) {
return ($database == "domain");
return new Result($result);
}
- function multi_query($query) {
- return $this->result = $this->query($query);
- }
-
- function store_result() {
- return $this->result;
- }
-
- function next_result() {
- return false;
- }
-
function quote($string) {
return "'" . str_replace("'", "''", $string) . "'";
}