yf_db_driver_mysqli class| File | plugins/db/classes/db/yf_db_driver_mysqli.class.php |
|---|---|
| Use | _class('db_driver_mysqli', 'classes/db/') |
| Extends | yf_db_driver |
A site sets them in its config with $PROJECT_CONF['db_driver_mysqli']['NAME'] = ...;
| Property | Default | Description |
|---|---|---|
$CONNECT_TIMEOUTint |
5 |
|
$DEF_PORT |
null |
|
$INI_OPTSarray |
['mysqli.reconnect' => true] |
of ini settings to apply before connect |
$ON_AFTER_CONNECTarray |
[] |
of callables |
$ON_BEFORE_CONNECTarray |
[] |
of callables |
$SQL_AFTER_CONNECTarray |
['SET SQL_MODE = ""', 'SET interactive_timeout = 3600', 'SET wait_timeout = 3600'] |
of strings |
$SQL_AFTER_CONNECT_CONSOLEarray |
['SET SQL_MODE = ""', 'SET interactive_timeout = 86400', 'SET wait_timeout = 86400'] |
of strings |
$SQL_MODEstring |
'' |
|
$_connect_error |
null |
|
$db_connect_id@conf_skip |
null |
|
$params |
[] |
from yf_db_driver: $ESCAPE_BUILDER_VALUES
public function affected_rows($query_id = false)
public function affected_rows($query_id = false)
{
return $this->db_connect_id ? mysqli_affected_rows($this->db_connect_id) : false;
}
public function auto_limit_one()
public function auto_limit_one()
{
return true;
}
public function begin()
public function begin()
{
return $this->query('START TRANSACTION');
}
public function bind_params($stmt, $data = [])
public function bind_params($stmt, $data = [])
{
$types_string = '';
$params = null;
foreach ((array) $data as $k => $v) {
$var_type = substr($k, 0, 1);
$types_string .= $var_type;
$params[] = '$data[\'' . $k . '\']';
}
return eval('return mysqli_stmt_bind_param($stmt, \'' . $types_string . '\', ' . implode(',', $params) . ');');
}
public function close()
public function close()
{
return mysqli_close($this->db_connect_id);
}
public function commit()
public function commit()
{
return $this->query('COMMIT');
}
public function connect()
public function connect()
{
$this->db_connect_id = mysqli_init();
if ( ! $this->db_connect_id || mysqli_connect_errno()) {
$this->_connect_error = 'cannot_connect_to_server';
$this->db_connect_id = null;
return false;
}
foreach ((array) $this->INI_OPTS as $ini_name => $ini_val) {
ini_set($ini_name, $ini_val);
}
if ( ! $this->ON_BEFORE_CONNECT) {
$this->ON_BEFORE_CONNECT[] = function () {
return $this->_on_before_connect_default();
};
}
foreach ((array) $this->ON_BEFORE_CONNECT as $func) {
if (is_callable($func)) {
$func($this);
}
}
if ($this->params['socket']) {
$connect_host = $this->params['socket'];
} else {
$connect_port = $this->params['port'] && $this->params['port'] != $this->DEF_PORT ? $this->params['port'] : '';
$connect_host = ($this->params['persist'] ? 'p:' : '') . $this->params['host'] . ($connect_port ? ':' . $connect_port : '');
}
if ( ! $this->params['persist']) {
mysqli_options($this->db_connect_id, MYSQLI_OPT_CONNECT_TIMEOUT, $this->CONNECT_TIMEOUT);
}
$is_connected = mysqli_real_connect($this->db_connect_id, $this->params['host'], $this->params['user'], $this->params['pswd'], '', $this->params['port'], $this->params['socket'], $this->params['ssl'] ? MYSQLI_CLIENT_SSL : 0);
if ( ! $is_connected) {
$this->_connect_error = 'cannot_connect_to_server';
return false;
}
foreach ((array) $this->SQL_AFTER_CONNECT as $sql) {
$this->query($sql);
}
if ($this->params['name'] != '') {
$dbselect = $this->select_db($this->params['name']);
// Try to create database, if not exists and if allowed
if ( ! $dbselect && $this->params['allow_auto_create_db'] && preg_match('/^[a-z0-9][a-z0-9_]+[a-z0-9]$/i', $this->params['name'])) {
$res = $this->query('CREATE DATABASE IF NOT EXISTS ' . $this->params['name']);
if ($res) {
$dbselect = $this->select_db($this->params['name']);
}
}
if ( ! $dbselect) {
$this->_connect_error = 'cannot_select_db';
}
foreach ((array) $this->ON_AFTER_CONNECT as $func) {
if (is_callable($func)) {
$func($this, $dbselect);
}
}
return $dbselect;
}
}
public function error()
public function error()
{
if (mysqli_connect_errno()) {
return [
'message' => mysqli_connect_error(),
'code' => mysqli_connect_errno(),
];
} elseif ($this->db_connect_id) {
return [
'message' => mysqli_error($this->db_connect_id),
'code' => mysqli_errno($this->db_connect_id),
];
} elseif ($this->_connect_error) {
return [
'message' => 'YF: Connect error: ' . $this->_connect_error,
'code' => '9999',
];
}
return false;
}
public function escape_key($data)
public function escape_key($data)
{
return '`' . str_replace('`', '``', trim($data, '`')) . '`';
}
public function escape_val($data)
public function escape_val($data)
{
if ($data === null) {
return 'NULL';
}
if ($this->ESCAPE_BUILDER_VALUES) {
$data = $this->real_escape_string($data);
}
return '\'' . $data . '\'';
}
public function fetch_array($query_id)
public function fetch_array($query_id)
{
return $query_id instanceof mysqli_result ? mysqli_fetch_array($query_id) : false;
}
public function fetch_assoc($query_id)
public function fetch_assoc($query_id)
{
return $query_id instanceof mysqli_result ? mysqli_fetch_assoc($query_id) : false;
}
public function fetch_object($query_id)
public function fetch_object($query_id)
{
return $query_id instanceof mysqli_result ? mysqli_fetch_object($query_id) : false;
}
public function fetch_row($query_id)
public function fetch_row($query_id)
{
return $query_id instanceof mysqli_result ? mysqli_fetch_row($query_id) : false;
}
public function free_result($query_id)
public function free_result($query_id)
{
if ($query_id instanceof mysqli_result) {
mysqli_free_result($query_id);
// We need this for compatibility, because mysqli_free_result() returns "void"
return true;
}
return true;
}
public function get_host_info()
public function get_host_info()
{
return $this->db_connect_id ? mysqli_get_host_info($this->db_connect_id) : false;
}
public function get_last_query_info()
public function get_last_query_info()
{
if ( ! $this->db_connect_id) {
return false;
}
// Example: Records: 42 Deleted: 0 Skipped: 0 Warnings: 0
return mysqli_info($this->db_connect_id);
}
public function get_last_warnings()
public function get_last_warnings()
{
if ( ! $this->db_connect_id) {
return false;
}
$q = $this->query('SHOW WARNINGS');
if ( ! $q) {
return false;
}
$warnings = [];
// Example: Warning (1264): Data truncated for column 'Name' at row 1
while ($a = $this->fetch_assoc($q)) {
$warnings[] = $a;
}
return $warnings;
}
public function get_server_version()
public function get_server_version()
{
return $this->db_connect_id ? mysqli_get_server_info($this->db_connect_id) : false;
}
public function insert_all($table, $fields, &$data)
Insert data with preparing, types.
public function insert_all($table, $fields, &$data)
{
if ( ! $table) {
return [[], 0, null];
}
if ( ! $fields || ! is_array($fields)) {
return [[], 0, null];
}
if ( ! $data || ! is_array($data) || count($data) < 1) {
return [[], 0, null];
}
list($allow, $type, $q) = $this->insert_all_prepare($table, $fields, $data);
$stmt = mysqli_prepare($this->db_connect_id, $q);
if ( ! $stmt) {
return [[], 0, $stmt];
}
$this->begin();
list($err, $a) = $this->stmt_all_exec($stmt, $allow, $type, $data);
if ($err) {
$this->rollback();
return [$err, $a, $stmt];
}
$this->commit();
mysqli_stmt_close($stmt);
return [[], $a];
}
public function insert_all_prepare($table, $fields, &$data)
public function insert_all_prepare($table, $fields, &$data)
{
$table = db($table);
$item0 = $data[0];
$f = [];
$t = [];
$p = [];
$allow = [];
foreach ($item0 as $k => $i) {
$field = $fields[$k] ?? null;
if ( ! $field) {
continue;
}
$allow[$k] = $field;
$f[] = db()->escape_key($k);
$t[] = $field['type'];
$p[] = '?';
}
$f = implode(',', $f);
$p = implode(',', $p);
$t = implode('', $t);
$q = sprintf('INSERT INTO %s (%s) VALUES (%s)', $table, $f, $p);
return [$allow, $t, $q];
}
public function insert_id($query_id = false)
public function insert_id($query_id = false)
{
return $this->db_connect_id ? mysqli_insert_id($this->db_connect_id) : false;
}
public function is_reconnect_error($db_error, array $codes = [])
$codes array public function is_reconnect_error($db_error, array $codes = [])
{
return in_array($db_error['code'], $codes);
}
public function limit($count, $offset)
public function limit($count, $offset)
{
$sql = '';
if ($count > 0) {
$offset = ($offset > 0) ? $offset : 0;
$sql .= 'LIMIT ' . ($offset ? $offset . ', ' : '') . $count;
}
return $sql;
}
public function no_cache_hint()
public function no_cache_hint()
{
return 'SQL_NO_CACHE';
}
public function num_rows($query_id)
public function num_rows($query_id)
{
return $query_id instanceof mysqli_result ? mysqli_num_rows($query_id) : false;
}
public function prepare($query)
public function prepare($query)
{
return mysqli_prepare($this->db_connect_id, $query);
}
public function query($query)
public function query($query)
{
return $this->db_connect_id && strlen($query) ? mysqli_query($this->db_connect_id, $query) : false;
}
public function query_fetch_prepared($query, $data = [])
Query with preparing.
public function query_fetch_prepared($query, $data = [])
{
$result = null;
$stmt = mysqli_prepare($this->db_connect_id, $query);
$this->bind_params($stmt, $data);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $result);
mysqli_stmt_fetch($stmt);
mysqli_stmt_close($stmt);
return $result;
}
public function real_escape_string($string)
public function real_escape_string($string)
{
if ( ! $this->db_connect_id) {
return _class('db')->_mysql_escape_mimic($string);
}
if ($string === null) {
return 'NULL';
} elseif (is_float($string)) {
return str_replace(',', '.', $string);
} elseif (is_int($string)) {
return $string;
} elseif (is_bool($string)) {
return (int) $string;
}
return mysqli_real_escape_string($this->db_connect_id, $string);
}
public function repairable_error_codes()
public function repairable_error_codes()
{
return [
1191, // Can't find FULLTEXT index matching the column list
2013, // Lost connection to MySQL server during query
1205, // Lock wait timeout expired. Transaction was rolled back (InnoDB)
1213, // Transaction deadlock. You should rerun the transaction. (InnoDB)
1146, // Table %s doesn't exist
1054, // Unknown column %s
];
}
public function rollback()
public function rollback()
{
return $this->query('ROLLBACK');
}
public function select_db($name)
public function select_db($name)
{
return $this->db_connect_id ? mysqli_select_db($this->db_connect_id, $name) : false;
}
public function stmt_all_exec($stmt, $allow, $type, &$data)
public function stmt_all_exec($stmt, $allow, $type, &$data)
{
if ( ! $allow || ! is_array($allow)) {
return false;
}
if ( ! $type) {
return [false, 0];
}
$n = count($allow);
if ($n < 1) {
return [false, 0];
}
$r = true;
$err = [];
$a = 0;
$d = array_fill(0, $n, null);
$r = mysqli_stmt_bind_param($stmt, $type, ...$d);
if ( ! $r) {
return [false, 0];
}
$fields = array_keys($allow);
foreach ($data as $i) {
foreach ($fields as $j => $k) {
$d[$j] = isset($i[$k]) ? $i[$k] :
(isset($allow[$k]['value']) ? $allow[$k]['value'] : null);
}
try {
$r = mysqli_stmt_execute($stmt);
} catch (Exception $e) {
$r = false;
$err = [
'message' => $e->getMessage(),
'code' => $e->getCode(),
];
}
if ( ! $r) {
break;
}
$a += mysqli_stmt_affected_rows($stmt);
}
return [$err, $a];
}
public function supports_upsert()
public function supports_upsert()
{
return true;
}
public function update_all($table, $fields, &$data)
Update data with preparing, types.
public function update_all($table, $fields, &$data)
{
if ( ! $table) {
return [[], 0, null];
}
if ( ! $fields || ! is_array($fields)) {
return [[], 0, null];
}
if ( ! $data || ! is_array($data) || count($data) < 1) {
return [[], 0, null];
}
list($allow, $type, $q) = $this->update_all_prepare($table, $fields, $data);
$stmt = mysqli_prepare($this->db_connect_id, $q);
if ( ! $stmt) {
return [[], 0, $stmt];
}
$this->begin();
list($err, $a) = $this->stmt_all_exec($stmt, $allow, $type, $data);
if ($err) {
$this->rollback();
return [$err, $a, $stmt];
}
$this->commit();
mysqli_stmt_close($stmt);
return [[], $a];
}
public function update_all_prepare($table, $fields, &$data)
public function update_all_prepare($table, $fields, &$data)
{
$table = db($table);
$item0 = reset($data);
$f = [];
$tf = [];
$tk = [];
$w = [];
$allow = [];
$key = [];
foreach ($item0 as $k => $i) {
$field = $fields[$k] ?? null;
if ( ! $field) {
continue;
}
$p = db()->escape_key($k) . '=?';
if ($field['is_key'] ?? false) {
$w[] = $p;
$key[$k] = $field;
$tk[] = $field['type'];
} else {
$f[] = $p;
$allow[$k] = $field;
$tf[] = $field['type'];
}
}
$f = implode(',', $f);
$t = implode('', $tf) . implode('', $tk);
$w = implode(' AND ', $w);
$allow = array_merge($allow, $key);
$q = sprintf('UPDATE %s SET %s WHERE %s', $table, $f, $w);
return [$allow, $t, $q];
}
_ hooks and helpers; not routable as page actionspublic function __construct(array $params)
$params array public function __construct(array $params)
{
if ( ! function_exists('mysqli_init')) {
throw new RuntimeException('YF MySQLi db driver require missing php extension mysqli');
return false;
}
$params['port'] = ($params['port'] ?? null) ?: 3306;
if ($params['socket'] && ! file_exists($params['socket'])) {
$params['socket'] = '';
}
$charset = 'utf8';
$params['charset'] = ($params['charset'] ?? null) ?: (defined('DB_CHARSET') ? DB_CHARSET : $charset);
$this->params = $params;
$connected = $this->connect();
if ($params['charset'] && $connected && $this->db_connect_id) {
// See http://php.net/manual/en/mysqlinfo.concepts.charset.php
if (version_compare($this->get_server_version(), '8.0.0') >= 0) {
$charset = 'utf8mb4';
}
mysqli_set_charset($this->db_connect_id, $charset);
mysqli_query($this->db_connect_id, 'SET NAMES ' . $charset . ' COLLATE ' . $charset . '_unicode_ci');
}
return $this->db_connect_id;
}
public function _on_before_connect_default()
public function _on_before_connect_default()
{
if (is_console()) {
$this->params['persist'] = true;
$this->SQL_AFTER_CONNECT = $this->SQL_AFTER_CONNECT_CONSOLE;
}
}
from yf_db_driver: __call()