| Server IP : 172.67.179.166 / Your IP : 172.70.49.197 Web Server : nginx/1.20.2 System : Linux 172-104-110-161.ip.linodeusercontent.com 3.10.0-1160.36.2.el7.x86_64 #1 SMP Wed Jul 21 11:57:15 UTC 2021 x86_64 User : www ( 1000) PHP Version : 8.1.9 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /www/wwwroot/data.driver-hp.download/framework-4.1.3/system/Database/MySQLi/ |
Upload File : |
<?php
/**
* This file is part of the CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CodeIgniter\Database\MySQLi;
use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Database\Exceptions\DatabaseException;
use LogicException;
use MySQLi;
use mysqli_sql_exception;
use stdClass;
use Throwable;
/**
* Connection for MySQLi
*/
class Connection extends BaseConnection
{
/**
* Database driver
*
* @var string
*/
public $DBDriver = 'MySQLi';
/**
* DELETE hack flag
*
* Whether to use the MySQL "delete hack" which allows the number
* of affected rows to be shown. Uses a preg_replace when enabled,
* adding a bit more processing to all queries.
*
* @var boolean
*/
public $deleteHack = true;
// --------------------------------------------------------------------
/**
* Identifier escape character
*
* @var string
*/
public $escapeChar = '`';
// --------------------------------------------------------------------
/**
* MySQLi object
*
* Has to be preserved without being assigned to $conn_id.
*
* @var MySQLi
*/
public $mysqli;
//--------------------------------------------------------------------
/**
* Connect to the database.
*
* @param boolean $persistent
*
* @return mixed
* @throws DatabaseException
*/
public function connect(bool $persistent = false)
{
// Do we have a socket path?
if ($this->hostname[0] === '/')
{
$hostname = null;
$port = null;
$socket = $this->hostname;
}
else
{
$hostname = ($persistent === true) ? 'p:' . $this->hostname : $this->hostname;
$port = empty($this->port) ? null : $this->port;
$socket = '';
}
$clientFlags = ($this->compress === true) ? MYSQLI_CLIENT_COMPRESS : 0;
$this->mysqli = mysqli_init();
mysqli_report(MYSQLI_REPORT_ALL & ~MYSQLI_REPORT_INDEX);
$this->mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 10);
if (isset($this->strictOn))
{
if ($this->strictOn)
{
$this->mysqli->options(MYSQLI_INIT_COMMAND,
'SET SESSION sql_mode = CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")');
}
else
{
$this->mysqli->options(MYSQLI_INIT_COMMAND, 'SET SESSION sql_mode =
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
@@sql_mode,
"STRICT_ALL_TABLES,", ""),
",STRICT_ALL_TABLES", ""),
"STRICT_ALL_TABLES", ""),
"STRICT_TRANS_TABLES,", ""),
",STRICT_TRANS_TABLES", ""),
"STRICT_TRANS_TABLES", "")'
);
}
}
if (is_array($this->encrypt))
{
$ssl = [];
if (! empty($this->encrypt['ssl_key']))
{
$ssl['key'] = $this->encrypt['ssl_key'];
}
if (! empty($this->encrypt['ssl_cert']))
{
$ssl['cert'] = $this->encrypt['ssl_cert'];
}
if (! empty($this->encrypt['ssl_ca']))
{
$ssl['ca'] = $this->encrypt['ssl_ca'];
}
if (! empty($this->encrypt['ssl_capath']))
{
$ssl['capath'] = $this->encrypt['ssl_capath'];
}
if (! empty($this->encrypt['ssl_cipher']))
{
$ssl['cipher'] = $this->encrypt['ssl_cipher'];
}
if (! empty($ssl))
{
if (isset($this->encrypt['ssl_verify']))
{
if ($this->encrypt['ssl_verify'])
{
defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT') &&
$this->mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, 1);
}
// Apparently (when it exists), setting MYSQLI_OPT_SSL_VERIFY_SERVER_CERT
// to FALSE didn't do anything, so PHP 5.6.16 introduced yet another
// constant ...
//
// https://secure.php.net/ChangeLog-5.php#5.6.16
// https://bugs.php.net/bug.php?id=68344
elseif (defined('MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT') && version_compare($this->mysqli->client_info, 'mysqlnd 5.6', '>='))
{
$clientFlags += MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT;
}
}
$clientFlags += MYSQLI_CLIENT_SSL;
$this->mysqli->ssl_set(
$ssl['key'] ?? null, $ssl['cert'] ?? null, $ssl['ca'] ?? null,
$ssl['capath'] ?? null, $ssl['cipher'] ?? null
);
}
}
try
{
if ($this->mysqli->real_connect($hostname, $this->username, $this->password,
$this->database, $port, $socket, $clientFlags)
)
{
// Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails
if (($clientFlags & MYSQLI_CLIENT_SSL) && version_compare($this->mysqli->client_info, 'mysqlnd 5.7.3', '<=')
&& empty($this->mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")
->fetch_object()->Value)
)
{
$this->mysqli->close();
$message = 'MySQLi was configured for an SSL connection, but got an unencrypted connection instead!';
log_message('error', $message);
if ($this->DBDebug)
{
throw new DatabaseException($message);
}
return false;
}
if (! $this->mysqli->set_charset($this->charset))
{
log_message('error',
"Database: Unable to set the configured connection charset ('{$this->charset}').");
$this->mysqli->close();
if ($this->DBDebug)
{
throw new DatabaseException('Unable to set client connection character set: ' . $this->charset);
}
return false;
}
return $this->mysqli;
}
}
catch (Throwable $e)
{
// Clean sensitive information from errors.
$msg = $e->getMessage();
$msg = str_replace($this->username, '****', $msg);
$msg = str_replace($this->password, '****', $msg);
throw new DatabaseException($msg, $e->getCode(), $e);
}
return false;
}
//--------------------------------------------------------------------
/**
* Keep or establish the connection if no queries have been sent for
* a length of time exceeding the server's idle timeout.
*
* @return void
*/
public function reconnect()
{
$this->close();
$this->initialize();
}
//--------------------------------------------------------------------
/**
* Close the database connection.
*
* @return void
*/
protected function _close()
{
$this->connID->close();
}
//--------------------------------------------------------------------
/**
* Select a specific database table to use.
*
* @param string $databaseName
*
* @return boolean
*/
public function setDatabase(string $databaseName): bool
{
if ($databaseName === '')
{
$databaseName = $this->database;
}
if (empty($this->connID))
{
$this->initialize();
}
if ($this->connID->select_db($databaseName))
{
$this->database = $databaseName;
return true;
}
return false;
}
//--------------------------------------------------------------------
/**
* Returns a string containing the version of the database being used.
*
* @return string
*/
public function getVersion(): string
{
if (isset($this->dataCache['version']))
{
return $this->dataCache['version'];
}
if (empty($this->mysqli))
{
$this->initialize();
}
return $this->dataCache['version'] = $this->mysqli->server_info;
}
//--------------------------------------------------------------------
/**
* Executes the query against the database.
*
* @param string $sql
*
* @return mixed
*/
public function execute(string $sql)
{
while ($this->connID->more_results())
{
$this->connID->next_result();
if ($res = $this->connID->store_result())
{
$res->free();
}
}
try
{
return $this->connID->query($this->prepQuery($sql));
}
catch (mysqli_sql_exception $e)
{
log_message('error', $e->getMessage());
if ($this->DBDebug)
{
throw $e;
}
}
return false;
}
//--------------------------------------------------------------------
/**
* Prep the query
*
* If needed, each database adapter can prep the query string
*
* @param string $sql an SQL query
*
* @return string
*/
protected function prepQuery(string $sql): string
{
// mysqli_affected_rows() returns 0 for "DELETE FROM TABLE" queries. This hack
// modifies the query so that it a proper number of affected rows is returned.
if ($this->deleteHack === true && preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
{
return trim($sql) . ' WHERE 1=1';
}
return $sql;
}
//--------------------------------------------------------------------
/**
* Returns the total number of rows affected by this query.
*
* @return integer
*/
public function affectedRows(): int
{
return $this->connID->affected_rows ?? 0;
}
//--------------------------------------------------------------------
/**
* Platform-dependant string escape
*
* @param string $str
* @return string
*/
protected function _escapeString(string $str): string
{
if (! $this->connID)
{
$this->initialize();
}
return $this->connID->real_escape_string($str);
}
//--------------------------------------------------------------------
/**
* Escape Like String Direct
* There are a few instances where MySQLi queries cannot take the
* additional "ESCAPE x" parameter for specifying the escape character
* in "LIKE" strings, and this handles those directly with a backslash.
*
* @param string|string[] $str Input string
* @return string|string[]
*/
public function escapeLikeStringDirect($str)
{
if (is_array($str))
{
foreach ($str as $key => $val)
{
$str[$key] = $this->escapeLikeStringDirect($val);
}
return $str;
}
$str = $this->_escapeString($str);
// Escape LIKE condition wildcards
return str_replace([
$this->likeEscapeChar,
'%',
'_',
], [
'\\' . $this->likeEscapeChar,
'\\' . '%',
'\\' . '_',
], $str
);
}
//--------------------------------------------------------------------
/**
* Generates the SQL for listing tables in a platform-dependent manner.
* Uses escapeLikeStringDirect().
*
* @param boolean $prefixLimit
*
* @return string
*/
protected function _listTables(bool $prefixLimit = false): string
{
$sql = 'SHOW TABLES FROM ' . $this->escapeIdentifiers($this->database);
if ($prefixLimit !== false && $this->DBPrefix !== '')
{
return $sql . " LIKE '" . $this->escapeLikeStringDirect($this->DBPrefix) . "%'";
}
return $sql;
}
//--------------------------------------------------------------------
/**
* Generates a platform-specific query string so that the column names can be fetched.
*
* @param string $table
*
* @return string
*/
protected function _listColumns(string $table = ''): string
{
return 'SHOW COLUMNS FROM ' . $this->protectIdentifiers($table, true, null, false);
}
//--------------------------------------------------------------------
/**
* Returns an array of objects with field data
*
* @param string $table
* @return stdClass[]
* @throws DatabaseException
*/
public function _fieldData(string $table): array
{
$table = $this->protectIdentifiers($table, true, null, false);
if (($query = $this->query('SHOW COLUMNS FROM ' . $table)) === false)
{
throw new DatabaseException(lang('Database.failGetFieldData'));
}
$query = $query->getResultObject();
$retVal = [];
for ($i = 0, $c = count($query); $i < $c; $i++)
{
$retVal[$i] = new stdClass();
$retVal[$i]->name = $query[$i]->Field;
sscanf($query[$i]->Type, '%[a-z](%d)', $retVal[$i]->type, $retVal[$i]->max_length);
$retVal[$i]->nullable = $query[$i]->Null === 'YES';
$retVal[$i]->default = $query[$i]->Default;
$retVal[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
}
return $retVal;
}
//--------------------------------------------------------------------
/**
* Returns an array of objects with index data
*
* @param string $table
* @return stdClass[]
* @throws DatabaseException
* @throws LogicException
*/
public function _indexData(string $table): array
{
$table = $this->protectIdentifiers($table, true, null, false);
if (($query = $this->query('SHOW INDEX FROM ' . $table)) === false)
{
throw new DatabaseException(lang('Database.failGetIndexData'));
}
if (! $indexes = $query->getResultArray())
{
return [];
}
$keys = [];
foreach ($indexes as $index)
{
if (empty($keys[$index['Key_name']]))
{
$keys[$index['Key_name']] = new stdClass();
$keys[$index['Key_name']]->name = $index['Key_name'];
if ($index['Key_name'] === 'PRIMARY')
{
$type = 'PRIMARY';
}
elseif ($index['Index_type'] === 'FULLTEXT')
{
$type = 'FULLTEXT';
}
elseif ($index['Non_unique'])
{
$type = $index['Index_type'] === 'SPATIAL' ? 'SPATIAL' : 'INDEX';
}
else
{
$type = 'UNIQUE';
}
$keys[$index['Key_name']]->type = $type;
}
$keys[$index['Key_name']]->fields[] = $index['Column_name'];
}
return $keys;
}
//--------------------------------------------------------------------
/**
* Returns an array of objects with Foreign key data
*
* @param string $table
* @return stdClass[]
* @throws DatabaseException
*/
public function _foreignKeyData(string $table): array
{
$sql = '
SELECT
tc.CONSTRAINT_NAME,
tc.TABLE_NAME,
kcu.COLUMN_NAME,
rc.REFERENCED_TABLE_NAME,
kcu.REFERENCED_COLUMN_NAME
FROM information_schema.TABLE_CONSTRAINTS AS tc
INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS rc
ON tc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
INNER JOIN information_schema.KEY_COLUMN_USAGE AS kcu
ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
WHERE
tc.CONSTRAINT_TYPE = ' . $this->escape('FOREIGN KEY') . ' AND
tc.TABLE_SCHEMA = ' . $this->escape($this->database) . ' AND
tc.TABLE_NAME = ' . $this->escape($table);
if (($query = $this->query($sql)) === false)
{
throw new DatabaseException(lang('Database.failGetForeignKeyData'));
}
$query = $query->getResultObject();
$retVal = [];
foreach ($query as $row)
{
$obj = new stdClass();
$obj->constraint_name = $row->CONSTRAINT_NAME;
$obj->table_name = $row->TABLE_NAME;
$obj->column_name = $row->COLUMN_NAME;
$obj->foreign_table_name = $row->REFERENCED_TABLE_NAME;
$obj->foreign_column_name = $row->REFERENCED_COLUMN_NAME;
$retVal[] = $obj;
}
return $retVal;
}
//--------------------------------------------------------------------
/**
* Returns platform-specific SQL to disable foreign key checks.
*
* @return string
*/
protected function _disableForeignKeyChecks()
{
return 'SET FOREIGN_KEY_CHECKS=0';
}
//--------------------------------------------------------------------
/**
* Returns platform-specific SQL to enable foreign key checks.
*
* @return string
*/
protected function _enableForeignKeyChecks()
{
return 'SET FOREIGN_KEY_CHECKS=1';
}
//--------------------------------------------------------------------
/**
* Returns the last error code and message.
* Must return this format: ['code' => string|int, 'message' => string]
* intval(code) === 0 means "no error".
*
* @return array<string,string|int>
*/
public function error(): array
{
if (! empty($this->mysqli->connect_errno))
{
return [
'code' => $this->mysqli->connect_errno,
'message' => $this->mysqli->connect_error,
];
}
return [
'code' => $this->connID->errno,
'message' => $this->connID->error,
];
}
//--------------------------------------------------------------------
/**
* Insert ID
*
* @return integer
*/
public function insertID(): int
{
return $this->connID->insert_id;
}
//--------------------------------------------------------------------
/**
* Begin Transaction
*
* @return boolean
*/
protected function _transBegin(): bool
{
$this->connID->autocommit(false);
return $this->connID->begin_transaction();
}
//--------------------------------------------------------------------
/**
* Commit Transaction
*
* @return boolean
*/
protected function _transCommit(): bool
{
if ($this->connID->commit())
{
$this->connID->autocommit(true);
return true;
}
return false;
}
//--------------------------------------------------------------------
/**
* Rollback Transaction
*
* @return boolean
*/
protected function _transRollback(): bool
{
if ($this->connID->rollback())
{
$this->connID->autocommit(true);
return true;
}
return false;
}
//--------------------------------------------------------------------
}