master
Vitaliy Filippov 2012-09-30 22:44:34 +00:00
commit 31d27904d2
1 changed files with 394 additions and 0 deletions

394
DatabaseMysql.php Normal file
View File

@ -0,0 +1,394 @@
<?php
/**
* Very stable interface for MySQL - object-oriented at last :)
* Select builder is inspired by MediaWiki's one.
* (c) Vitaliy Filippov, 2012
*/
define('MS_HASH', 0);
define('MS_LIST', 1);
define('MS_ROW', 2);
define('MS_ONE', 2);
define('MS_COL', 4);
define('MS_VALUE', 6);
define('MS_RESULT', 8);
class DatabaseMysql
{
var $dbName;
var $link;
var $tableNames = array();
var $queryCount = 0;
var $queryLogFile;
function __construct($host, $username, $password, $dbname, $port = NULL, $socket = NULL)
{
if ($socket !== NULL)
{
$this->link = new mysqli($host, $username, $password, $dbname, $port, $socket);
}
elseif ($port !== NULL)
{
$this->link = new mysqli($host, $username, $password, $dbname, $port);
}
else
{
$this->link = new mysqli($host, $username, $password, $dbname);
}
$this->dbName = $dbname;
}
function getDBName()
{
return $this->dbName;
}
function quoteId($name)
{
return "`".str_replace("`", "``", $name)."`";
}
function quote($value)
{
if ($value === NULL)
return "NULL";
return "'" . $this->link->real_escape_string($s) . "'";
}
function query($sql, $fetchMode = MYSQLI_STORE_RESULT)
{
$this->queryCount++;
if ($this->queryLogFile)
{
file_put_contents($this->queryLogFile, date("[Y-m-d H:i:s] ").$sql."\n", FILE_APPEND);
}
return $this->link->query($sql, $fetchMode);
}
function where_builder($where)
{
if (!is_array($where))
return $where;
$wh = array();
foreach ($where as $k => $v)
{
if (ctype_digit($k))
$wh[] = $v;
elseif (is_array($v))
{
if (!$v)
{
throw new DatabaseException(E_DB_EMPTY_IN, "Error: empty array for '$k IN (...)', don't know what to do");
}
else
{
if (is_array($v[0]))
foreach ($v as &$l)
$l = "(" . implode(",", array_map(array($this, 'quote'), $l)) . ")";
else
$v = array_map(array($this, 'quote'), $v);
$wh[] = "$k IN (" . implode(",", $v) . ")";
}
}
elseif ($v !== NULL)
$wh[] = "$k=".$this->quote($v);
else
$wh[] = "$k IS NULL";
}
if (!$wh)
$where = '1';
else
$where = '(' . join(') AND (', $wh) . ')';
return $where;
}
function select_builder($tables, $fields, $where, $options = NULL)
{
if (!$options)
$options = array();
else
{
foreach ($options as $k => $v)
if (ctype_digit($k))
$options[$v] = true;
}
if (is_array($fields))
$fields = join(',', $fields);
$where = $this->where_builder($where);
$tables = $this->tables_builder($tables);
$sql = 'SELECT ';
if ($options['CALC_FOUND_ROWS'] || $options['SQL_CALC_FOUND_ROWS'])
$sql .= 'SQL_CALC_FOUND_ROWS ';
if ($options['NO_CACHE'] || $options['SQL_NO_CACHE'])
$sql .= 'SQL_NO_CACHE ';
elseif ($options['CACHE'] || $options['SQL_CACHE'])
$sql .= 'SQL_CACHE ';
$sql .= "$fields FROM $tables WHERE $where";
if ($g = $options['GROUP BY'])
{
if (is_array($g))
{
$g1 = array();
foreach ($g as $k => $v)
{
if (ctype_digit($k))
$g1[] = $v;
else
$g1[] = "$k $v";
}
$g = join(',', $g1);
}
$sql .= " GROUP BY $g";
}
if ($g = $options['ORDER BY'])
{
if (is_array($g))
{
$g1 = array();
foreach ($g as $k => $v)
{
if (ctype_digit($k))
$g1[] = $v;
else
$g1[] = "$k $v";
}
$g = join(',', $g1);
}
$sql .= " ORDER BY $g";
}
if ($g = $options['LIMIT'])
{
if (is_array($g))
$g = join(',', $g);
if ($g)
$sql .= " LIMIT $g";
}
if ($options['FOR UPDATE'])
$sql .= ' FOR UPDATE';
elseif ($options['LOCK IN SHARE MODE'])
$sql .= ' LOCK IN SHARE MODE';
return $sql;
}
function tables_builder($tables)
{
if (is_array($tables))
{
$t = '';
foreach ($tables as $k => $v)
{
if (!ctype_digit($k))
{
if (is_array($v))
{
$join = substr(strtolower($v[0]), 0, 4);
if ($join == 'righ')
$join = 'RIGHT';
elseif ($join == 'left')
$join = 'LEFT';
else /* if (!$join || $join == 'inne' || $join == 'join') */
$join = 'INNER';
if (is_array($v[1])) // nested join (left join (A join B on ...) on ...)
$table = '('.$this->tables_builder($v[1]).')';
else
$table = (isset($this->tableNames[$v[1]]) ? $this->quoteId($this->tableNames[$v[1]]) : $v[1]) . ' ' . $k;
if ($t)
$t .= " $join JOIN $table ON ".$this->where_builder($v[2]);
else
$t = $table;
continue;
}
else
$v = (isset($this->tableNames[$v]) ? $this->quoteId($this->tableNames[$v]) : $v) . ' ' . $k;
}
else
$v = (isset($this->tableNames[$v]) ? $this->quoteId($this->tableNames[$v]).' '.$v : $v);
if ($t)
$t .= " INNER JOIN $v";
else
$t = $v;
}
$tables = $t;
}
else
$tables = preg_replace_callback('/((?:,|JOIN)\s*`)([^`]+)/s', array($this, 'tables_builder_pregcb1'), $tables);
return $tables;
}
function tables_builder_pregcb1($m)
{
$t = $this->tableNames[$m[2]];
if (!$t)
$t = $m[2];
return $m[1].$t;
}
function select($tables, $fields = '*', $where = 1, $options = NULL, $format = 0)
{
if (!strcmp(intval($fields), "$fields"))
{
$sql = $tables;
$format = $fields;
}
else
$sql = $this->select_builder($tables, $fields, $where, $options);
if ($format & MS_RESULT)
return $this->query($sql, MYSQLI_USE_RESULT);
if ($format & MS_LIST)
$r = $this->get_rows($sql);
else
$r = $this->get_assocs($sql);
if (!$r)
$r = array();
if ($format & MS_ROW)
{
if ($format & MS_COL)
{
if (!count($r))
return NULL;
$r = $r[0];
$k = array_keys($r);
$r = $r[$k[0]];
}
else
$r = $r[0];
}
elseif ($format & MS_COL)
{
foreach ($r as $i => $v)
{
if (!$k)
{
$k = array_keys($v);
$k = $k[0];
}
$r[$i] = $v[$k];
}
}
return $r;
}
function found_rows()
{
return $this->select('SELECT FOUND_ROWS()', MS_VALUE);
}
function delete($tables, $where, $options = NULL)
{
$tables = $this->tables_builder($tables);
$where = $this->where_builder($where);
$sql = "DELETE FROM $tables WHERE $where";
if (is_array($options))
{
if ($g = $options['LIMIT'])
{
if (is_array($g))
$g = join(',', $g);
if ($g)
$sql .= " LIMIT $g";
}
}
$this->query($sql);
return $this->link->affected_rows;
}
function insert_builder($table, $rows, $onduplicatekey = false)
{
if ($this->tableNames[$table])
$table = $this->tableNames[$table];
$key = array_keys($rows[0]);
foreach ($rows as &$r)
{
$rs = array();
foreach ($key as &$k)
$rs[] = $this->quote($r[$k]);
$r = "(".implode(",", $rs).")";
}
foreach ($key as &$k)
if (strpos($k, '`') === false)
$k = $this->quoteId($k);
$sql = "INSERT INTO $table (".implode(",",$key).") VALUES ".implode(",",$rows);
if ($onduplicatekey)
{
foreach ($key as &$k)
$k = "$k=VALUES($k)";
$sql .= " ON DUPLICATE KEY UPDATE ".implode(",",$key);
}
return $sql;
}
function insert_row($table, $row)
{
$sql = $this->insert_builder($table, array($row));
if ($this->query($sql))
return $this->link->insert_id;
return NULL;
}
function update($table, $rows, $where = NULL, $options = NULL)
{
if (!$rows)
return false;
if (is_null($where))
{
if (!is_array($rows))
return false;
if (!is_array($rows[0]))
$rows = array($rows);
$sql = $this->insert_builder($table, $rows, true);
}
else
{
$sql = array();
if (!is_array($rows))
$rows = array($rows);
foreach ($rows as $k => $v)
{
if (!ctype_digit($k))
$sql[] = $k.'='.$this->quote($v);
else
$sql[] = $v;
}
$where = $this->where_builder($where);
$sql = 'UPDATE ' . $this->tables_builder($table) . ' SET ' . implode(', ', $sql) . ' WHERE ' . $where;
if (is_array($options))
{
if ($g = $options['LIMIT'])
{
if (is_array($g))
$g = join(',', $g);
if ($g)
$sql .= " LIMIT $g";
}
}
}
if ($this->query($sql))
return $this->link->affected_rows;
return false;
}
function get_rows($sql)
{
$r = array();
if ($res = $this->query($sql))
{
while ($row = $res->fetch_row())
$r[] = $row;
$res->free();
}
return $r;
}
function get_assocs($sql)
{
$r = array();
if ($res = $this->query($sql))
{
while ($row = $res->fetch_assoc())
$r[] = $row;
$res->free();
}
return $r;
}
}