340 lines
7.4 KiB
PHP
340 lines
7.4 KiB
PHP
|
<?php
|
||
|
|
||
|
class gmeDB
|
||
|
{
|
||
|
const OPT_FORCE_STMT = 0x1;
|
||
|
const OPT_NASSOC = 0x4;
|
||
|
|
||
|
public $config = array();
|
||
|
|
||
|
private $conn = null;
|
||
|
|
||
|
public $db_host;
|
||
|
public $db_port = null;
|
||
|
public $db_sock = null;
|
||
|
public $db_user;
|
||
|
public $db_pass;
|
||
|
public $db_name;
|
||
|
public $db_pconn = false;
|
||
|
public $db_charset = null;
|
||
|
|
||
|
function __construct(array $conf)
|
||
|
{
|
||
|
$this->config = $conf;
|
||
|
foreach($this->config as $k => $v)
|
||
|
$this->$k = $v;
|
||
|
|
||
|
$this->conn = null;
|
||
|
}
|
||
|
|
||
|
function getConnection()
|
||
|
{
|
||
|
if(!$this->conn)
|
||
|
$this->connect();
|
||
|
return $this->conn;
|
||
|
}
|
||
|
|
||
|
function connect()
|
||
|
{
|
||
|
$this->conn = mysqli_connect(
|
||
|
($this->db_pconn ? 'p:'.$this->db_host : $this->db_host),
|
||
|
$this->db_user,
|
||
|
$this->db_pass,
|
||
|
$this->db_name,
|
||
|
$this->db_port,
|
||
|
$this->db_sock
|
||
|
);
|
||
|
if(!$this->conn)
|
||
|
throw new Exception("Could not connect to mysql server");
|
||
|
|
||
|
if($this->db_charset !== null && !mysqli_set_charset($this->conn, $this->db_charset))
|
||
|
$this->_raise("Charset setup error");
|
||
|
}
|
||
|
|
||
|
function disconnect()
|
||
|
{
|
||
|
if(!$this->conn)
|
||
|
return;
|
||
|
mysqli_close($this->conn);
|
||
|
$this->conn = null;
|
||
|
}
|
||
|
|
||
|
function fetch($sql, array $args = array(), $opts = 0, &$meta = array())
|
||
|
{
|
||
|
if($args || ($opts & self::OPT_FORCE_STMT))
|
||
|
{
|
||
|
$stmt = $this->_newStatement($sql, $args);
|
||
|
$res = $this->_fetchStatement($stmt, $opts, $meta);
|
||
|
}
|
||
|
else
|
||
|
$res = $this->_fetchQuery($sql, $opts, $meta);
|
||
|
|
||
|
return $res;
|
||
|
}
|
||
|
|
||
|
function fetchRow($sql, array $args = array(), $opts = 0, &$meta = array())
|
||
|
{
|
||
|
$rows = $this->fetch($sql, $args, $opts, $meta);
|
||
|
if(isset($rows[0]))
|
||
|
return $rows[0];
|
||
|
}
|
||
|
|
||
|
function fetchOne($sql, array $args = array(), $opts = 0)
|
||
|
{
|
||
|
$row = $this->fetchRow($sql, $args, $opts | self::OPT_NASSOC);
|
||
|
if(!$row || !isset($row[0]))
|
||
|
return NULL;
|
||
|
return $row[0];
|
||
|
}
|
||
|
|
||
|
function execute($sql, array $args = array())
|
||
|
{
|
||
|
if($args)
|
||
|
$this->_newStatement($sql, $args);
|
||
|
else
|
||
|
$this->_newQuery($sql);
|
||
|
}
|
||
|
|
||
|
function sanify($what)
|
||
|
{
|
||
|
if(is_string($what))
|
||
|
return $this->escape($what);
|
||
|
if(is_null($what))
|
||
|
return "NULL";
|
||
|
if(is_array($what))
|
||
|
{
|
||
|
foreach($what as $k => &$v)
|
||
|
$v = $this->sanify($v);
|
||
|
return $what;
|
||
|
}
|
||
|
return 1*$what;
|
||
|
}
|
||
|
|
||
|
function escape($what, $quote = true)
|
||
|
{
|
||
|
if(is_null($what))
|
||
|
return "NULL";
|
||
|
$what = mysqli_escape_string($this->getConnection(), $what);
|
||
|
return $quote ? "'" . $what . "'" : $what;
|
||
|
}
|
||
|
|
||
|
function lastInsertId()
|
||
|
{
|
||
|
return mysqli_insert_id($this->getConnection());
|
||
|
}
|
||
|
|
||
|
function affectedRows()
|
||
|
{
|
||
|
return mysqli_affected_rows($this->getConnection());
|
||
|
}
|
||
|
|
||
|
function getLastError()
|
||
|
{
|
||
|
return array(mysqli_errno($this->conn), mysqli_error($this->conn));
|
||
|
}
|
||
|
|
||
|
private function _newQuery($sql)
|
||
|
{
|
||
|
if(!$this->conn)
|
||
|
$this->connect();
|
||
|
|
||
|
if(!$result = mysqli_query($this->conn, $sql))
|
||
|
$this->_raise("Query error: $sql");
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
private function _fetchQuery($sql, $opts = 0, &$meta = array())
|
||
|
{
|
||
|
$result = $this->_newQuery($sql);
|
||
|
|
||
|
$rows = array();
|
||
|
if($opts & self::OPT_NASSOC)
|
||
|
{
|
||
|
while($row = $result->fetch_row())
|
||
|
$rows[] = $row;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while($row = $result->fetch_assoc())
|
||
|
$rows[] = $row;
|
||
|
}
|
||
|
|
||
|
$result->free();
|
||
|
return $rows;
|
||
|
}
|
||
|
|
||
|
private function _newStatement($sql, array $args = array())
|
||
|
{
|
||
|
if(!$this->conn)
|
||
|
$this->connect();
|
||
|
|
||
|
$stmt = mysqli_prepare($this->conn, $sql);
|
||
|
if(!$stmt)
|
||
|
$this->_raise("Stmt prepare error: $sql");
|
||
|
|
||
|
if($args)
|
||
|
$this->_bindArgs($stmt, $args);
|
||
|
|
||
|
if(!mysqli_stmt_execute($stmt))
|
||
|
$this->_raise("Stmt exec error: $sql");
|
||
|
|
||
|
return $stmt;
|
||
|
}
|
||
|
|
||
|
private function _fetchStatement($stmt, $opts = 0, &$meta = array())
|
||
|
{
|
||
|
$rows = array();
|
||
|
$res_meta = mysqli_stmt_result_metadata($stmt);
|
||
|
$fields = array();
|
||
|
$out = array();
|
||
|
|
||
|
$fields[0] = &$stmt;
|
||
|
$count = 1;
|
||
|
|
||
|
while($field = mysqli_fetch_field($res_meta))
|
||
|
{
|
||
|
$fields[$count++] = &$out[$field->name];
|
||
|
$meta[$field->name] = $field;
|
||
|
}
|
||
|
|
||
|
mysqli_stmt_store_result($stmt);
|
||
|
call_user_func_array('mysqli_stmt_bind_result', $fields);
|
||
|
if($opts & self::OPT_NASSOC)
|
||
|
{
|
||
|
while(mysqli_stmt_fetch($stmt))
|
||
|
{
|
||
|
$out_deref = array();
|
||
|
foreach($out as $v)
|
||
|
$out_deref[] = $v;
|
||
|
$rows[] = $out_deref;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while(mysqli_stmt_fetch($stmt))
|
||
|
{
|
||
|
$out_deref = array();
|
||
|
foreach($out as $k => $v)
|
||
|
$out_deref[$k] = $v;
|
||
|
$rows[] = $out_deref;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mysqli_stmt_free_result($stmt);
|
||
|
mysqli_stmt_close($stmt);
|
||
|
|
||
|
return $rows;
|
||
|
}
|
||
|
|
||
|
private function _bindArgs($stmt, array $args)
|
||
|
{
|
||
|
$types = '';
|
||
|
$blob = null;
|
||
|
$blob_pos = -1;
|
||
|
$c = 0;
|
||
|
foreach($args as $key => $arg)
|
||
|
{
|
||
|
if(is_string($key))
|
||
|
{
|
||
|
$types .= $key;
|
||
|
|
||
|
//NOTE: supporting exactly one blob special case
|
||
|
if($key === 'b')
|
||
|
{
|
||
|
$blob = &$args[$key];
|
||
|
$blob_pos = $c;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(is_string($arg) || is_null($arg))
|
||
|
$types .= 's';
|
||
|
else if(is_int($arg) || is_bool($arg))
|
||
|
$types .= 'i';
|
||
|
else if(is_float($arg))
|
||
|
$types .= 'd';
|
||
|
else
|
||
|
throw new Exception("Unknown type of variable '" . serialize($arg) . "'");
|
||
|
}
|
||
|
++$c;
|
||
|
}
|
||
|
|
||
|
$res = call_user_func_array('mysqli_stmt_bind_param', array_merge(array($stmt, $types), $this->_refValues($args)));
|
||
|
if(!$res)
|
||
|
$this->_raise("Stmt bind error");
|
||
|
|
||
|
if($blob !== null)
|
||
|
{
|
||
|
if(!mysqli_stmt_send_long_data($stmt, $blob_pos, $blob))
|
||
|
$this->_raise("Stmt blob send error");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private function _refValues(array $arr)
|
||
|
{
|
||
|
$refs = array();
|
||
|
foreach($arr as $key => $value)
|
||
|
$refs[$key] = &$arr[$key];
|
||
|
return $refs;
|
||
|
}
|
||
|
|
||
|
private function _raise($err)
|
||
|
{
|
||
|
throw new Exception($err . ", MySQLi error:" . mysqli_error($this->conn));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function gme_db_insert_or_update_sql_ex($table, array $fields, array $rows)
|
||
|
{
|
||
|
$update = array();
|
||
|
foreach($fields as $field)
|
||
|
$update[] = $field.'=VALUES('.$field.')';
|
||
|
|
||
|
$sql = '';
|
||
|
$sql .= 'INSERT INTO '.$table.' ('.implode(',', $fields).') VALUES ';
|
||
|
|
||
|
foreach($rows as $row)
|
||
|
$sql .= '('.implode(',', $row).'),';
|
||
|
$sql = rtrim($sql, ',');
|
||
|
|
||
|
$sql .= 'ON DUPLICATE KEY UPDATE '.implode(',', $update);
|
||
|
|
||
|
return $sql;
|
||
|
}
|
||
|
|
||
|
function gme_db_insert_or_update_sql($table, array $row)
|
||
|
{
|
||
|
return gme_db_insert_or_update_sql_ex($table, array_keys($row), array($row));
|
||
|
}
|
||
|
|
||
|
function gme_db_insert_sql_ex($table, array $fields, array $rows, $delayed = false, $replace = false)
|
||
|
{
|
||
|
$sql = '';
|
||
|
$sql .= $replace ? 'REPLACE ' : 'INSERT ';
|
||
|
$sql .= $delayed ? ' DELAYED ' : '';
|
||
|
$sql .= 'INTO '.$table.' ('.implode(',', $fields).') VALUES ';
|
||
|
|
||
|
foreach($rows as $row)
|
||
|
$sql .= '('.implode(',', $row).'),';
|
||
|
$sql = rtrim($sql, ',');
|
||
|
|
||
|
return $sql;
|
||
|
}
|
||
|
|
||
|
function gme_db_insert_sql($table, array $row, $delayed = false)
|
||
|
{
|
||
|
return gme_db_insert_sql_ex($table, array_keys($row), array($row), $delayed);
|
||
|
}
|
||
|
|
||
|
function gme_db_replace_sql_ex($table, array $fields, array $rows, $delayed = false)
|
||
|
{
|
||
|
return gme_db_insert_sql_ex($table, $fields, $rows, $delayed, true/*replace*/);
|
||
|
}
|
||
|
|
||
|
function gme_db_replace_sql($table, array $row, $delayed = false)
|
||
|
{
|
||
|
return gme_db_insert_sql_ex($table, array_keys($row), array($row), $delayed, true/*replace*/);
|
||
|
}
|
||
|
|