526 Zeilen
16 KiB
PHP
526 Zeilen
16 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Project:
|
|
* Contenido Content Management System
|
|
*
|
|
* Description:
|
|
* MySQLi database driver
|
|
*
|
|
* Requirements:
|
|
* @con_php_req 5
|
|
*
|
|
*
|
|
* @package Contenido database
|
|
* @version 0.3.1
|
|
* @author Boris Erdmann, Kristian Koehntopp
|
|
* @copyright four for business AG <www.4fb.de>
|
|
* @license http://www.contenido.org/license/LIZENZ.txt
|
|
* @link http://www.4fb.de
|
|
* @link http://www.contenido.org
|
|
* @since file available since contenido release <Contenido Version>
|
|
*
|
|
* {@internal
|
|
* created 2000-01-01
|
|
* modified 2008-07-04, bilal arslan, added security fix
|
|
* modified 2009-10-29, Murat Purc, removed deprecated functions (PHP 5.3 ready) extended DB_Sql_Abstract, added/optimized some functioms and some formatting
|
|
* modified 2009-12-29, Murat Purc, replaced is_resource() against mysqli compatible check [#CON-290]
|
|
* modified 2011-03-03, Murat Purc, Some redesign and improvements (partial adaption to PHP 5 and extending DB_Sql_Abstract).
|
|
* modified 2011-03-13, Murat Purc, Cleanup and documentation.
|
|
* modified 2011-04-22, Murat Purc, Connect to DB server without database and more
|
|
* readable connection settings.
|
|
*
|
|
* $Id$:
|
|
* }}
|
|
*
|
|
*/
|
|
if (!defined('CON_FRAMEWORK')) {
|
|
die('Illegal call');
|
|
}
|
|
|
|
class DB_Sql extends DB_Sql_Abstract {
|
|
|
|
protected $_aDataTypes = array(
|
|
0 => 'decimal',
|
|
1 => 'tinyint',
|
|
2 => 'smallint',
|
|
3 => 'int',
|
|
4 => 'float',
|
|
5 => 'double',
|
|
7 => 'timestamp',
|
|
8 => 'bigint',
|
|
9 => 'mediumint',
|
|
10 => 'date',
|
|
11 => 'time',
|
|
12 => 'datetime',
|
|
13 => 'year',
|
|
252 => 'blob', // text, blob, tinyblob,mediumblob, etc...
|
|
253 => 'string', // varchar and char
|
|
254 => 'enum',
|
|
);
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param array $options Optional assoziative options
|
|
*/
|
|
public function __construct(array $options = array()) {
|
|
$options = array_merge($options, array(
|
|
'type' => 'mysqli',
|
|
));
|
|
parent::__construct($options);
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::_connect()
|
|
*/
|
|
protected function _connect() {
|
|
// feasible connection values are:
|
|
// - $options['connection']['host'] (string) Hostname or ip
|
|
// - $options['connection']['database'] (string) Database name
|
|
// - $options['connection']['user'] (string) User name
|
|
// - $options['connection']['password'] (string) User password
|
|
// - $options['connection']['options'] (array) Optional, MySQLi options array
|
|
// - $options['connection']['socket'] (int) Optional, socket
|
|
// - $options['connection']['port'] (int) Optional, port
|
|
// - $options['connection']['flags'] (int) Optional, flags
|
|
// see http://www.php.net/manual/en/mysqli.real-connect.php
|
|
// extract($this->_aDbCfg['connection']);
|
|
|
|
if (!extension_loaded('mysqli')) {
|
|
$this->halt('MySQLi _connect() extension not loaded!');
|
|
return null;
|
|
}
|
|
|
|
// PHP 8.1 fix
|
|
$driver = new mysqli_driver();
|
|
$driver->report_mode = MYSQLI_REPORT_OFF;
|
|
|
|
$dbh = mysqli_init();
|
|
//print_r($dbh);
|
|
if (!$dbh) {
|
|
$this->halt('MySQLi _connect() Init failed');
|
|
return null;
|
|
}
|
|
|
|
$aCon = $this->_aDbCfg['connection'];
|
|
if (!isset($aCon['host']) || !isset($aCon['user']) || !isset($aCon['password'])) {
|
|
$this->halt('MySQLi _connect() Connection settings not complete');
|
|
return null;
|
|
}
|
|
|
|
|
|
// set existing option flags
|
|
if (isset($aCon['options']) && is_array($aCon['options'])) {
|
|
foreach ($aCon['options'] as $optKey => $optVal) {
|
|
mysqli_options($dbh, $optKey, $optVal);
|
|
}
|
|
}
|
|
|
|
if (($iPos = strpos($aCon['host'], ':')) !== false) {
|
|
list($aCon['host'], $aCon['port']) = explode(':', $aCon['host']);
|
|
} else {
|
|
$aCon['port'] = null;
|
|
}
|
|
|
|
if (!isset($aCon['socket'])) {
|
|
$aCon['socket'] = null;
|
|
}
|
|
if (!isset($aCon['flags'])) {
|
|
$aCon['flags'] = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;
|
|
}
|
|
if (!isset($aCon['database'])) {
|
|
$aCon['database'] = null;
|
|
}
|
|
|
|
$res = mysqli_real_connect(
|
|
$dbh, $aCon['host'], $aCon['user'], $aCon['password'], $aCon['database'], $aCon['port'], $aCon['socket'], $aCon['flags']
|
|
);
|
|
|
|
|
|
if (!empty($aCon['charset'])) {
|
|
mysqli_set_charset($dbh, $aCon['charset']);
|
|
} else {
|
|
mysqli_set_charset($dbh, 'utf8');
|
|
}
|
|
|
|
//echo mysqli_character_set_name($dbh);
|
|
|
|
if ($res && $dbh && $aCon['database']) {
|
|
if (!@mysqli_select_db($dbh, $aCon['database'])) {
|
|
$this->halt('MySQLi _connect() Cannot use database ' . $aCon['database']);
|
|
return null;
|
|
}
|
|
$this->Database = $aCon['database'];
|
|
}
|
|
|
|
$this->User = $aCon['user'];
|
|
|
|
return $dbh;
|
|
}
|
|
|
|
/**
|
|
* Discard the query result
|
|
*/
|
|
public function free() {
|
|
if (is_object($this->Query_ID)) {
|
|
mysqli_free_result($this->Query_ID);
|
|
}
|
|
$this->Query_ID = 0;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::_query()
|
|
*/
|
|
protected function _query($sQuery) {
|
|
$this->Query_ID = mysqli_query($this->Link_ID, $sQuery);
|
|
$this->Row = 0;
|
|
$this->Errno = $this->_getErrorNumber();
|
|
$this->Error = $this->_getErrorMessage();
|
|
if (!$this->Query_ID) {
|
|
$this->halt($sQuery);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::next_record()
|
|
*/
|
|
public function next_record() {
|
|
if (!$this->Query_ID instanceof mysqli_result) {
|
|
return false;
|
|
}
|
|
$this->Record = mysqli_fetch_array($this->Query_ID, MYSQLI_BOTH);
|
|
$this->Row += 1;
|
|
$this->Errno = $this->_getErrorNumber();
|
|
$this->Error = $this->_getErrorMessage();
|
|
|
|
$stat = is_array($this->Record);
|
|
if (!$stat && $this->Auto_Free) {
|
|
$this->free();
|
|
}
|
|
return $stat;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::seek()
|
|
*/
|
|
public function seek($pos = 0) {
|
|
$status = mysqli_data_seek($this->Query_ID, $pos);
|
|
if ($status) {
|
|
$this->Row = $pos;
|
|
} else {
|
|
$this->halt("seek($pos) failed: result has " . $this->num_rows() . " rows.");
|
|
// half assed attempt to save the day, but do not consider this
|
|
// documented or even desireable behaviour.
|
|
mysqli_data_seek($this->Query_ID, $this->num_rows());
|
|
$this->Row = $this->num_rows();
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::lock()
|
|
*/
|
|
public function lock($table, $mode = 'write') {
|
|
if ($this->_bNolock == true) {
|
|
return true;
|
|
}
|
|
$query = 'LOCK TABLES ';
|
|
if (is_array($table)) {
|
|
while (list ($key, $value) = each($table)) {
|
|
if (!is_int($key)) {
|
|
// texts key are "read", "read local", "write", "low priority write"
|
|
$query .= "$value $key, ";
|
|
} else {
|
|
$query .= "$value $mode, ";
|
|
}
|
|
}
|
|
$query = substr($query, 0, -2);
|
|
} else {
|
|
$query .= "$table $mode";
|
|
}
|
|
$res = $this->query($query);
|
|
if (!$res) {
|
|
$this->halt('lock() failed.');
|
|
return 0;
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::unlock()
|
|
*/
|
|
public function unlock() {
|
|
if ($this->_bNolock == true) {
|
|
return true;
|
|
}
|
|
|
|
$res = $this->query('UNLOCK TABLES');
|
|
if (!$res) {
|
|
$this->halt('unlock() failed.');
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::affected_rows()
|
|
*/
|
|
public function affected_rows() {
|
|
return ($this->Link_ID) ? mysqli_affected_rows($this->Link_ID) : 0;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::num_rows()
|
|
*/
|
|
public function num_rows() {
|
|
return ($this->Query_ID) ? mysqli_num_rows($this->Query_ID) : 0;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::num_fields()
|
|
*/
|
|
public function num_fields() {
|
|
return ($this->Query_ID) ? mysqli_num_fields($this->Query_ID) : 0;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::nextid()
|
|
*/
|
|
public function nextid($seq_name) {
|
|
$this->connect();
|
|
|
|
if ($this->lock($this->Seq_Table)) {
|
|
/* get sequence number (locked) and increment */
|
|
$q = sprintf("SELECT nextid FROM `%s` WHERE seq_name = '%s'", $this->Seq_Table, $seq_name);
|
|
$id = mysqli_query($this->Link_ID, $q);
|
|
$res = mysqli_fetch_array($id, MYSQLI_BOTH);
|
|
|
|
/* No current value, make one */
|
|
if (!is_array($res)) {
|
|
$currentid = 0;
|
|
$q = sprintf("INSERT INTO `%s` VALUES('%s', %s)", $this->Seq_Table, $seq_name, $currentid);
|
|
$id = mysqli_query($this->Link_ID, $q);
|
|
} else {
|
|
$currentid = $res["nextid"];
|
|
}
|
|
$nextid = $currentid + 1;
|
|
$q = sprintf("UPDATE `%s` set nextid = '%s' WHERE seq_name = '%s'", $this->Seq_Table, $nextid, $seq_name);
|
|
$id = mysqli_query($this->Link_ID, $q);
|
|
$this->unlock();
|
|
} else {
|
|
$this->halt('Cannot lock ' . $this->Seq_Table . ' - has it been created?');
|
|
return 0;
|
|
}
|
|
return $nextid;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::disconnect()
|
|
*/
|
|
public function disconnect() {
|
|
//$this->_debug("Debug: Disconnecting $this->Link_ID...");
|
|
if (is_resource($this->Link_ID)) {
|
|
mysqli_close($this->Link_ID);
|
|
$this->_removeConnection($this->Link_ID);
|
|
}
|
|
$this->Link_ID = 0;
|
|
$this->Query_ID = 0;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::_metaData()
|
|
* * Due to compatibility problems with Table we changed the behavior
|
|
* of metadata();
|
|
* depending on $full, metadata returns the following values:
|
|
*
|
|
* - full is false (default):
|
|
* $result[]:
|
|
* [0]["table"] table name
|
|
* [0]["name"] field name
|
|
* [0]["type"] field type
|
|
* [0]["len"] field length
|
|
* [0]["flags"] field flags
|
|
*
|
|
* - full is true
|
|
* $result[]:
|
|
* ["num_fields"] number of metadata records
|
|
* [0]["table"] table name
|
|
* [0]["name"] field name
|
|
* [0]["type"] field type
|
|
* [0]["len"] field length
|
|
* [0]["flags"] field flags
|
|
* ["meta"][field name] index of field named "field name"
|
|
* This last one could be used if you have a field name, but no index.
|
|
* Test: if (isset($result['meta']['myfield'])) { ...
|
|
*/
|
|
protected function _metaData($table = '', $full = false) {
|
|
$count = 0;
|
|
$id = 0;
|
|
$res = array();
|
|
// if no $table specified, assume that we are working with a query
|
|
// result
|
|
if (!empty($table)) {
|
|
$this->connect();
|
|
$id = mysqli_query($this->Link_ID, sprintf("SELECT * FROM `%s` LIMIT 1", $table));
|
|
if (!$id) {
|
|
$this->halt('Metadata query failed.');
|
|
return false;
|
|
}
|
|
} else {
|
|
//var_dump($this->Query_ID);
|
|
$id = $this->Query_ID;
|
|
if (!$id) {
|
|
$this->halt('No query specified.');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//$count = mysqli_num_fields($id);
|
|
|
|
/*
|
|
// made this IF due to performance (one if is faster than $count if's)
|
|
for ($i = 0; $i < $count; $i ++) {
|
|
$finfo = mysqli_fetch_field($id);
|
|
$res[$i]['table'] = $finfo->table;
|
|
$res[$i]['name'] = $finfo->name;
|
|
$res[$i]['type'] = $this->_aDataTypes[$finfo->type];
|
|
$res[$i]['len'] = $finfo->max_length;
|
|
$res[$i]['flags'] = $finfo->flags;
|
|
if ($full) {
|
|
$res['meta'][$res[$i]['name']] = $i;
|
|
}
|
|
|
|
} */
|
|
|
|
$count = 0;
|
|
while ($finfo = $id->fetch_field()) {
|
|
//rint_r($finfo);
|
|
$res[$count]['table'] = $finfo->table;
|
|
$res[$count]['name'] = $finfo->name;
|
|
$res[$count]['type'] = $this->_aDataTypes[$finfo->type];
|
|
$res[$count]['len'] = $finfo->length;
|
|
$res[$count]['flags'] = $finfo->flags;
|
|
if ($full) {
|
|
$res['meta'][$res[$count]['name']] = $count;
|
|
}
|
|
|
|
$count++;
|
|
}
|
|
if ($full) {
|
|
$res['num_fields'] = $count + 1;
|
|
}
|
|
|
|
// free the result only if we were called on a table
|
|
if ($table) {
|
|
mysqli_free_result($id);
|
|
}
|
|
|
|
return (count($res) > 0) ? $res : FALSE;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::escape()
|
|
*/
|
|
public function escape($sString) {
|
|
if(is_null($sString)) {
|
|
$sString = '';
|
|
}
|
|
$sResult = '';
|
|
if (is_resource($this->Link_ID) || $this->connect()) {
|
|
$sResult = mysqli_real_escape_string($this->Link_ID, $sString);
|
|
}
|
|
return $sResult;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::_tableNames()
|
|
*/
|
|
protected function _tableNames() {
|
|
$return = array();
|
|
$this->connect();
|
|
$h = @mysqli_query($this->Link_ID, 'SHOW TABLES');
|
|
$i = 0;
|
|
if (isset($h) && @mysqli_num_rows($h) > 0) {
|
|
while ($info = mysqli_fetch_row($h)) {
|
|
$return[$i]['table_name'] = $info[0];
|
|
$return[$i]['tablespace_name'] = $this->Database;
|
|
$return[$i]['database'] = $this->Database;
|
|
$i++;
|
|
}
|
|
|
|
mysqli_free_result($h);
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::_serverInfo()
|
|
*/
|
|
protected function _serverInfo() {
|
|
$arr['description'] = mysqli_get_server_info($this->Link_ID);
|
|
return $arr;
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::_getErrorMessage()
|
|
*/
|
|
protected function _getErrorMessage() {
|
|
if ($this->Link_ID) {
|
|
return @mysqli_error($this->Link_ID);
|
|
} else {
|
|
return @mysqli_connect_error();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @see DB_Sql_Abstract::_getErrorNumber()
|
|
*/
|
|
protected function _getErrorNumber() {
|
|
if ($this->Link_ID) {
|
|
return @mysqli_errno($this->Link_ID);
|
|
} else {
|
|
return @mysqli_connect_errno();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method equates to mysqli_fetch_object(). It returns the current
|
|
* result set as object or null if no result set is left. If optional
|
|
* param $sClassName is set, the result object is an instance of class
|
|
* $sClassName.
|
|
*
|
|
* @return object|null
|
|
*
|
|
* @author Holger Librenz <holger.librenz@4fb.de>
|
|
* @version 1.0
|
|
*/
|
|
public function getResultObject($sClassName = null) {
|
|
$oResult = null;
|
|
|
|
if (is_resource($this->Link_ID) && is_resource($this->Query_ID)) {
|
|
if ($sClassName == null) {
|
|
$oResult = mysqli_fetch_object($this->Query_ID);
|
|
} else {
|
|
$oResult = mysqli_fetch_object($this->Query_ID, $sClassName);
|
|
}
|
|
}
|
|
|
|
return $oResult;
|
|
}
|
|
|
|
public function getServerInfo() {
|
|
return mysqli_get_server_info($this->Link_ID);
|
|
}
|
|
|
|
public function getClientEncoding() {
|
|
$oCharSet = mysqli_get_charset($this->Link_ID);
|
|
return $oCharSet->charset;
|
|
}
|
|
|
|
public function getClientInfo() {
|
|
return mysqli_get_client_info();
|
|
}
|
|
|
|
}
|