MySQLi database connection.
Class declared in MODPATH/database/classes/Database/MySQLi.php on line 3.
integer 1
integer 2
integer 3
integer 4
string
$defaultdefault instance name
string(7) "default"
array
$instancesDatabase instances
array(0)
string
$last_querythe last query executed
NULL
$_configNULL
$_connectionNULL
$_connection_idNULL
$_current_databasesarray(0)
$_identifierstring(1) "`"
$_instanceNULL
$_set_namesNULL
Start a SQL transaction
string
$mode
= NULL - Isolation level boolean
public function begin($mode = null)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if ($mode AND ! $this->_connection->query("SET TRANSACTION ISOLATION LEVEL $mode")) {
throw new Database_Exception(':error', [':error' => $this->_connection->error], $this->_connection->errno);
}
return (bool) $this->_connection->query('START TRANSACTION');
}
Commit a SQL transaction
boolean
public function commit()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return (bool) $this->_connection->query('COMMIT');
}
Connect to the database. This is called automatically when the first query is executed.
$db->connect();
void
public function connect()
{
if ($this->_connection)
return;
if (Database_MySQLi::$_set_names === null) {
// Determine if we can use mysqli_set_charset(), which is only
// available on PHP 5.2.3+ when compiled against MySQL 5.0+
Database_MySQLi::$_set_names = !function_exists('mysqli_set_charset');
}
// Extract the connection parameters, adding required variabels
extract($this->_config['connection'] + [
'database' => '',
'hostname' => '',
'username' => '',
'password' => '',
'socket' => '',
'port' => 3306,
'ssl' => null,
]);
// Prevent this information from showing up in traces
unset($this->_config['connection']['username'], $this->_config['connection']['password']);
try {
if (is_array($ssl)) {
$this->_connection = mysqli_init();
$this->_connection->ssl_set(
Arr::get($ssl, 'client_key_path'), Arr::get($ssl, 'client_cert_path'), Arr::get($ssl, 'ca_cert_path'), Arr::get($ssl, 'ca_dir_path'), Arr::get($ssl, 'cipher')
);
$this->_connection->real_connect($hostname, $username, $password, $database, $port, $socket, MYSQLI_CLIENT_SSL);
} else {
$this->_connection = new mysqli($hostname, $username, $password, $database, $port, $socket);
}
} catch (Exception $e) {
// No connection exists
$this->_connection = null;
throw new Database_Exception(':error', [':error' => $e->getMessage()], $e->getCode());
}
// \xFF is a better delimiter, but the PHP driver uses underscore
$this->_connection_id = sha1($hostname . '_' . $username . '_' . $password);
if (!empty($this->_config['charset'])) {
// Set the character set
$this->set_charset($this->_config['charset']);
}
if (!empty($this->_config['connection']['variables'])) {
// Set session variables
$variables = [];
foreach ($this->_config['connection']['variables'] as $var => $val) {
$variables[] = 'SESSION ' . $var . ' = ' . $this->quote($val);
}
$this->_connection->query('SET ' . implode(', ', $variables));
}
}
Returns a normalized array describing the SQL data type
$db->datatype('char');
string
$type
required - SQL data type array
public function datatype($type)
{
static $types = [
'blob' => ['type' => 'string', 'binary' => true, 'character_maximum_length' => '65535'],
'bool' => ['type' => 'bool'],
'bigint unsigned' => ['type' => 'int', 'min' => '0', 'max' => '18446744073709551615'],
'datetime' => ['type' => 'string'],
'decimal unsigned' => ['type' => 'float', 'exact' => true, 'min' => '0'],
'double' => ['type' => 'float'],
'double precision unsigned' => ['type' => 'float', 'min' => '0'],
'double unsigned' => ['type' => 'float', 'min' => '0'],
'enum' => ['type' => 'string'],
'fixed' => ['type' => 'float', 'exact' => true],
'fixed unsigned' => ['type' => 'float', 'exact' => true, 'min' => '0'],
'float unsigned' => ['type' => 'float', 'min' => '0'],
'geometry' => ['type' => 'string', 'binary' => true],
'int unsigned' => ['type' => 'int', 'min' => '0', 'max' => '4294967295'],
'integer unsigned' => ['type' => 'int', 'min' => '0', 'max' => '4294967295'],
'longblob' => ['type' => 'string', 'binary' => true, 'character_maximum_length' => '4294967295'],
'longtext' => ['type' => 'string', 'character_maximum_length' => '4294967295'],
'mediumblob' => ['type' => 'string', 'binary' => true, 'character_maximum_length' => '16777215'],
'mediumint' => ['type' => 'int', 'min' => '-8388608', 'max' => '8388607'],
'mediumint unsigned' => ['type' => 'int', 'min' => '0', 'max' => '16777215'],
'mediumtext' => ['type' => 'string', 'character_maximum_length' => '16777215'],
'national varchar' => ['type' => 'string'],
'numeric unsigned' => ['type' => 'float', 'exact' => true, 'min' => '0'],
'nvarchar' => ['type' => 'string'],
'point' => ['type' => 'string', 'binary' => true],
'real unsigned' => ['type' => 'float', 'min' => '0'],
'set' => ['type' => 'string'],
'smallint unsigned' => ['type' => 'int', 'min' => '0', 'max' => '65535'],
'text' => ['type' => 'string', 'character_maximum_length' => '65535'],
'tinyblob' => ['type' => 'string', 'binary' => true, 'character_maximum_length' => '255'],
'tinyint' => ['type' => 'int', 'min' => '-128', 'max' => '127'],
'tinyint unsigned' => ['type' => 'int', 'min' => '0', 'max' => '255'],
'tinytext' => ['type' => 'string', 'character_maximum_length' => '255'],
'year' => ['type' => 'string'],
];
$type = str_replace(' zerofill', '', $type);
if (isset($types[$type]))
return $types[$type];
return parent::datatype($type);
}
Disconnect from the database. This is called automatically by Database::__destruct. Clears the database instance from Database::$instances.
$db->disconnect();
boolean
public function disconnect()
{
try {
// Database is assumed disconnected
$status = true;
if (is_resource($this->_connection)) {
if ($status = $this->_connection->close()) {
// Clear the connection
$this->_connection = null;
// Clear the instance
parent::disconnect();
}
}
} catch (Exception $e) {
// Database is probably not disconnected
$status = !is_resource($this->_connection);
}
return $status;
}
Sanitize a string by escaping characters that could cause an SQL injection attack.
$value = $db->escape('any string');
string
$value
required - Value to quote string
public function escape($value)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (($value = $this->_connection->real_escape_string((string) $value)) === false) {
throw new Database_Exception(':error', [':error' => $this->_connection->error], $this->_connection->errno);
}
// SQL standard is to use single-quotes for all values
return "'$value'";
}
Lists all of the columns in a table. Optionally, a LIKE string can be used to search for specific fields.
// Get all columns from the "users" table
$columns = $db->list_columns('users');
// Get all name-related columns
$columns = $db->list_columns('users', '%name%');
// Get the columns from a table that doesn't use the table prefix
$columns = $db->list_columns('users', null, false);
string
$table
required - Table to get columns from string
$like
= NULL - Column to search for boolean
$add_prefix
= bool TRUE - Whether to add the table prefix automatically or not array
public function list_columns($table, $like = null, $add_prefix = true)
{
// Quote the table name
$table = ($add_prefix === true) ? $this->quote_table($table) : $table;
if (is_string($like)) {
// Search for column names
$result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM ' . $table . ' LIKE ' . $this->quote($like), false);
} else {
// Find all column names
$result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM ' . $table, false);
}
$count = 0;
$columns = [];
foreach ($result as $row) {
list($type, $length) = $this->_parse_type($row['Type']);
$column = $this->datatype($type);
$column['column_name'] = $row['Field'];
$column['column_default'] = $row['Default'];
$column['data_type'] = $type;
$column['is_nullable'] = ($row['Null'] == 'YES');
$column['ordinal_position'] = ++$count;
switch ($column['type']) {
case 'float':
if (isset($length)) {
list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
}
break;
case 'int':
if (isset($length)) {
// MySQL attribute
$column['display'] = $length;
}
break;
case 'string':
switch ($column['data_type']) {
case 'binary':
case 'varbinary':
$column['character_maximum_length'] = $length;
break;
case 'char':
case 'varchar':
$column['character_maximum_length'] = $length;
case 'text':
case 'tinytext':
case 'mediumtext':
case 'longtext':
$column['collation_name'] = $row['Collation'];
break;
case 'enum':
case 'set':
$column['collation_name'] = $row['Collation'];
$column['options'] = explode('\',\'', substr($length, 1, -1));
break;
}
break;
}
// MySQL attributes
$column['comment'] = $row['Comment'];
$column['extra'] = $row['Extra'];
$column['key'] = $row['Key'];
$column['privileges'] = $row['Privileges'];
$columns[$row['Field']] = $column;
}
return $columns;
}
List all of the tables in the database. Optionally, a LIKE string can be used to search for specific tables.
// Get all tables in the current database
$tables = $db->list_tables();
// Get all user-related tables
$tables = $db->list_tables('user%');
string
$like
= NULL - Table to search for array
public function list_tables($like = null)
{
if (is_string($like)) {
// Search for table names
$result = $this->query(Database::SELECT, 'SHOW TABLES LIKE ' . $this->quote($like), false);
} else {
// Find all table names
$result = $this->query(Database::SELECT, 'SHOW TABLES', false);
}
$tables = [];
foreach ($result as $row) {
$tables[] = reset($row);
}
return $tables;
}
Perform an SQL query of the given type.
// Make a SELECT query and use objects for results
$db->query(Database::SELECT, 'SELECT * FROM groups', true);
// Make a SELECT query and use "Model_User" for the results
$db->query(Database::SELECT, 'SELECT * FROM users LIMIT 1', 'Model_User');
integer
$type
required - Database::SELECT, Database::INSERT, etc string
$sql
required - SQL query mixed
$as_object
= bool FALSE - Result object class string, true for stdClass, false for assoc array array
$params
= NULL - Object construct parameters for result class object
- Database_Result for SELECT queriesarray
- List (insert id, row count) for INSERT queriesinteger
- Number of affected rows for all other queriespublic function query($type, $sql, $as_object = false, array $params = null)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (Kohana::$profiling) {
// Benchmark this query for the current instance
$benchmark = Profiler::start("Database ({$this->_instance})", $sql);
}
// Execute the query
if (($result = $this->_connection->query($sql)) === false) {
if (isset($benchmark)) {
// This benchmark is worthless
Profiler::delete($benchmark);
}
throw new Database_Exception(':error [ :query ]', [
':error' => $this->_connection->error,
':query' => $sql
], $this->_connection->errno);
}
if (isset($benchmark)) {
Profiler::stop($benchmark);
}
// Set the last query
$this->last_query = $sql;
if ($type === Database::SELECT) {
// Return an iterator of results
return new Database_MySQLi_Result($result, $sql, $as_object, $params);
} elseif ($type === Database::INSERT) {
// Return a list of insert id and rows created
return [
$this->_connection->insert_id,
$this->_connection->affected_rows,
];
} else {
// Return the number of rows affected
return $this->_connection->affected_rows;
}
}
Rollback a SQL transaction
boolean
public function rollback()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return (bool) $this->_connection->query('ROLLBACK');
}
Set the connection character set. This is called automatically by Database::connect.
$db->set_charset('utf8');
string
$charset
required - Character set name void
public function set_charset($charset)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (Database_MySQLi::$_set_names === true) {
// PHP is compiled against MySQL 4.x
$status = (bool) $this->_connection->query('SET NAMES ' . $this->quote($charset));
} else {
// PHP is compiled against MySQL 5.x
$status = $this->_connection->set_charset($charset);
}
if ($status === false) {
throw new Database_Exception(':error', [':error' => $this->_connection->error], $this->_connection->errno);
}
}
Stores the database configuration locally and name the instance.
This method cannot be accessed directly, you must use Database::instance.
void
public function __construct($name, array $config)
{
// Set the instance name
$this->_instance = $name;
// Store the config locally
$this->_config = $config;
if (empty($this->_config['table_prefix'])) {
$this->_config['table_prefix'] = '';
}
}
Disconnect from the database when the object is destroyed.
// Destroy the database instance
unset(Database::instances[(string) $db], $db);
Calling unset($db)
is not enough to destroy the database, as it
will still be stored in Database::$instances
.
void
public function __destruct()
{
$this->disconnect();
}
Returns the database instance name.
echo (string) $db;
string
public function __toString()
{
return $this->_instance;
}
Count the number of records in a table.
// Get the total number of records in the "users" table
$count = $db->count_records('users');
mixed
$table
required - Table name string or [query, alias] integer
public function count_records($table)
{
// Quote the table name
$table = $this->quote_table($table);
return $this->query(Database::SELECT, 'SELECT COUNT(*) AS total_row_count FROM ' . $table, false)
->get('total_row_count');
}
Get a singleton Database instance. If configuration is not specified, it will be loaded from the database configuration file using the same group as the name.
// Load the default database
$db = Database::instance();
// Create a custom configured instance
$db = Database::instance('custom', $config);
string
$name
= NULL - Instance name array
$config
= NULL - Configuration parameters Database
public static function instance($name = null, array $config = null)
{
if ($name === null) {
// Use the default instance name
$name = Database::$default;
}
if (!isset(Database::$instances[$name])) {
if ($config === null) {
// Load the configuration for this database
$config = Kohana::$config->load('database')->$name;
}
if (!isset($config['type'])) {
throw new Kohana_Exception('Database type not defined in :name configuration', [':name' => $name]);
}
// Set the driver class name
$driver = 'Database_' . ucfirst($config['type']);
// Create the database connection instance
$driver = new $driver($name, $config);
// Store the database instance
Database::$instances[$name] = $driver;
}
return Database::$instances[$name];
}
Quote a value for an SQL query.
$db->quote(null); // 'NULL'
$db->quote(10); // 10
$db->quote('fred'); // 'fred'
Objects passed to this function will be converted to strings.
Database_Expression objects will be compiled.
Database_Query objects will be compiled and converted to a sub-query.
All other objects will be converted using the __toString
method.
mixed
$value
required - Any value to quote string
public function quote($value)
{
if ($value === null) {
return 'NULL';
} elseif ($value === true) {
return "'1'";
} elseif ($value === false) {
return "'0'";
} elseif (is_object($value)) {
if ($value instanceof Database_Query) {
// Create a sub-query
return '(' . $value->compile($this) . ')';
} elseif ($value instanceof Database_Expression) {
// Compile the expression
return $value->compile($this);
} else {
// Convert the object to a string
return $this->quote((string) $value);
}
} elseif (is_array($value)) {
return '(' . implode(', ', array_map([$this, __FUNCTION__], $value)) . ')';
} elseif (is_int($value)) {
return (int) $value;
} elseif (is_float($value)) {
// Convert to non-locale aware float to prevent possible commas
return sprintf('%F', $value);
}
return $this->escape($value);
}
Quote a database column name and add the table prefix if needed.
$column = $db->quote_column($column);
You can also use SQL methods within identifiers.
$column = $db->quote_column(DB::expr('COUNT(`column`)'));
Objects passed to this function will be converted to strings.
Database_Expression objects will be compiled.
Database_Query objects will be compiled and converted to a sub-query.
All other objects will be converted using the __toString
method.
mixed
$column
required - Column name or [column, alias] string
public function quote_column($column)
{
// Identifiers are escaped by repeating them
$escaped_identifier = $this->_identifier . $this->_identifier;
if (is_array($column)) {
list($column, $alias) = $column;
$alias = str_replace($this->_identifier, $escaped_identifier, $alias);
}
if ($column instanceof Database_Query) {
// Create a sub-query
$column = '(' . $column->compile($this) . ')';
} elseif ($column instanceof Database_Expression) {
// Compile the expression
$column = $column->compile($this);
} else {
// Convert to a string
$column = (string) $column;
$column = str_replace($this->_identifier, $escaped_identifier, $column);
if ($column === '*') {
return $column;
} elseif (strpos($column, '.') !== false) {
$parts = explode('.', $column);
if ($prefix = $this->table_prefix()) {
// Get the offset of the table name, 2nd-to-last part
$offset = count($parts) - 2;
// Add the table prefix to the table name
$parts[$offset] = $prefix . $parts[$offset];
}
foreach ($parts as & $part) {
if ($part !== '*') {
// Quote each of the parts
$part = $this->_identifier . $part . $this->_identifier;
}
}
$column = implode('.', $parts);
} else {
$column = $this->_identifier . $column . $this->_identifier;
}
}
if (isset($alias)) {
$column .= ' AS ' . $this->_identifier . $alias . $this->_identifier;
}
return $column;
}
Quote a database identifier
Objects passed to this function will be converted to strings.
Database_Expression objects will be compiled.
Database_Query objects will be compiled and converted to a sub-query.
All other objects will be converted using the __toString
method.
mixed
$value
required - Any identifier string
public function quote_identifier($value)
{
// Identifiers are escaped by repeating them
$escaped_identifier = $this->_identifier . $this->_identifier;
if (is_array($value)) {
list($value, $alias) = $value;
$alias = str_replace($this->_identifier, $escaped_identifier, $alias);
}
if ($value instanceof Database_Query) {
// Create a sub-query
$value = '(' . $value->compile($this) . ')';
} elseif ($value instanceof Database_Expression) {
// Compile the expression
$value = $value->compile($this);
} else {
// Convert to a string
$value = (string) $value;
$value = str_replace($this->_identifier, $escaped_identifier, $value);
if (strpos($value, '.') !== false) {
$parts = explode('.', $value);
foreach ($parts as & $part) {
// Quote each of the parts
$part = $this->_identifier . $part . $this->_identifier;
}
$value = implode('.', $parts);
} else {
$value = $this->_identifier . $value . $this->_identifier;
}
}
if (isset($alias)) {
$value .= ' AS ' . $this->_identifier . $alias . $this->_identifier;
}
return $value;
}
Quote a database table name and adds the table prefix if needed.
$table = $db->quote_table($table);
Objects passed to this function will be converted to strings.
Database_Expression objects will be compiled.
Database_Query objects will be compiled and converted to a sub-query.
All other objects will be converted using the __toString
method.
mixed
$table
required - Table name or [table, alias] string
public function quote_table($table)
{
// Identifiers are escaped by repeating them
$escaped_identifier = $this->_identifier . $this->_identifier;
if (is_array($table)) {
list($table, $alias) = $table;
$alias = str_replace($this->_identifier, $escaped_identifier, $alias);
}
if ($table instanceof Database_Query) {
// Create a sub-query
$table = '(' . $table->compile($this) . ')';
} elseif ($table instanceof Database_Expression) {
// Compile the expression
$table = $table->compile($this);
} else {
// Convert to a string
$table = (string) $table;
$table = str_replace($this->_identifier, $escaped_identifier, $table);
if (strpos($table, '.') !== false) {
$parts = explode('.', $table);
if ($prefix = $this->table_prefix()) {
// Get the offset of the table name, last part
$offset = count($parts) - 1;
// Add the table prefix to the table name
$parts[$offset] = $prefix . $parts[$offset];
}
foreach ($parts as & $part) {
// Quote each of the parts
$part = $this->_identifier . $part . $this->_identifier;
}
$table = implode('.', $parts);
} else {
// Add the table prefix
$table = $this->_identifier . $this->table_prefix() . $table . $this->_identifier;
}
}
if (isset($alias)) {
// Attach table prefix to alias
$table .= ' AS ' . $this->_identifier . $this->table_prefix() . $alias . $this->_identifier;
}
return $table;
}
Return the table prefix defined in the current configuration.
$prefix = $db->table_prefix();
string
public function table_prefix()
{
return $this->_config['table_prefix'];
}
Extracts the text between parentheses, if any.
// Returns: ['CHAR', '6']
list($type, $length) = $db->_parse_type('CHAR(6)');
string
$type
required - $type array
- List containing the type and length, if anyprotected function _parse_type($type)
{
if (($open = strpos($type, '(')) === false) {
// No length specified
return [$type, null];
}
// Closing parenthesis
$close = strrpos($type, ')', $open);
// Length without parentheses
$length = substr($type, $open + 1, $close - 1 - $open);
// Type without the length
$type = substr($type, 0, $open) . substr($type, $close + 1);
return [$type, $length];
}