Merge pull request #18014 from MauricioFauth/connection-dbal

Create Dbal\Connection class
This commit is contained in:
Maurício Meneghini Fauth 2023-01-16 19:52:42 -03:00 committed by GitHub
commit e2bda4fb48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 288 additions and 491 deletions

View File

@ -609,19 +609,18 @@ final class Common
* Try to connect MySQL with the control user profile (will be used to get the privileges list for the current
* user but the true user link must be open after this one so it would be default one for all the scripts).
*/
$controlLink = false;
$controlConnection = null;
if ($GLOBALS['cfg']['Server']['controluser'] !== '') {
$controlLink = $dbi->connect(DatabaseInterface::CONNECT_CONTROL);
$controlConnection = $dbi->connect(DatabaseInterface::CONNECT_CONTROL);
}
// Connects to the server (validates user's login)
$userLink = $dbi->connect(DatabaseInterface::CONNECT_USER);
if ($userLink === false) {
$userConnection = $dbi->connect(DatabaseInterface::CONNECT_USER);
if ($userConnection === null) {
$auth->showFailure('mysql-denied');
}
if ($controlLink) {
if ($controlConnection !== null) {
return;
}

View File

@ -1,7 +1,4 @@
<?php
/**
* Main interface for database interactions
*/
declare(strict_types=1);
@ -9,6 +6,7 @@ namespace PhpMyAdmin;
use PhpMyAdmin\Config\Settings\Server;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Dbal\Connection;
use PhpMyAdmin\Dbal\DatabaseName;
use PhpMyAdmin\Dbal\DbalInterface;
use PhpMyAdmin\Dbal\DbiExtension;
@ -41,7 +39,6 @@ use function explode;
use function implode;
use function is_array;
use function is_int;
use function is_object;
use function is_string;
use function mb_strtolower;
use function microtime;
@ -111,11 +108,11 @@ class DatabaseInterface implements DbalInterface
private $extension;
/**
* Opened database links
* Opened database connections.
*
* @var array<int, object>
* @var array<int, Connection>
*/
private $links;
private $connections;
/** @var array<int, string>|null */
private $currentUserAndHost = null;
@ -155,10 +152,10 @@ class DatabaseInterface implements DbalInterface
public function __construct(DbiExtension $ext)
{
$this->extension = $ext;
$this->links = [];
$this->connections = [];
if (defined('TESTSUITE')) {
$this->links[self::CONNECT_USER] = new stdClass();
$this->links[self::CONNECT_CONTROL] = new stdClass();
$this->connections[self::CONNECT_USER] = new Connection(new stdClass());
$this->connections[self::CONNECT_CONTROL] = new Connection(new stdClass());
}
$this->cache = new Cache();
@ -169,21 +166,20 @@ class DatabaseInterface implements DbalInterface
* runs a query
*
* @param string $query SQL query to execute
* @param int $link optional database link to use
* @param int $options optional query options
* @param bool $cacheAffectedRows whether to cache affected rows
*/
public function query(
string $query,
int $link = self::CONNECT_USER,
int $connectionType = self::CONNECT_USER,
int $options = self::QUERY_BUFFERED,
bool $cacheAffectedRows = true
): ResultInterface {
$result = $this->tryQuery($query, $link, $options, $cacheAffectedRows);
$result = $this->tryQuery($query, $connectionType, $options, $cacheAffectedRows);
if (! $result) {
// The following statement will exit
Generator::mysqlDie($this->getError($link), $query);
Generator::mysqlDie($this->getError($connectionType), $query);
exit;
}
@ -200,7 +196,6 @@ class DatabaseInterface implements DbalInterface
* runs a query and returns the result
*
* @param string $query query to run
* @param int $link link type
* @param int $options if DatabaseInterface::QUERY_UNBUFFERED
* is provided, it will instruct the extension
* to use unbuffered mode
@ -210,26 +205,26 @@ class DatabaseInterface implements DbalInterface
*/
public function tryQuery(
string $query,
int $link = self::CONNECT_USER,
int $connectionType = self::CONNECT_USER,
int $options = self::QUERY_BUFFERED,
bool $cacheAffectedRows = true
) {
$debug = isset($GLOBALS['cfg']['DBG']) && $GLOBALS['cfg']['DBG']['sql'];
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
$time = microtime(true);
$result = $this->extension->realQuery($query, $this->links[$link], $options);
$result = $this->extension->realQuery($query, $this->connections[$connectionType], $options);
if ($cacheAffectedRows) {
$GLOBALS['cached_affected_rows'] = $this->affectedRows($link, false);
$GLOBALS['cached_affected_rows'] = $this->affectedRows($connectionType, false);
}
$this->lastQueryExecutionTime = microtime(true) - $time;
if ($debug) {
$errorMessage = $this->getError($link);
$errorMessage = $this->getError($connectionType);
Utilities::debugLogQueryIntoSession(
$query,
$errorMessage !== '' ? $errorMessage : null,
@ -246,9 +241,9 @@ class DatabaseInterface implements DbalInterface
basename($_SERVER['SCRIPT_NAME']),
Common::getRequest()->getRoute(),
$this->lastQueryExecutionTime,
$this->getWarningCount($link),
$this->getWarningCount($connectionType),
$cacheAffectedRows ? 'y' : 'n',
$link,
$connectionType,
$query
)
);
@ -267,17 +262,16 @@ class DatabaseInterface implements DbalInterface
* Send multiple SQL queries to the database server and execute the first one
*
* @param string $multiQuery multi query statement to execute
* @param int $link index of the opened database link
*/
public function tryMultiQuery(
string $multiQuery = '',
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): bool {
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
return $this->extension->realMultiQuery($this->links[$link], $multiQuery);
return $this->extension->realMultiQuery($this->connections[$connectionType], $multiQuery);
}
/**
@ -318,11 +312,10 @@ class DatabaseInterface implements DbalInterface
* returns array with table names for given db
*
* @param string $database name of database
* @param int $link mysql link resource|object
*
* @return array<int, string> tables names
*/
public function getTables(string $database, int $link = self::CONNECT_USER): array
public function getTables(string $database, int $connectionType = self::CONNECT_USER): array
{
if ($database === '') {
return [];
@ -333,7 +326,7 @@ class DatabaseInterface implements DbalInterface
'SHOW TABLES FROM ' . Util::backquote($database) . ';',
null,
0,
$link
$connectionType
);
if ($GLOBALS['cfg']['NaturalOrder']) {
usort($tables, 'strnatcasecmp');
@ -364,7 +357,6 @@ class DatabaseInterface implements DbalInterface
* @param string $sortBy table attribute to sort by
* @param string $sortOrder direction to sort (ASC or DESC)
* @param string|null $tableType whether table or view
* @param int $link link type
*
* @return array list of tables in given db(s)
*
@ -379,7 +371,7 @@ class DatabaseInterface implements DbalInterface
string $sortBy = 'Name',
string $sortOrder = 'ASC',
?string $tableType = null,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): array {
if ($limitCount === true) {
$limitCount = $GLOBALS['cfg']['MaxTableList'];
@ -429,7 +421,7 @@ class DatabaseInterface implements DbalInterface
'TABLE_NAME',
],
null,
$link
$connectionType
);
// here, we check for Mroonga engine and compute the good data_length and index_length
@ -502,16 +494,15 @@ class DatabaseInterface implements DbalInterface
. implode(
', ',
array_map(
[
$this,
'quoteString',
],
$table,
$link
function (string $string) use ($connectionType): string {
return $this->quoteString($string, $connectionType);
},
$table
)
) . ')';
} else {
$sql .= ' `Name` LIKE ' . $this->quoteString($this->escapeMysqlWildcards($table) . '%', $link);
$sql .= ' `Name` LIKE '
. $this->quoteString($this->escapeMysqlWildcards($table) . '%', $connectionType);
}
$needAnd = true;
@ -530,7 +521,7 @@ class DatabaseInterface implements DbalInterface
}
}
$eachTables = $this->fetchResult($sql, 'Name', null, $link);
$eachTables = $this->fetchResult($sql, 'Name', null, $connectionType);
// here, we check for Mroonga engine and compute the good data_length and index_length
// in the StructureController only we need to sum the two values as the other engines
@ -644,7 +635,6 @@ class DatabaseInterface implements DbalInterface
*
* @param string|null $database database
* @param bool $forceStats retrieve stats also for MySQL < 5
* @param int $link link type
* @param string $sortBy column to order by
* @param string $sortOrder ASC or DESC
* @param int $limitOffset starting offset for LIMIT
@ -657,7 +647,7 @@ class DatabaseInterface implements DbalInterface
public function getDatabasesFull(
?string $database = null,
bool $forceStats = false,
int $link = self::CONNECT_USER,
int $connectionType = self::CONNECT_USER,
string $sortBy = 'SCHEMA_NAME',
string $sortOrder = 'ASC',
int $limitOffset = 0,
@ -690,7 +680,7 @@ class DatabaseInterface implements DbalInterface
$sqlWhereSchema = '';
if ($database !== null) {
$sqlWhereSchema = 'WHERE `SCHEMA_NAME` LIKE \''
. $this->escapeString($database, $link) . '\'';
. $this->escapeString($database, $connectionType) . '\'';
}
$sql = QueryGenerator::getInformationSchemaDatabasesFullRequest(
@ -701,9 +691,9 @@ class DatabaseInterface implements DbalInterface
$limit
);
$databases = $this->fetchResult($sql, 'SCHEMA_NAME', null, $link);
$databases = $this->fetchResult($sql, 'SCHEMA_NAME', null, $connectionType);
$mysqlError = $this->getError($link);
$mysqlError = $this->getError($connectionType);
if (! count($databases) && isset($GLOBALS['errno'])) {
Generator::mysqlDie($mysqlError, $sql);
}
@ -831,7 +821,6 @@ class DatabaseInterface implements DbalInterface
* @param string|null $database name of database
* @param string|null $table name of table to retrieve columns from
* @param string|null $column name of specific column
* @param int $link mysql link resource
*
* @return array
*/
@ -839,23 +828,23 @@ class DatabaseInterface implements DbalInterface
?string $database = null,
?string $table = null,
?string $column = null,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): array {
if (! $GLOBALS['cfg']['Server']['DisableIS']) {
$sql = QueryGenerator::getInformationSchemaColumnsFullRequest(
$database !== null ? $this->quoteString($database, $link) : null,
$table !== null ? $this->quoteString($table, $link) : null,
$column !== null ? $this->quoteString($column, $link) : null
$database !== null ? $this->quoteString($database, $connectionType) : null,
$table !== null ? $this->quoteString($table, $connectionType) : null,
$column !== null ? $this->quoteString($column, $connectionType) : null
);
$arrayKeys = QueryGenerator::getInformationSchemaColumns($database, $table, $column);
return $this->fetchResult($sql, $arrayKeys, null, $link);
return $this->fetchResult($sql, $arrayKeys, null, $connectionType);
}
$columns = [];
if ($database === null) {
foreach ($this->getDatabaseList() as $database) {
$columns[$database] = $this->getColumnsFull($database, null, null, $link);
$columns[$database] = $this->getColumnsFull($database, null, null, $connectionType);
}
return $columns;
@ -864,7 +853,7 @@ class DatabaseInterface implements DbalInterface
if ($table === null) {
$tables = $this->getTables($database);
foreach ($tables as $table) {
$columns[$table] = $this->getColumnsFull($database, $table, null, $link);
$columns[$table] = $this->getColumnsFull($database, $table, null, $connectionType);
}
return $columns;
@ -873,10 +862,10 @@ class DatabaseInterface implements DbalInterface
$sql = 'SHOW FULL COLUMNS FROM '
. Util::backquote($database) . '.' . Util::backquote($table);
if ($column !== null) {
$sql .= " LIKE '" . $this->escapeString($column, $link) . "'";
$sql .= " LIKE '" . $this->escapeString($column, $connectionType) . "'";
}
$columns = $this->fetchResult($sql, 'Field', null, $link);
$columns = $this->fetchResult($sql, 'Field', null, $connectionType);
$columns = Compatibility::getISCompatForGetColumnsFull($columns, $database, $table);
@ -894,7 +883,6 @@ class DatabaseInterface implements DbalInterface
* @param string $table name of table to retrieve columns from
* @param string $column name of column
* @param bool $full whether to return full info or only column names
* @param int $link link type
*
* @return array flat array description
*/
@ -903,7 +891,7 @@ class DatabaseInterface implements DbalInterface
string $table,
string $column,
bool $full = false,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): array {
$sql = QueryGenerator::getColumnsSql(
$database,
@ -912,7 +900,7 @@ class DatabaseInterface implements DbalInterface
$full
);
/** @var array<string, array> $fields */
$fields = $this->fetchResult($sql, 'Field', null, $link);
$fields = $this->fetchResult($sql, 'Field', null, $connectionType);
$columns = $this->attachIndexInfoToColumns($database, $table, $fields);
@ -925,7 +913,6 @@ class DatabaseInterface implements DbalInterface
* @param string $database name of database
* @param string $table name of table to retrieve columns from
* @param bool $full whether to return full info or only column names
* @param int $link link type
*
* @return array<string, array> array indexed by column names
*/
@ -933,7 +920,7 @@ class DatabaseInterface implements DbalInterface
string $database,
string $table,
bool $full = false,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): array {
$sql = QueryGenerator::getColumnsSql(
$database,
@ -942,7 +929,7 @@ class DatabaseInterface implements DbalInterface
$full
);
/** @var array<string, array> $fields */
$fields = $this->fetchResult($sql, 'Field', null, $link);
$fields = $this->fetchResult($sql, 'Field', null, $connectionType);
return $this->attachIndexInfoToColumns($database, $table, $fields);
}
@ -998,19 +985,18 @@ class DatabaseInterface implements DbalInterface
*
* @param string $database name of database
* @param string $table name of table to retrieve columns from
* @param int $link mysql link resource
*
* @return string[]
*/
public function getColumnNames(
string $database,
string $table,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): array {
$sql = QueryGenerator::getColumnsSql($database, $table);
// We only need the 'Field' column which contains the table's column names
return $this->fetchResult($sql, null, 'Field', $link);
return $this->fetchResult($sql, null, 'Field', $connectionType);
}
/**
@ -1018,7 +1004,6 @@ class DatabaseInterface implements DbalInterface
*
* @param string $database name of database
* @param string $table name of the table whose indexes are to be retrieved
* @param int $link mysql link resource
*
* @return array<int, array<string, string|null>>
* @psalm-return array<int, array{
@ -1043,11 +1028,11 @@ class DatabaseInterface implements DbalInterface
public function getTableIndexes(
string $database,
string $table,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): array {
$sql = QueryGenerator::getTableIndexesSql($database, $table);
return $this->fetchResult($sql, null, null, $link);
return $this->fetchResult($sql, null, null, $connectionType);
}
/**
@ -1056,14 +1041,13 @@ class DatabaseInterface implements DbalInterface
* @param string $var mysql server variable name
* @param int $type DatabaseInterface::GETVAR_SESSION |
* DatabaseInterface::GETVAR_GLOBAL
* @param int $link mysql link resource|object
*
* @return false|string|null value for mysql server variable
*/
public function getVariable(
string $var,
int $type = self::GETVAR_SESSION,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
) {
switch ($type) {
case self::GETVAR_SESSION:
@ -1076,7 +1060,7 @@ class DatabaseInterface implements DbalInterface
$modifier = '';
}
return $this->fetchValue('SHOW' . $modifier . ' VARIABLES LIKE \'' . $var . '\';', 1, $link);
return $this->fetchValue('SHOW' . $modifier . ' VARIABLES LIKE \'' . $var . '\';', 1, $connectionType);
}
/**
@ -1084,19 +1068,18 @@ class DatabaseInterface implements DbalInterface
*
* @param string $var variable name
* @param string $value value to set
* @param int $link mysql link resource|object
*/
public function setVariable(
string $var,
string $value,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): bool {
$currentValue = $this->getVariable($var, self::GETVAR_SESSION, $link);
$currentValue = $this->getVariable($var, self::GETVAR_SESSION, $connectionType);
if ($currentValue == $value) {
return true;
}
return (bool) $this->query('SET ' . $var . ' = ' . $value . ';', $link);
return (bool) $this->query('SET ' . $var . ' = ' . $value . ';', $connectionType);
}
/**
@ -1222,16 +1205,15 @@ class DatabaseInterface implements DbalInterface
* @param string $query The query to execute
* @param int|string $field field to fetch the value from,
* starting at 0, with 0 being default
* @param int $link link type
*
* @return string|false|null value of first field in first row from result or false if not found
*/
public function fetchValue(
string $query,
$field = 0,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
) {
$result = $this->tryQuery($query, $link, self::QUERY_BUFFERED, false);
$result = $this->tryQuery($query, $connectionType, self::QUERY_BUFFERED, false);
if ($result === false) {
return false;
}
@ -1252,15 +1234,14 @@ class DatabaseInterface implements DbalInterface
* @param string $query The query to execute
* @param string $type NUM|ASSOC|BOTH returned array should either numeric
* associative or both
* @param int $link link type
* @psalm-param DatabaseInterface::FETCH_NUM|DatabaseInterface::FETCH_ASSOC $type
*/
public function fetchSingleRow(
string $query,
string $type = DbalInterface::FETCH_ASSOC,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): ?array {
$result = $this->tryQuery($query, $link, self::QUERY_BUFFERED, false);
$result = $this->tryQuery($query, $connectionType, self::QUERY_BUFFERED, false);
if ($result === false) {
return null;
}
@ -1341,7 +1322,6 @@ class DatabaseInterface implements DbalInterface
* or array of those
* @param string|int|null $value value-name or offset
* used as value for array
* @param int $link link type
*
* @return array resultrows or values indexed by $key
*/
@ -1349,11 +1329,11 @@ class DatabaseInterface implements DbalInterface
string $query,
$key = null,
$value = null,
int $link = self::CONNECT_USER
int $connectionType = self::CONNECT_USER
): array {
$resultRows = [];
$result = $this->tryQuery($query, $link, self::QUERY_BUFFERED, false);
$result = $this->tryQuery($query, $connectionType, self::QUERY_BUFFERED, false);
// return empty array if result is empty or false
if ($result === false) {
@ -1431,13 +1411,11 @@ class DatabaseInterface implements DbalInterface
/**
* returns warnings for last query
*
* @param int $link link type
*
* @return Warning[] warnings
*/
public function getWarnings(int $link = self::CONNECT_USER): array
public function getWarnings(int $connectionType = self::CONNECT_USER): array
{
$result = $this->tryQuery('SHOW WARNINGS', $link, 0, false);
$result = $this->tryQuery('SHOW WARNINGS', $connectionType, 0, false);
if ($result === false) {
return [];
}
@ -1575,7 +1553,7 @@ class DatabaseInterface implements DbalInterface
public function isConnected(): bool
{
return isset($this->links[self::CONNECT_USER]);
return isset($this->connections[self::CONNECT_USER]);
}
/**
@ -1623,16 +1601,14 @@ class DatabaseInterface implements DbalInterface
}
/**
* connects to the database server
* Connects to the database server.
*
* @param int $mode Connection mode on of CONNECT_USER, CONNECT_CONTROL
* or CONNECT_AUXILIARY.
* @param array|null $server Server information like host/port/socket/persistent
* @param int|null $target How to store connection link, defaults to $mode
*
* @return object|false false on error or a connection object on success
*/
public function connect(int $mode, ?array $server = null, ?int $target = null)
public function connect(int $mode, ?array $server = null, ?int $target = null): ?Connection
{
[$user, $password, $server] = Config::getConnectionParams($mode, $server);
@ -1646,7 +1622,7 @@ class DatabaseInterface implements DbalInterface
E_USER_WARNING
);
return false;
return null;
}
$server['host'] = ! is_string($server['host']) || $server['host'] === '' ? 'localhost' : $server['host'];
@ -1656,8 +1632,8 @@ class DatabaseInterface implements DbalInterface
$result = $this->extension->connect($user, $password, new Server($server));
$GLOBALS['errorHandler']->setHideLocation(false);
if (is_object($result)) {
$this->links[$target] = $result;
if ($result !== null) {
$this->connections[$target] = $result;
/* Run post connect for user connections */
if ($target == self::CONNECT_USER) {
$this->postConnect();
@ -1674,13 +1650,13 @@ class DatabaseInterface implements DbalInterface
E_USER_WARNING
);
return false;
return null;
}
if ($mode == self::CONNECT_AUXILIARY) {
// Do not go back to main login if connection failed
// (currently used only in unit testing)
return false;
return null;
}
return $result;
@ -1690,91 +1666,80 @@ class DatabaseInterface implements DbalInterface
* selects given database
*
* @param string|DatabaseName $dbname database name to select
* @param int $link link type
*/
public function selectDb($dbname, int $link = self::CONNECT_USER): bool
public function selectDb($dbname, int $connectionType = self::CONNECT_USER): bool
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
return $this->extension->selectDb($dbname, $this->links[$link]);
return $this->extension->selectDb($dbname, $this->connections[$connectionType]);
}
/**
* Check if there are any more query results from a multi query
*
* @param int $link link type
*/
public function moreResults(int $link = self::CONNECT_USER): bool
public function moreResults(int $connectionType = self::CONNECT_USER): bool
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
return $this->extension->moreResults($this->links[$link]);
return $this->extension->moreResults($this->connections[$connectionType]);
}
/**
* Prepare next result from multi_query
*
* @param int $link link type
*/
public function nextResult(int $link = self::CONNECT_USER): bool
public function nextResult(int $connectionType = self::CONNECT_USER): bool
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
return $this->extension->nextResult($this->links[$link]);
return $this->extension->nextResult($this->connections[$connectionType]);
}
/**
* Store the result returned from multi query
*
* @param int $link link type
*
* @return ResultInterface|false false when empty results / result set when not empty
*/
public function storeResult(int $link = self::CONNECT_USER)
public function storeResult(int $connectionType = self::CONNECT_USER)
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
return $this->extension->storeResult($this->links[$link]);
return $this->extension->storeResult($this->connections[$connectionType]);
}
/**
* Returns a string representing the type of connection used
*
* @param int $link link type
*
* @return string|bool type of connection used
*/
public function getHostInfo(int $link = self::CONNECT_USER)
public function getHostInfo(int $connectionType = self::CONNECT_USER)
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
return $this->extension->getHostInfo($this->links[$link]);
return $this->extension->getHostInfo($this->connections[$connectionType]);
}
/**
* Returns the version of the MySQL protocol used
*
* @param int $link link type
*
* @return int|bool version of the MySQL protocol used
*/
public function getProtoInfo(int $link = self::CONNECT_USER)
public function getProtoInfo(int $connectionType = self::CONNECT_USER)
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return false;
}
return $this->extension->getProtoInfo($this->links[$link]);
return $this->extension->getProtoInfo($this->connections[$connectionType]);
}
/**
@ -1789,16 +1754,14 @@ class DatabaseInterface implements DbalInterface
/**
* Returns last error message or an empty string if no errors occurred.
*
* @param int $link link type
*/
public function getError(int $link = self::CONNECT_USER): string
public function getError(int $connectionType = self::CONNECT_USER): string
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return '';
}
return $this->extension->getError($this->links[$link]);
return $this->extension->getError($this->connections[$connectionType]);
}
/**
@ -1824,10 +1787,8 @@ class DatabaseInterface implements DbalInterface
/**
* returns last inserted auto_increment id for given $link
* or $GLOBALS['userlink']
*
* @param int $link link type
*/
public function insertId(int $link = self::CONNECT_USER): int
public function insertId(int $connectionType = self::CONNECT_USER): int
{
// If the primary key is BIGINT we get an incorrect result
// (sometimes negative, sometimes positive)
@ -1837,23 +1798,22 @@ class DatabaseInterface implements DbalInterface
// When no controluser is defined, using mysqli_insert_id($link)
// does not always return the last insert id due to a mixup with
// the tracking mechanism, but this works:
return (int) $this->fetchValue('SELECT LAST_INSERT_ID();', 0, $link);
return (int) $this->fetchValue('SELECT LAST_INSERT_ID();', 0, $connectionType);
}
/**
* returns the number of rows affected by last query
*
* @param int $link link type
* @param bool $getFromCache whether to retrieve from cache
*
* @return int|string
* @psalm-return int|numeric-string
*/
public function affectedRows(
int $link = self::CONNECT_USER,
int $connectionType = self::CONNECT_USER,
bool $getFromCache = true
) {
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return -1;
}
@ -1861,7 +1821,7 @@ class DatabaseInterface implements DbalInterface
return $GLOBALS['cached_affected_rows'];
}
return $this->extension->affectedRows($this->links[$link]);
return $this->extension->affectedRows($this->connections[$connectionType]);
}
/**
@ -1901,16 +1861,15 @@ class DatabaseInterface implements DbalInterface
/**
* Returns properly quoted string for use in MySQL queries.
*
* @param string $str string to be quoted
* @param int $link optional database link to use
* @param string $str string to be quoted
*
* @psalm-return non-empty-string
*
* @psalm-taint-escape sql
*/
public function quoteString(string $str, int $link = self::CONNECT_USER): string
public function quoteString(string $str, int $connectionType = self::CONNECT_USER): string
{
return "'" . $this->extension->escapeString($this->links[$link], $str) . "'";
return "'" . $this->extension->escapeString($this->connections[$connectionType], $str) . "'";
}
/**
@ -1918,15 +1877,14 @@ class DatabaseInterface implements DbalInterface
*
* @deprecated Use {@see quoteString()} instead.
*
* @param string $str string to be escaped
* @param int $link optional database link to use
* @param string $str string to be escaped
*
* @return string a MySQL escaped string
*/
public function escapeString(string $str, int $link = self::CONNECT_USER): string
public function escapeString(string $str, int $connectionType = self::CONNECT_USER): string
{
if (isset($this->links[$link])) {
return $this->extension->escapeString($this->links[$link], $str);
if (isset($this->connections[$connectionType])) {
return $this->extension->escapeString($this->connections[$connectionType], $str);
}
return $str;
@ -2112,13 +2070,12 @@ class DatabaseInterface implements DbalInterface
* Prepare an SQL statement for execution.
*
* @param string $query The query, as a string.
* @param int $link Link type.
*
* @return object|false A statement object or false.
*/
public function prepare(string $query, int $link = self::CONNECT_USER)
public function prepare(string $query, int $connectionType = self::CONNECT_USER)
{
return $this->extension->prepare($this->links[$link], $query);
return $this->extension->prepare($this->connections[$connectionType], $query);
}
public function getDatabaseList(): ListDatabase
@ -2133,12 +2090,12 @@ class DatabaseInterface implements DbalInterface
/**
* Returns the number of warnings from the last query.
*/
private function getWarningCount(int $link): int
private function getWarningCount(int $connectionType): int
{
if (! isset($this->links[$link])) {
if (! isset($this->connections[$connectionType])) {
return 0;
}
return $this->extension->getWarningCount($this->links[$link]);
return $this->extension->getWarningCount($this->connections[$connectionType]);
}
}

View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Dbal;
/**
* @psalm-immutable
*/
final class Connection
{
/** @var object */
public $connection;
public function __construct(object $connection)
{
$this->connection = $connection;
}
}

View File

@ -22,13 +22,12 @@ interface DbalInterface
* runs a query
*
* @param string $query SQL query to execute
* @param int $link optional database link to use
* @param int $options optional query options
* @param bool $cacheAffectedRows whether to cache affected rows
*/
public function query(
string $query,
int $link = DatabaseInterface::CONNECT_USER,
int $connectionType = DatabaseInterface::CONNECT_USER,
int $options = 0,
bool $cacheAffectedRows = true
): ResultInterface;
@ -37,7 +36,6 @@ interface DbalInterface
* runs a query and returns the result
*
* @param string $query query to run
* @param int $link link type
* @param int $options query options
* @param bool $cacheAffectedRows whether to cache affected row
*
@ -45,7 +43,7 @@ interface DbalInterface
*/
public function tryQuery(
string $query,
int $link = DatabaseInterface::CONNECT_USER,
int $connectionType = DatabaseInterface::CONNECT_USER,
int $options = 0,
bool $cacheAffectedRows = true
);
@ -54,22 +52,20 @@ interface DbalInterface
* Send multiple SQL queries to the database server and execute the first one
*
* @param string $multiQuery multi query statement to execute
* @param int $link index of the opened database link
*/
public function tryMultiQuery(
string $multiQuery = '',
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): bool;
/**
* returns array with table names for given db
*
* @param string $database name of database
* @param int $link mysql link resource|object
*
* @return array<int, string> tables names
*/
public function getTables(string $database, int $link = DatabaseInterface::CONNECT_USER): array;
public function getTables(string $database, int $connectionType = DatabaseInterface::CONNECT_USER): array;
/**
* returns array of all tables in given db or dbs
@ -93,7 +89,6 @@ interface DbalInterface
* @param string $sortBy table attribute to sort by
* @param string $sortOrder direction to sort (ASC or DESC)
* @param string|null $tableType whether table or view
* @param int $link link type
*
* @return array list of tables in given db(s)
*
@ -108,7 +103,7 @@ interface DbalInterface
string $sortBy = 'Name',
string $sortOrder = 'ASC',
?string $tableType = null,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): array;
/**
@ -125,7 +120,6 @@ interface DbalInterface
*
* @param string|null $database database
* @param bool $forceStats retrieve stats also for MySQL < 5
* @param int $link link type
* @param string $sortBy column to order by
* @param string $sortOrder ASC or DESC
* @param int $limitOffset starting offset for LIMIT
@ -138,7 +132,7 @@ interface DbalInterface
public function getDatabasesFull(
?string $database = null,
bool $forceStats = false,
int $link = DatabaseInterface::CONNECT_USER,
int $connectionType = DatabaseInterface::CONNECT_USER,
string $sortBy = 'SCHEMA_NAME',
string $sortOrder = 'ASC',
int $limitOffset = 0,
@ -162,7 +156,6 @@ interface DbalInterface
* @param string|null $database name of database
* @param string|null $table name of table to retrieve columns from
* @param string|null $column name of specific column
* @param int $link mysql link resource
*
* @return array
*/
@ -170,7 +163,7 @@ interface DbalInterface
?string $database = null,
?string $table = null,
?string $column = null,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): array;
/**
@ -180,7 +173,6 @@ interface DbalInterface
* @param string $table name of table to retrieve columns from
* @param string $column name of column
* @param bool $full whether to return full info or only column names
* @param int $link link type
*
* @return array flat array description
*/
@ -189,7 +181,7 @@ interface DbalInterface
string $table,
string $column,
bool $full = false,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): array;
/**
@ -198,7 +190,6 @@ interface DbalInterface
* @param string $database name of database
* @param string $table name of table to retrieve columns from
* @param bool $full whether to return full info or only column names
* @param int $link link type
*
* @return array<string, array> array indexed by column names
*/
@ -206,7 +197,7 @@ interface DbalInterface
string $database,
string $table,
bool $full = false,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): array;
/**
@ -214,14 +205,13 @@ interface DbalInterface
*
* @param string $database name of database
* @param string $table name of table to retrieve columns from
* @param int $link mysql link resource
*
* @return string[]
*/
public function getColumnNames(
string $database,
string $table,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): array;
/**
@ -229,7 +219,6 @@ interface DbalInterface
*
* @param string $database name of database
* @param string $table name of the table whose indexes are to be retrieved
* @param int $link mysql link resource
*
* @return array<int, array<string, string|null>>
* @psalm-return array<int, array{
@ -254,7 +243,7 @@ interface DbalInterface
public function getTableIndexes(
string $database,
string $table,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): array;
/**
@ -263,14 +252,13 @@ interface DbalInterface
* @param string $var mysql server variable name
* @param int $type DatabaseInterface::GETVAR_SESSION |
* DatabaseInterface::GETVAR_GLOBAL
* @param int $link mysql link resource|object
*
* @return false|string|null value for mysql server variable
*/
public function getVariable(
string $var,
int $type = DatabaseInterface::GETVAR_SESSION,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
);
/**
@ -278,9 +266,12 @@ interface DbalInterface
*
* @param string $var variable name
* @param string $value value to set
* @param int $link mysql link resource|object
*/
public function setVariable(string $var, string $value, int $link = DatabaseInterface::CONNECT_USER): bool;
public function setVariable(
string $var,
string $value,
int $connectionType = DatabaseInterface::CONNECT_USER
): bool;
/**
* Function called just after a connection to the MySQL database server has
@ -319,7 +310,6 @@ interface DbalInterface
* @param int|string $field field to fetch the value from,
* starting at 0, with 0 being
* default
* @param int $link link type
*
* @return string|false|null value of first field in first row from result
* or false if not found
@ -327,7 +317,7 @@ interface DbalInterface
public function fetchValue(
string $query,
$field = 0,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
);
/**
@ -343,13 +333,12 @@ interface DbalInterface
* @param string $query The query to execute
* @param string $type NUM|ASSOC returned array should either numeric
* associative or both
* @param int $link link type
* @psalm-param self::FETCH_NUM|self::FETCH_ASSOC $type
*/
public function fetchSingleRow(
string $query,
string $type = DbalInterface::FETCH_ASSOC,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): ?array;
/**
@ -402,7 +391,6 @@ interface DbalInterface
* @param string|int $value value-name or offset
* used as value for
* array
* @param int $link link type
*
* @return array resultrows or values indexed by $key
*/
@ -410,7 +398,7 @@ interface DbalInterface
string $query,
$key = null,
$value = null,
int $link = DatabaseInterface::CONNECT_USER
int $connectionType = DatabaseInterface::CONNECT_USER
): array;
/**
@ -423,11 +411,9 @@ interface DbalInterface
/**
* returns warnings for last query
*
* @param int $link link type
*
* @return array warnings
*/
public function getWarnings(int $link = DatabaseInterface::CONNECT_USER): array;
public function getWarnings(int $connectionType = DatabaseInterface::CONNECT_USER): array;
/**
* gets the current user with host
@ -465,65 +451,52 @@ interface DbalInterface
public function getLowerCaseNames(): int;
/**
* connects to the database server
* Connects to the database server.
*
* @param int $mode Connection mode on of CONNECT_USER, CONNECT_CONTROL
* or CONNECT_AUXILIARY.
* @param array|null $server Server information like host/port/socket/persistent
* @param int|null $target How to store connection link, defaults to $mode
*
* @return object|false false on error or a connection object on success
*/
public function connect(int $mode, ?array $server = null, ?int $target = null);
public function connect(int $mode, ?array $server = null, ?int $target = null): ?Connection;
/**
* selects given database
*
* @param string|DatabaseName $dbname database name to select
* @param int $link link type
*/
public function selectDb($dbname, int $link = DatabaseInterface::CONNECT_USER): bool;
public function selectDb($dbname, int $connectionType = DatabaseInterface::CONNECT_USER): bool;
/**
* Check if there are any more query results from a multi query
*
* @param int $link link type
*/
public function moreResults(int $link = DatabaseInterface::CONNECT_USER): bool;
public function moreResults(int $connectionType = DatabaseInterface::CONNECT_USER): bool;
/**
* Prepare next result from multi_query
*
* @param int $link link type
*/
public function nextResult(int $link = DatabaseInterface::CONNECT_USER): bool;
public function nextResult(int $connectionType = DatabaseInterface::CONNECT_USER): bool;
/**
* Store the result returned from multi query
*
* @param int $link link type
*
* @return mixed false when empty results / result set when not empty
*/
public function storeResult(int $link = DatabaseInterface::CONNECT_USER);
public function storeResult(int $connectionType = DatabaseInterface::CONNECT_USER);
/**
* Returns a string representing the type of connection used
*
* @param int $link link type
*
* @return string|bool type of connection used
*/
public function getHostInfo(int $link = DatabaseInterface::CONNECT_USER);
public function getHostInfo(int $connectionType = DatabaseInterface::CONNECT_USER);
/**
* Returns the version of the MySQL protocol used
*
* @param int $link link type
*
* @return int|bool version of the MySQL protocol used
*/
public function getProtoInfo(int $link = DatabaseInterface::CONNECT_USER);
public function getProtoInfo(int $connectionType = DatabaseInterface::CONNECT_USER);
/**
* returns a string that represents the client library version
@ -534,10 +507,8 @@ interface DbalInterface
/**
* Returns last error message or an empty string if no errors occurred.
*
* @param int $link link type
*/
public function getError(int $link = DatabaseInterface::CONNECT_USER): string;
public function getError(int $connectionType = DatabaseInterface::CONNECT_USER): string;
/**
* returns the number of rows returned by last query
@ -554,22 +525,19 @@ interface DbalInterface
* returns last inserted auto_increment id for given $link
* or $GLOBALS['userlink']
*
* @param int $link link type
*
* @return int
*/
public function insertId(int $link = DatabaseInterface::CONNECT_USER);
public function insertId(int $connectionType = DatabaseInterface::CONNECT_USER);
/**
* returns the number of rows affected by last query
*
* @param int $link link type
* @param bool $getFromCache whether to retrieve from cache
*
* @return int|string
* @psalm-return int|numeric-string
*/
public function affectedRows(int $link = DatabaseInterface::CONNECT_USER, bool $getFromCache = true);
public function affectedRows(int $connectionType = DatabaseInterface::CONNECT_USER, bool $getFromCache = true);
/**
* returns metainfo for fields in $result
@ -583,26 +551,24 @@ interface DbalInterface
/**
* Returns properly quoted string for use in MySQL queries.
*
* @param string $str string to be quoted
* @param int $link optional database link to use
* @param string $str string to be quoted
*
* @psalm-return non-empty-string
*
* @psalm-taint-escape sql
*/
public function quoteString(string $str, int $link = DatabaseInterface::CONNECT_USER): string;
public function quoteString(string $str, int $connectionType = DatabaseInterface::CONNECT_USER): string;
/**
* returns properly escaped string for use in MySQL queries
*
* @deprecated Use {@see quoteString()} instead.
*
* @param string $str string to be escaped
* @param int $link optional database link to use
* @param string $str string to be escaped
*
* @return string a MySQL escaped string
*/
public function escapeString(string $str, int $link = DatabaseInterface::CONNECT_USER): string;
public function escapeString(string $str, int $connectionType = DatabaseInterface::CONNECT_USER): string;
/**
* Returns properly escaped string for use in MySQL LIKE clauses.
@ -682,9 +648,8 @@ interface DbalInterface
* Prepare an SQL statement for execution.
*
* @param string $query The query, as a string.
* @param int $link Link type.
*
* @return object|false A statement object or false.
*/
public function prepare(string $query, int $link = DatabaseInterface::CONNECT_USER);
public function prepare(string $query, int $connectionType = DatabaseInterface::CONNECT_USER);
}

View File

@ -16,80 +16,65 @@ interface DbiExtension
{
/**
* Connects to the database server.
*
* @return object|false A connection object on success or false on failure.
*/
public function connect(string $user, string $password, Server $server);
public function connect(string $user, string $password, Server $server): ?Connection;
/**
* selects given database
*
* @param string|DatabaseName $databaseName database name to select
* @param object $link connection object
*/
public function selectDb($databaseName, $link): bool;
public function selectDb($databaseName, Connection $connection): bool;
/**
* runs a query and returns the result
*
* @param string $query query to execute
* @param object $link connection object
* @param int $options query options
*
* @return ResultInterface|false result
*/
public function realQuery(string $query, $link, int $options);
public function realQuery(string $query, Connection $connection, int $options);
/**
* Run the multi query and output the results
*
* @param object $link connection object
* @param string $query multi query statement to execute
*
* @return bool
*/
public function realMultiQuery($link, $query);
public function realMultiQuery(Connection $connection, $query);
/**
* Check if there are any more query results from a multi query
*
* @param object $link the connection object
*/
public function moreResults($link): bool;
public function moreResults(Connection $connection): bool;
/**
* Prepare next result from multi_query
*
* @param object $link the connection object
*/
public function nextResult($link): bool;
public function nextResult(Connection $connection): bool;
/**
* Store the result returned from multi query
*
* @param object $link mysql link
*
* @return ResultInterface|false false when empty results / result set when not empty
*/
public function storeResult($link);
public function storeResult(Connection $connection);
/**
* Returns a string representing the type of connection used
*
* @param object $link mysql link
*
* @return string type of connection used
*/
public function getHostInfo($link);
public function getHostInfo(Connection $connection);
/**
* Returns the version of the MySQL protocol used
*
* @param object $link mysql link
*
* @return int|string version of the MySQL protocol used
* @return int version of the MySQL protocol used
*/
public function getProtoInfo($link);
public function getProtoInfo(Connection $connection);
/**
* returns a string that represents the client library version
@ -100,45 +85,37 @@ interface DbiExtension
/**
* Returns last error message or an empty string if no errors occurred.
*
* @param object $link connection link
*/
public function getError($link): string;
public function getError(Connection $connection): string;
/**
* returns the number of rows affected by last query
*
* @param object $link the connection object
*
* @return int|string
* @psalm-return int|numeric-string
*/
public function affectedRows($link);
public function affectedRows(Connection $connection);
/**
* returns properly escaped string for use in MySQL queries
*
* @param object $link database link
* @param string $string string to be escaped
*
* @return string a MySQL escaped string
*/
public function escapeString($link, $string);
public function escapeString(Connection $connection, $string);
/**
* Prepare an SQL statement for execution.
*
* @param object $link database link
* @param string $query The query, as a string.
*
* @return object|false A statement object or false.
*/
public function prepare($link, string $query);
public function prepare(Connection $connection, string $query);
/**
* Returns the number of warnings from the last query.
*
* @param object $link
*/
public function getWarningCount($link): int;
public function getWarningCount(Connection $connection): int;
}

View File

@ -16,8 +16,6 @@ use PhpMyAdmin\Query\Utilities;
use function __;
use function defined;
use function mysqli_connect_errno;
use function mysqli_connect_error;
use function mysqli_get_client_info;
use function mysqli_init;
use function mysqli_report;
@ -43,19 +41,14 @@ use const MYSQLI_USE_RESULT;
*/
class DbiMysqli implements DbiExtension
{
/**
* Connects to the database server.
*
* @return object|false A connection object on success or false on failure.
*/
public function connect(string $user, string $password, Server $server)
public function connect(string $user, string $password, Server $server): ?Connection
{
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = mysqli_init();
if ($mysqli === false) {
return false;
return null;
}
$client_flags = 0;
@ -156,7 +149,7 @@ class DbiMysqli implements DbiExtension
mysqli_report(MYSQLI_REPORT_OFF);
return false;
return null;
}
// phpcs:enable
@ -165,37 +158,41 @@ class DbiMysqli implements DbiExtension
mysqli_report(MYSQLI_REPORT_OFF);
return $mysqli;
return new Connection($mysqli);
}
/**
* selects given database
*
* @param string|DatabaseName $databaseName database name to select
* @param mysqli $link the mysqli object
*/
public function selectDb($databaseName, $link): bool
public function selectDb($databaseName, Connection $connection): bool
{
return $link->select_db((string) $databaseName);
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
return $mysqli->select_db((string) $databaseName);
}
/**
* runs a query and returns the result
*
* @param string $query query to execute
* @param mysqli $link mysqli object
* @param int $options query options
*
* @return MysqliResult|false
*/
public function realQuery(string $query, $link, int $options)
public function realQuery(string $query, Connection $connection, int $options)
{
$method = MYSQLI_STORE_RESULT;
if ($options == ($options | DatabaseInterface::QUERY_UNBUFFERED)) {
$method = MYSQLI_USE_RESULT;
}
$result = $link->query($query, $method);
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
$result = $mysqli->query($query, $method);
if ($result === false) {
return false;
}
@ -206,44 +203,49 @@ class DbiMysqli implements DbiExtension
/**
* Run the multi query and output the results
*
* @param mysqli $link mysqli object
* @param string $query multi query statement to execute
*/
public function realMultiQuery($link, $query): bool
public function realMultiQuery(Connection $connection, $query): bool
{
return $link->multi_query($query);
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
return $mysqli->multi_query($query);
}
/**
* Check if there are any more query results from a multi query
*
* @param mysqli $link the mysqli object
*/
public function moreResults($link): bool
public function moreResults(Connection $connection): bool
{
return $link->more_results();
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
return $mysqli->more_results();
}
/**
* Prepare next result from multi_query
*
* @param mysqli $link the mysqli object
*/
public function nextResult($link): bool
public function nextResult(Connection $connection): bool
{
return $link->next_result();
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
return $mysqli->next_result();
}
/**
* Store the result returned from multi query
*
* @param mysqli $link the mysqli object
*
* @return MysqliResult|false false when empty results / result set when not empty
*/
public function storeResult($link)
public function storeResult(Connection $connection)
{
$result = $link->store_result();
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
$result = $mysqli->store_result();
return $result === false ? false : new MysqliResult($result);
}
@ -251,27 +253,29 @@ class DbiMysqli implements DbiExtension
/**
* Returns a string representing the type of connection used
*
* @param mysqli $link mysql link
*
* @return string type of connection used
*/
public function getHostInfo($link)
public function getHostInfo(Connection $connection)
{
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
return $link->host_info;
return $mysqli->host_info;
}
/**
* Returns the version of the MySQL protocol used
*
* @param mysqli $link mysql link
*
* @return string version of the MySQL protocol used
* @return int version of the MySQL protocol used
*/
public function getProtoInfo($link)
public function getProtoInfo(Connection $connection)
{
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
return $link->protocol_version;
return (int) $mysqli->protocol_version;
}
/**
@ -286,20 +290,16 @@ class DbiMysqli implements DbiExtension
/**
* Returns last error message or an empty string if no errors occurred.
*
* @param mysqli|false|null $link mysql link
*/
public function getError($link): string
public function getError(Connection $connection): string
{
$GLOBALS['errno'] = 0;
if ($link !== null && $link !== false) {
$error_number = $link->errno;
$error_message = $link->error;
} else {
$error_number = mysqli_connect_errno();
$error_message = (string) mysqli_connect_error();
}
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
$error_number = $mysqli->errno;
$error_message = $mysqli->error;
if ($error_number === 0 || $error_message === '') {
return '';
@ -315,52 +315,55 @@ class DbiMysqli implements DbiExtension
/**
* returns the number of rows affected by last query
*
* @param mysqli $link the mysqli object
*
* @return int|string
* @psalm-return int|numeric-string
*/
public function affectedRows($link)
public function affectedRows(Connection $connection)
{
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
return $link->affected_rows;
return $mysqli->affected_rows;
}
/**
* returns properly escaped string for use in MySQL queries
*
* @param mysqli $link database link
* @param string $string string to be escaped
*
* @return string a MySQL escaped string
*/
public function escapeString($link, $string)
public function escapeString(Connection $connection, $string)
{
return $link->real_escape_string($string);
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
return $mysqli->real_escape_string($string);
}
/**
* Prepare an SQL statement for execution.
*
* @param mysqli $link database link
* @param string $query The query, as a string.
*
* @return mysqli_stmt|false A statement object or false.
*/
public function prepare($link, string $query)
public function prepare(Connection $connection, string $query)
{
return $link->prepare($query);
/** @var mysqli $mysqli */
$mysqli = $connection->connection;
return $mysqli->prepare($query);
}
/**
* Returns the number of warnings from the last query.
*
* @param object $link
*/
public function getWarningCount($link): int
public function getWarningCount(Connection $connection): int
{
/** @var mysqli $mysqli */
$mysqli = $link;
$mysqli = $connection->connection;
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
return $mysqli->warning_count;

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace PhpMyAdmin;
use PhpMyAdmin\Dbal\Connection;
use PhpMyAdmin\Dbal\ResultInterface;
use function explode;
@ -122,8 +123,6 @@ class Replication
* @param string $host mysql server's hostname or IP
* @param int $port mysql remote port
* @param string $socket path to unix socket
*
* @return object|false
*/
public function connectToPrimary(
$user,
@ -131,7 +130,7 @@ class Replication
$host = null,
$port = null,
$socket = null
) {
): ?Connection {
$server = [];
$server['user'] = $user;
$server['password'] = $password;

View File

@ -511,14 +511,14 @@ class ReplicationGui
$_SESSION['replication']['sr_action_info'] = __('Unknown error');
// Attempt to connect to the new primary server
$linkToPrimary = $this->replication->connectToPrimary(
$connectionToPrimary = $this->replication->connectToPrimary(
$username,
$pmaPassword,
$hostname,
$port
);
if (! $linkToPrimary) {
if ($connectionToPrimary === null) {
$_SESSION['replication']['sr_action_status'] = 'error';
$_SESSION['replication']['sr_action_info'] = sprintf(
__('Unable to connect to primary %s.'),

View File

@ -3155,11 +3155,6 @@ parameters:
count: 1
path: libraries/classes/DatabaseInterface.php
-
message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getProtoInfo\\(\\) should return bool\\|int but returns int\\|string\\.$#"
count: 1
path: libraries/classes/DatabaseInterface.php
-
message: "#^Method PhpMyAdmin\\\\DatabaseInterface\\:\\:getTablesFull\\(\\) has parameter \\$table with no value type specified in iterable type array\\.$#"
count: 1
@ -3180,11 +3175,6 @@ parameters:
count: 1
path: libraries/classes/DatabaseInterface.php
-
message: "#^Parameter \\#3 \\.\\.\\.\\$args of function array_map expects array, int given\\.$#"
count: 1
path: libraries/classes/DatabaseInterface.php
-
message: "#^Method PhpMyAdmin\\\\Dbal\\\\DbalInterface\\:\\:connect\\(\\) has parameter \\$server with no value type specified in iterable type array\\.$#"
count: 1
@ -3255,66 +3245,6 @@ parameters:
count: 1
path: libraries/classes/Dbal/DbalInterface.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:affectedRows\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:affectedRows\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:escapeString\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:escapeString\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:getHostInfo\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:getHostInfo\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:getProtoInfo\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:getProtoInfo\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:moreResults\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:moreResults\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:nextResult\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:nextResult\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:prepare\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:prepare\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:realMultiQuery\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:realMultiQuery\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:storeResult\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:storeResult\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#1 \\$link \\(mysqli\\|false\\|null\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:getError\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:getError\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#2 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:realQuery\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:realQuery\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Parameter \\#2 \\$link \\(mysqli\\) of method PhpMyAdmin\\\\Dbal\\\\DbiMysqli\\:\\:selectDb\\(\\) should be contravariant with parameter \\$link \\(object\\) of method PhpMyAdmin\\\\Dbal\\\\DbiExtension\\:\\:selectDb\\(\\)$#"
count: 1
path: libraries/classes/Dbal/DbiMysqli.php
-
message: "#^Call to function method_exists\\(\\) with mysqli_result and 'fetch_all' will always evaluate to true\\.$#"
count: 3

View File

@ -5571,12 +5571,6 @@
<EmptyArrayAccess occurrences="1">
<code>$resultTarget[]</code>
</EmptyArrayAccess>
<InvalidArgument occurrences="1">
<code>$link</code>
</InvalidArgument>
<InvalidArrayAccess occurrences="1">
<code>$link</code>
</InvalidArrayAccess>
<InvalidOperand occurrences="6">
<code>$row['Data_free']</code>
<code>$row['Data_length']</code>
@ -5585,19 +5579,11 @@
<code>$row['Max_data_length']</code>
<code>$row['Rows']</code>
</InvalidOperand>
<InvalidReturnStatement occurrences="1">
<code>$this-&gt;extension-&gt;getProtoInfo($this-&gt;links[$link])</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="1">
<code>int|bool</code>
</InvalidReturnType>
<MixedArgument occurrences="10">
<MixedArgument occurrences="8">
<code>$a</code>
<code>$b</code>
<code>$link</code>
<code>$password</code>
<code>$table</code>
<code>$table</code>
<code>$tableData[$sortBy] ?? ''</code>
<code>$this-&gt;versionComment</code>
<code>$this-&gt;versionString</code>
@ -5646,8 +5632,8 @@
<code>reset($columns)</code>
</MixedReturnStatement>
<MixedReturnTypeCoercion occurrences="4">
<code>$this-&gt;fetchResult($sql, null, 'Field', $link)</code>
<code>$this-&gt;fetchResult($sql, null, null, $link)</code>
<code>$this-&gt;fetchResult($sql, null, 'Field', $connectionType)</code>
<code>$this-&gt;fetchResult($sql, null, null, $connectionType)</code>
<code>string[]</code>
</MixedReturnTypeCoercion>
<NullableReturnStatement occurrences="2">
@ -5698,20 +5684,6 @@
</MixedAssignment>
</file>
<file src="libraries/classes/Dbal/DbiMysqli.php">
<MoreSpecificImplementedParamType occurrences="12">
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
<code>$link</code>
</MoreSpecificImplementedParamType>
<PossiblyNullArgument occurrences="1">
<code>$error_message</code>
</PossiblyNullArgument>

View File

@ -6,12 +6,14 @@ namespace PhpMyAdmin\Tests\Dbal;
use mysqli;
use mysqli_result;
use PhpMyAdmin\Dbal\Connection;
use PhpMyAdmin\Dbal\DbiMysqli;
use PhpMyAdmin\Dbal\MysqliResult;
use PhpMyAdmin\Tests\AbstractTestCase;
/**
* @covers \PhpMyAdmin\Dbal\DbiMysqli
* @covers \PhpMyAdmin\Dbal\Connection
*/
class DbiMysqliTest extends AbstractTestCase
{
@ -45,7 +47,7 @@ class DbiMysqliTest extends AbstractTestCase
->with($this->equalTo($databaseName))
->willReturn(true);
$this->assertTrue($this->object->selectDb($databaseName, $mysqli));
$this->assertTrue($this->object->selectDb($databaseName, new Connection($mysqli)));
}
/**
@ -60,7 +62,7 @@ class DbiMysqliTest extends AbstractTestCase
->with($this->equalTo($query))
->willReturn(true);
$this->assertTrue($this->object->realMultiQuery($mysqli, $query));
$this->assertTrue($this->object->realMultiQuery(new Connection($mysqli), $query));
}
/**
@ -76,7 +78,7 @@ class DbiMysqliTest extends AbstractTestCase
->with($this->equalTo($query))
->willReturn($mysqliResult);
$this->assertInstanceOf(MysqliResult::class, $this->object->realQuery($query, $mysqli, 0));
$this->assertInstanceOf(MysqliResult::class, $this->object->realQuery($query, new Connection($mysqli), 0));
}
/**
@ -89,7 +91,7 @@ class DbiMysqliTest extends AbstractTestCase
->method('more_results')
->willReturn(true);
$this->assertTrue($this->object->moreResults($mysqli));
$this->assertTrue($this->object->moreResults(new Connection($mysqli)));
}
/**
@ -102,7 +104,7 @@ class DbiMysqliTest extends AbstractTestCase
->method('next_result')
->willReturn(true);
$this->assertTrue($this->object->nextResult($mysqli));
$this->assertTrue($this->object->nextResult(new Connection($mysqli)));
}
/**
@ -116,7 +118,7 @@ class DbiMysqliTest extends AbstractTestCase
->method('store_result')
->willReturn($mysqliResult);
$this->assertInstanceOf(MysqliResult::class, $this->object->storeResult($mysqli));
$this->assertInstanceOf(MysqliResult::class, $this->object->storeResult(new Connection($mysqli)));
}
/**
@ -130,12 +132,12 @@ class DbiMysqliTest extends AbstractTestCase
->method('real_escape_string')
->willReturn($string);
$this->assertEquals($string, $this->object->escapeString($mysqli, $string));
$this->assertEquals($string, $this->object->escapeString(new Connection($mysqli), $string));
}
public function testGetWarningCount(): void
{
$mysqli = (object) ['warning_count' => 30];
$this->assertSame(30, $this->object->getWarningCount($mysqli));
$this->assertSame(30, $this->object->getWarningCount(new Connection($mysqli)));
}
}

View File

@ -12,6 +12,7 @@ declare(strict_types=1);
namespace PhpMyAdmin\Tests\Stubs;
use PhpMyAdmin\Config\Settings\Server;
use PhpMyAdmin\Dbal\Connection;
use PhpMyAdmin\Dbal\DatabaseName;
use PhpMyAdmin\Dbal\DbiExtension;
use PhpMyAdmin\Dbal\ResultInterface;
@ -95,23 +96,17 @@ class DbiDummy implements DbiExtension
$this->init();
}
/**
* Connects to the database server.
*
* @return object|false A connection object on success or false on failure.
*/
public function connect(string $user, string $password, Server $server)
public function connect(string $user, string $password, Server $server): ?Connection
{
return new stdClass();
return new Connection(new stdClass());
}
/**
* selects given database
*
* @param string|DatabaseName $databaseName name of db to select
* @param object $link mysql link resource
*/
public function selectDb($databaseName, $link): bool
public function selectDb($databaseName, Connection $connection): bool
{
$databaseName = $databaseName instanceof DatabaseName
? $databaseName->getName() : $databaseName;
@ -196,12 +191,11 @@ class DbiDummy implements DbiExtension
* runs a query and returns the result
*
* @param string $query query to run
* @param object $link mysql link resource
* @param int $options query options
*
* @return DummyResult|false
*/
public function realQuery(string $query, $link, int $options)
public function realQuery(string $query, Connection $connection, int $options)
{
$query = trim((string) preg_replace('/ */', ' ', str_replace("\n", ' ', $query)));
$filoQuery = $this->findFiloQuery($query);
@ -232,12 +226,11 @@ class DbiDummy implements DbiExtension
/**
* Run the multi query and output the results
*
* @param object $link connection object
* @param string $query multi query statement to execute
*
* @return bool
*/
public function realMultiQuery($link, $query)
public function realMultiQuery(Connection $connection, $query)
{
return false;
}
@ -311,20 +304,16 @@ class DbiDummy implements DbiExtension
/**
* Check if there are any more query results from a multi query
*
* @param object $link the connection object
*/
public function moreResults($link): bool
public function moreResults(Connection $connection): bool
{
return false;
}
/**
* Prepare next result from multi_query
*
* @param object $link the connection object
*/
public function nextResult($link): bool
public function nextResult(Connection $connection): bool
{
return false;
}
@ -332,11 +321,9 @@ class DbiDummy implements DbiExtension
/**
* Store the result returned from multi query
*
* @param object $link the connection object
*
* @return ResultInterface|false false when empty results / result set when not empty
*/
public function storeResult($link)
public function storeResult(Connection $connection)
{
return false;
}
@ -344,11 +331,9 @@ class DbiDummy implements DbiExtension
/**
* Returns a string representing the type of connection used
*
* @param object $link mysql link
*
* @return string type of connection used
*/
public function getHostInfo($link)
public function getHostInfo(Connection $connection)
{
return '';
}
@ -356,11 +341,9 @@ class DbiDummy implements DbiExtension
/**
* Returns the version of the MySQL protocol used
*
* @param object $link mysql link
*
* @return int version of the MySQL protocol used
*/
public function getProtoInfo($link)
public function getProtoInfo(Connection $connection)
{
return -1;
}
@ -377,10 +360,8 @@ class DbiDummy implements DbiExtension
/**
* Returns last error message or an empty string if no errors occurred.
*
* @param object $link connection link
*/
public function getError($link): string
public function getError(Connection $connection): string
{
foreach ($this->fifoErrorCodes as $i => $code) {
unset($this->fifoErrorCodes[$i]);
@ -413,13 +394,10 @@ class DbiDummy implements DbiExtension
/**
* returns the number of rows affected by last query
*
* @param object $link the mysql object
* @param bool $get_from_cache whether to retrieve from cache
*
* @return int|string
* @psalm-return int|numeric-string
*/
public function affectedRows($link = null, $get_from_cache = true)
public function affectedRows(Connection $connection)
{
return $GLOBALS['cached_affected_rows'] ?? 0;
}
@ -469,12 +447,11 @@ class DbiDummy implements DbiExtension
/**
* returns properly escaped string for use in MySQL queries
*
* @param object $link database link
* @param string $string string to be escaped
*
* @return string a MySQL escaped string
*/
public function escapeString($link, $string)
public function escapeString(Connection $connection, $string)
{
return addslashes($string);
}
@ -519,22 +496,19 @@ class DbiDummy implements DbiExtension
}
/**
* @param object $link link
* @param string $query query
*
* @return object|false
*/
public function prepare($link, string $query)
public function prepare(Connection $connection, string $query)
{
return false;
}
/**
* Returns the number of warnings from the last query.
*
* @param object $link
*/
public function getWarningCount($link): int
public function getWarningCount(Connection $connection): int
{
return 0;
}