Created
May 13, 2019 20:41
-
-
Save mikhail/2d4cfcdabd150240a4586235da08e7f5 to your computer and use it in GitHub Desktop.
MySQL abstraction library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
define('POSITIVE', 1); | |
define('NEGATIVE', -1); | |
define('DB_CONFIG_FILE', '/path/to/mysql.json'); | |
/* MySQLi module does not have this function by default */ | |
function mysqli_field_name($result, $field_offset) { | |
$properties = mysqli_fetch_field_direct($result, $field_offset); | |
return is_object($properties) ? $properties->name : null; | |
} | |
function mysqli_field_table($result, $field_offset) { | |
$properties = mysqli_fetch_field_direct($result, $field_offset); | |
return is_object($properties) ? $properties->table : null; | |
} | |
class mysqli_db { | |
var $Hostname = ''; | |
var $Username = ''; | |
var $Password = ''; | |
var $Database = ''; | |
var $error; | |
var $conn = null; | |
var $sql; | |
var $num_rows; | |
public $lastID; | |
var $_query_count; | |
var $_log_query; | |
var $Unbuffered = false; | |
var $total_time = 0; | |
var $resources = array(); | |
var $query_log = array(); | |
function __construct($hn = false, $un = false, $pw = false, $db = false) { | |
try { | |
// first variable might be a file path to json config. | |
if (file_exists(DB_CONFIG_FILE)) { | |
$config = @json_decode(file_get_contents(DB_CONFIG_FILE)); | |
} else { | |
$config = false; | |
} | |
} catch (Exception $e) { | |
$config = false; | |
} | |
if ($config) { | |
if ($config->hostname) $this->Hostname = $config->hostname; | |
if ($config->username) $this->Username = $config->username; | |
if ($config->password) $this->Password = $config->password; | |
if ($config->database) $this->Database = $config->database; | |
} elseif (getenv('DB_HOSTNAME') && getenv('DB_USERNAME') && getenv('DB_PASSWORD') && getenv('DB_DATABASE')) { | |
$this->Hostname = getenv('DB_HOSTNAME'); | |
$this->Username = getenv('DB_USERNAME'); | |
$this->Password = getenv('DB_PASSWORD'); | |
$this->Database = getenv('DB_DATABASE'); | |
} elseif ($hn && $un && $pw && $db) { | |
$this->Hostname = $hn; | |
$this->Username = $un; | |
$this->Password = $pw; | |
$this->Database = $db; | |
} | |
} | |
function init_conn() { | |
if ($this->conn != null) { | |
return; | |
} | |
$this->conn = @mysqli_connect($this->Hostname, $this->Username, $this->Password); | |
if (!$this->conn) { | |
if (mysqli_connect_errno() == 1040) { | |
die('The server is currently overloaded. Please try again in 10 minutes.'); | |
} | |
die('The server is currently not available. Please try again in 10 minutes. e'.mysqli_connect_errno()); | |
return; | |
} | |
if (!mysqli_select_db($this->conn, $this->Database)) { | |
die('The server is currently not available.'); | |
} | |
mysqli_set_charset($this->conn, "utf8mb4"); | |
} | |
function disconnect(){ | |
return mysqli_close($this->conn); | |
} | |
function escape($string) { | |
return mysqli_real_escape_string($this->conn, $string); | |
} | |
function & Query($sql = '', ...$args){ | |
$this->init_conn(); | |
global $_log_query; | |
$this->sql = $sql; | |
$_is_prepared = (func_num_args() > 1) == True; | |
if ($_is_prepared) { | |
// TODO: Refactor everything here to $args_types = get_args_types($args); | |
$arg_list = $args; | |
$args_types = ''; | |
$type_map = Array( | |
"boolean" => "b", | |
"integer" => "i", | |
"double" => "d", | |
"string" => "s", | |
"array" => "s", | |
"object" => "s", | |
"resource" => "s", | |
"NULL" => "s", | |
"unknown type" => "s", | |
); | |
foreach ($arg_list as $arg) { | |
$type = gettype($arg); | |
$ctype = $type_map[$type]; | |
$args_types .= $ctype; | |
} | |
} | |
# Measure query time | |
$query_start = microtime(true); | |
if (!$_is_prepared) { | |
$sql = mysqli_query($this->conn, $sql); | |
$this->num_rows = @mysqli_affected_rows($this->conn); | |
} else { | |
$p = $this->conn->prepare($sql); | |
$p->bind_param($args_types, ...$arg_list); | |
#call_user_func_array(array($p, 'bind_param'), $arg_list); | |
$p->execute(); | |
$sql = $p->get_result(); | |
$p->store_result(); | |
$this->num_rows = $p->affected_rows; | |
$p->close(); | |
} | |
$query_end = microtime(true); | |
$query_time = ($query_end - $query_start); | |
$this->total_time += $query_time; | |
$this->Unbuffered = false; | |
$this->_query_count++; | |
$this->resources[$this->_query_count] = &$sql; | |
// build backtrace | |
$backtrace = debug_backtrace(0,3); | |
$stacktrace = array(); | |
foreach ($backtrace as $key => $arr) { | |
if ($arr['file'] == __FILE__) { | |
continue; | |
} | |
$stacktrace[] = array( | |
'file' => str_replace($_SERVER['DOCUMENT_ROOT'], '', $arr['file']), | |
'line' => $arr['line'], | |
'function' => $arr['function']); | |
} | |
$this->query_log[$this->_query_count] = array('query' => $this->sql, 'time'=>$query_time, 'stacktrace' => $stacktrace); | |
//$this->num_rows = @mysqli_affected_rows($this->conn); | |
$this->lastID = @mysqli_insert_id($this->conn); | |
$this->error = ''; | |
# FIXME: Should not be recursive | |
if (mysqli_errno($this->conn) == 1205) { // Lock Timeout Exceeded | |
sleep(1); | |
$sql = $this->Query($this->sql); | |
} elseif (mysqli_errno($this->conn) == 1213) { // Deadlock found | |
sleep(1); | |
$sql = $this->Query($this->sql); | |
} elseif (mysqli_error($this->conn) && !$this->skipNextError) { | |
$this->error = mysqli_errno($this->conn) . ': ' . mysqli_error($this->conn); | |
trigger_error(htmlentities($this->sql).'<br /><br />'.htmlentities($this->error), E_USER_ERROR); | |
} | |
$this->skipNextError = false; | |
return $sql; | |
} | |
function & rQuery($sql, ...$args){ | |
$result = $this->Query($sql, ...$args); | |
if ($this->num_rows > 1) trigger_error('Multiple row selection for rQuery call', E_USER_WARNING); | |
if (!$result) return false; | |
$return = mysqli_fetch_object($result); | |
mysqli_free_result($result); | |
return $return; | |
} | |
function & aQuery($sql, ...$args) { | |
$result = $this->Query($sql, ...$args); | |
if ($this->num_rows > 1) trigger_error('Multiple row selection for aQuery call', E_USER_WARNING); | |
if (!$result) return false; | |
$return = mysqli_fetch_assoc($result); | |
mysqli_free_result($result); | |
return $return; | |
} | |
function & oQuery($sql, ...$args){ | |
$result = $this->Query($sql, ...$args); | |
if ($this->num_rows > 1) trigger_error('Multiple row selection for oQuery call', E_USER_WARNING); | |
if ($result) { | |
list($sql) = mysqli_fetch_row($result); | |
mysqli_free_result($result); | |
} | |
else | |
$sql = NULL; | |
return $sql; | |
} | |
function & cQuery($sql, ...$args){ | |
$this->Unbuffered = 1; | |
$result = $sql = $this->Query($sql, ...$args); | |
$csql = array(); | |
if ($result) { | |
while (list($_) = mysqli_fetch_row($sql)) $csql[] = $_; | |
mysqli_free_result($result); | |
} | |
return $csql; | |
} | |
function & keyQuery($sql, ...$args){ | |
$this->Unbuffered = 1; | |
$result = $sql = $this->Query($sql, ...$args); | |
$csql = array(); | |
if ($result) { | |
while (list($_) = mysqli_fetch_row($sql)) $csql[$_] = true; | |
mysqli_free_result($result); | |
} | |
return $csql; | |
} | |
function & kvQuery($sql, ...$args) { | |
$this->Unbuffered = 1; | |
$result = $sql = $this->Query($sql, ...$args); | |
$csql = array(); | |
while ($q = mysqli_fetch_row($sql)) | |
$csql[$q[0]] = $q[1]; | |
mysqli_free_result($result); | |
return $csql; | |
} | |
function & rowsQuery($sql, ...$args) { | |
// Same as krQuery but does allows prepared statements and does not accept custom key | |
// The key will be the first column | |
$result = $sql = $this->Query($sql, ...$args); | |
if (!$result) return array(); | |
$key = mysqli_field_name($result, 0); | |
$csql = array(); | |
while ($q = mysqli_fetch_object($sql)) { | |
$csql[$q->$key] = $q; | |
} | |
mysqli_free_result($result); | |
return $csql; | |
} | |
function & krQuery($key, $sql = false) { | |
// Some code leverages the $key variable. Until that is removed this function can't be deprecated | |
// once $key is not in use - replace rowsQuery with krQuery() | |
if (!$sql) { | |
$sql = $key; | |
$key = false; | |
} | |
$result = $sql = $this->Query($sql); | |
if (!$result) return array(); | |
if (!$key) { | |
$key = mysqli_field_name($result, 0); | |
} | |
$csql = array(); | |
while ($q = mysqli_fetch_object($sql)) { | |
$csql[$q->$key] = $q; | |
} | |
mysqli_free_result($result); | |
return $csql; | |
} | |
} | |
$db = new mysqli_db('/path/to/mysql.json'); | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment