trying to port web app starter from PHP
This commit is contained in:
+381
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
|
||||
class DB
|
||||
{
|
||||
|
||||
static $dataCache = array();
|
||||
static $link = false;
|
||||
static $lastQuery = '';
|
||||
static $keyDef = array();
|
||||
static $affectedRows = 0;
|
||||
static $writeOps = 0;
|
||||
static $readOps = 0;
|
||||
static $track_changes_in_tables = array();
|
||||
|
||||
static function isConnected()
|
||||
{
|
||||
return(self::$link instanceof mysqli);
|
||||
}
|
||||
|
||||
static function connect()
|
||||
{
|
||||
if(self::$link) return;
|
||||
if(!cfg('db/user')) die('database not configured');
|
||||
Profiler::Log('DB::Connect() start');
|
||||
self::$link = mysqli_connect(cfg('db/host'), cfg('db/user'), cfg('db/password'), cfg('db/database'), ini_get("mysqli.default_port"), cfg('db/socket')) or
|
||||
critical('The database connection to server '.cfg('db/user').'@'.cfg('db/host').
|
||||
' could not be established (code: '.@mysqli_connect_errno(self::$link).': '.@mysqli_connect_error(self::$link).')');
|
||||
#if(mysqli_character_set_name(self::$link) != 'utf8')
|
||||
mysqli_set_charset(self::$link, 'utf8mb4');
|
||||
self::$track_changes_in_tables = cfg('track/changes');
|
||||
Profiler::Log('DB::Connect() done');
|
||||
}
|
||||
|
||||
static function Update($table, $searchCriteria, $updateFields)
|
||||
{
|
||||
self::$writeOps++;
|
||||
DB::Query('UPDATE #'.DB::Safe($table).'
|
||||
SET '.DB::MakeSetList($updateFields).'
|
||||
WHERE '.DB::MakeSetList($searchCriteria, ' AND '));
|
||||
}
|
||||
|
||||
static function GetCached($query, $parameters = null)
|
||||
{
|
||||
$cacheKey = 'dbq-'.md5($query.json_encode($parameters));
|
||||
$result = Cache::Get($cacheKey);
|
||||
if(!$result)
|
||||
{
|
||||
$result = self::Get($query, $parameters);
|
||||
Cache::Set($cacheKey, $result);
|
||||
}
|
||||
return($result);
|
||||
}
|
||||
|
||||
# get a list of datasets matching the $query
|
||||
static function Get($query, $parameters = null, $keyByField = null)
|
||||
{
|
||||
self::$readOps++;
|
||||
$result = array();
|
||||
|
||||
$query = self::ParseQueryParams($query, $parameters);
|
||||
|
||||
$lines = mysqli_query(self::$link, $query) or critical(mysqli_error(self::$link).' {query: '.$query.' }');
|
||||
|
||||
while ($line = mysqli_fetch_array($lines, MYSQLI_ASSOC))
|
||||
{
|
||||
if ($keyByField !== null && isset($line[$keyByField]))
|
||||
$result[$line[$keyByField]] = $line;
|
||||
else
|
||||
$result[] = $line;
|
||||
}
|
||||
mysqli_free_result($lines);
|
||||
|
||||
Profiler::Log('DB::Get('.substr($query, 0, 40).'...)');
|
||||
return $result;
|
||||
}
|
||||
|
||||
# gets a list of keys for the table
|
||||
static function Keys($tablename)
|
||||
{
|
||||
if(isset(self::$keyDef[$tablename]))
|
||||
return(self::$keyDef[$tablename]);
|
||||
|
||||
self::$readOps++;
|
||||
$result = array();
|
||||
$sql = 'SHOW KEYS FROM `'.$tablename.'`';
|
||||
$res = mysqli_query(self::$link, $sql) or critical('Cannot get keys // '.mysqli_error(self::$link));
|
||||
|
||||
while ($row = @mysqli_fetch_assoc($res))
|
||||
{
|
||||
if ($row['Key_name']=='PRIMARY')
|
||||
array_push($result, $row['Column_name']);
|
||||
}
|
||||
|
||||
Profiler::Log('DB::Keys('.$tablename.') REBUILD KEY CACHE');
|
||||
self::$keyDef[$tablename] = $result;
|
||||
return($result);
|
||||
}
|
||||
|
||||
# get column info for $table
|
||||
static function Info($table)
|
||||
{
|
||||
self::$readOps++;
|
||||
$result = array('fields' => array(), 'info' => array());
|
||||
foreach(self::Get('SHOW FULL COLUMNS FROM #'.$table) as $fld)
|
||||
{
|
||||
$ds = array();
|
||||
foreach($fld as $k => $v)
|
||||
{
|
||||
$k = strtolower($k);
|
||||
if($k == 'comment')
|
||||
{
|
||||
$p = explode(',', $v);
|
||||
$v = false;
|
||||
if(sizeof($p) > 0) foreach($p as $pi)
|
||||
{
|
||||
$pk = trim(nibble('=', $pi));
|
||||
$ds['_'.$pk] = trim($pi);
|
||||
}
|
||||
}
|
||||
if($v)
|
||||
$ds[$k] = $v;
|
||||
}
|
||||
$ds['caption'] = first($ds['_title'], $ds['field']);
|
||||
$result['fields'][$ds['field']] = $ds;
|
||||
}
|
||||
return($result);
|
||||
}
|
||||
|
||||
# updates/creates the $dataset in the $tablename
|
||||
static function Insert($tablename, $dataset)
|
||||
{
|
||||
self::$writeOps++;
|
||||
$query='INSERT INTO '.$tablename.' ('.DB::MakeNamesList($dataset).
|
||||
') VALUES('.DB::MakeValuesList($dataset).')';
|
||||
|
||||
mysqli_query(self::$link, $query) or critical(mysqli_error(self::$link).'{ '.$query.' }');
|
||||
self::$affectedRows += mysqli_affected_rows(self::$link);
|
||||
return(mysqli_insert_id(self::$link));
|
||||
}
|
||||
|
||||
# updates/creates the $dataset in the $tablename
|
||||
static function Commit($tablename, &$dataset)
|
||||
{
|
||||
self::$writeOps++;
|
||||
$keynames = self::Keys($tablename);
|
||||
$keyname = $keynames[0];
|
||||
$keyvalue = $dataset[$keyname];
|
||||
Profiler::Log('DB::Commit('.$tablename.', '.$dataset[$keyname].') start');
|
||||
|
||||
$cache_entry = $tablename.':'.$keyname.':'.$keyvalue;
|
||||
unset(self::$dataCache[$cache_entry]);
|
||||
|
||||
$query='REPLACE INTO '.$tablename.' ('.DB::MakeNamesList($dataset).
|
||||
') VALUES('.DB::MakeValuesList($dataset).');';
|
||||
|
||||
# keeping this around just in case, but performance seems the same:
|
||||
# $query='INSERT INTO '.$tablename.' ('.DB::MakeNamesList($dataset).
|
||||
# ') VALUES('.DB::MakeValuesList($dataset).')
|
||||
# ON DUPLICATE KEY UPDATE '.DB::MakeSetList($dataset).';';
|
||||
|
||||
mysqli_query(self::$link, $query) or critical(mysqli_error(self::$link).' { '.$query.' }');
|
||||
$dataset[$keyname] = first($dataset[$keyname], mysqli_insert_id(self::$link));
|
||||
self::$dataCache[$cache_entry] = $dataset;
|
||||
|
||||
Profiler::Log('DB::Commit('.$tablename.', '.$dataset[$keyname].') done');
|
||||
return($dataset[$keyname]);
|
||||
}
|
||||
|
||||
static function GetRowsMatch($table, $matchOptions, $fillIfEmpty = true)
|
||||
{
|
||||
self::$readOps++;
|
||||
$where = array('1');
|
||||
foreach($matchOptions as $k => $v)
|
||||
$where[] = '('.$k.'="'.DB::Safe($v).'")';
|
||||
$iwhere = implode(' AND ', $where);
|
||||
$query = 'SELECT * FROM '.($table).
|
||||
' WHERE '.$iwhere;
|
||||
$resultDS = self::GetRowWithQuery($query);
|
||||
if ($fillIfEmpty && sizeof($resultDS) == 0)
|
||||
foreach($matchOptions as $k => $v)
|
||||
$resultDS[$k] = $v;
|
||||
Profiler::Log('DB::GetRowsMatch('.$table.') done');
|
||||
return($resultDS);
|
||||
}
|
||||
|
||||
# from table $tablename, get dataset with key $keyvalue
|
||||
static function GetRow($tablename, $keyvalue, $keyname = '', $options = array())
|
||||
{
|
||||
if($keyvalue == '0') return(array());
|
||||
$fields = @$options['fields'];
|
||||
$fields = first($fields, '*');
|
||||
if (!self::$link) return(array());
|
||||
|
||||
if ($keyname == '')
|
||||
{
|
||||
$keynames = self::Keys($tablename);
|
||||
$keyname = $keynames[0];
|
||||
}
|
||||
|
||||
$cache_entry = $tablename.':'.$keyname.':'.$keyvalue;
|
||||
if(isset(self::$dataCache[$cache_entry])) return(self::$dataCache[$cache_entry]);
|
||||
|
||||
$join = isset($options['join']) ? ' '.$options['join'] : '';
|
||||
$query = 'SELECT '.$fields.' FROM '.$tablename.$join.' WHERE '.$keyname.'="'.DB::Safe($keyvalue).'";';
|
||||
$queryResult = mysqli_query(self::$link, $query) or critical(mysqli_error(self::$link).' { Query: "'.$query.'" }');
|
||||
self::$readOps++;
|
||||
|
||||
if ($line = @mysqli_fetch_array($queryResult, MYSQLI_ASSOC))
|
||||
{
|
||||
mysqli_free_result($queryResult);
|
||||
self::$dataCache[$cache_entry] = $line;
|
||||
Profiler::Log('DB::GetRow('.$tablename.', '.$keyvalue.')');
|
||||
return($line);
|
||||
}
|
||||
else
|
||||
$result = array();
|
||||
|
||||
Profiler::Log('DB::GetRow('.$tablename.', '.$keyvalue.') #fail');
|
||||
return($result);
|
||||
}
|
||||
|
||||
static function RemoveRow($tablename, $keyvalue, $keyname = null)
|
||||
{
|
||||
if ($keyname == null)
|
||||
{
|
||||
$keynames = self::Keys($tablename);
|
||||
$keyname = $keynames[0];
|
||||
}
|
||||
$res = (mysqli_query(self::$link, 'DELETE FROM '.$tablename.' WHERE '.$keyname.'="'.
|
||||
DB::Safe($keyvalue).'";')
|
||||
or critical(' Cannot remove dataset // '.mysqli_error(self::$link)));
|
||||
Profiler::Log('DB::RemoveRow('.$tablename.', '.$keyvalue.') done');
|
||||
self::$affectedRows += mysqli_affected_rows(self::$link);
|
||||
self::$writeOps++;
|
||||
return($res);
|
||||
}
|
||||
|
||||
// retrieve dataset identified by SQL $query
|
||||
static function GetRowWithQuery($query, $parameters = null)
|
||||
{
|
||||
$query = self::ParseQueryParams($query, $parameters);
|
||||
|
||||
$queryResult = mysqli_query(self::$link, $query);
|
||||
|
||||
if(!$queryResult)
|
||||
return(critical('Error getting data // '.mysqli_error(self::$link).'{ '.$query.' }'));
|
||||
|
||||
if ($line = mysqli_fetch_array($queryResult, MYSQLI_ASSOC))
|
||||
{
|
||||
$result = $line;
|
||||
mysqli_free_result($queryResult);
|
||||
}
|
||||
else
|
||||
$result = array();
|
||||
|
||||
Profiler::Log('DB::GetRowWithQuery('.$query.')');
|
||||
self::$readOps++;
|
||||
return($result);
|
||||
}
|
||||
|
||||
# execute a simple update $query
|
||||
static function Query($query, $parameters = null)
|
||||
{
|
||||
$query = self::parseQueryParams($query, $parameters);
|
||||
if (substr($query, -1, 1) == ';')
|
||||
$query = substr($query, 0, -1);
|
||||
$result = (mysqli_query(self::$link, $query)
|
||||
or critical(' Query error // '.mysqli_error(self::$link)));
|
||||
Profiler::Log('DB::Query('.$query.') done');
|
||||
self::$affectedRows += mysqli_affected_rows(self::$link);
|
||||
self::$writeOps++;
|
||||
return($result);
|
||||
}
|
||||
|
||||
# create a comma-separated list of keys in $dataset
|
||||
static function MakeNamesList(&$dataset)
|
||||
{
|
||||
$result = '';
|
||||
if (sizeof($dataset) > 0)
|
||||
foreach (array_keys($dataset) as $k)
|
||||
{
|
||||
if ($k!='')
|
||||
$result = $result.','.$k;
|
||||
}
|
||||
return(substr($result, 1));
|
||||
}
|
||||
|
||||
# make a name-value list for UPDATE-queries
|
||||
static function MakeValuesList(&$dataset)
|
||||
{
|
||||
$result = '';
|
||||
if (sizeof($dataset) > 0)
|
||||
foreach ($dataset as $k => $v)
|
||||
{
|
||||
if ($k!='')
|
||||
$result = $result.',"'.DB::safe($v).'"';
|
||||
}
|
||||
return(substr($result, 1));
|
||||
}
|
||||
|
||||
static function MakeSetList(&$dataset, $concat = ', ')
|
||||
{
|
||||
$result = array();
|
||||
if (sizeof($dataset) > 0) foreach ($dataset as $k => $v)
|
||||
{
|
||||
if(substr($k, -1) == '+' || substr($k, -1) == '-')
|
||||
{
|
||||
$op = substr($k, -1);
|
||||
$k = substr($k, 0, -1);
|
||||
$result[] = $k.' = '.$k.' '.$op.' "'.DB::safe($v).'"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[] = $k.' = "'.DB::safe($v).'"';
|
||||
}
|
||||
}
|
||||
return(implode($concat, $result));
|
||||
}
|
||||
|
||||
static function ParseQueryParams($query, $parameters = null)
|
||||
{
|
||||
if ($parameters != null)
|
||||
{
|
||||
$pctr = 0;
|
||||
$result = '';
|
||||
for($a = 0; $a < strlen($query); $a++)
|
||||
{
|
||||
$chr = substr($query, $a, 1);
|
||||
if ($chr == '?')
|
||||
{
|
||||
$result .= '"'.DB::Safe($parameters[$pctr]).'"';
|
||||
$pctr++;
|
||||
}
|
||||
else if ($chr == '&')
|
||||
{
|
||||
$result .= ''.intval($parameters[$pctr]).'';
|
||||
$pctr++;
|
||||
}
|
||||
else if ($chr == ':')
|
||||
{
|
||||
$paramName = '';
|
||||
$a += 1;
|
||||
$pFormat = 'string';
|
||||
if($query[$a] == ':')
|
||||
{
|
||||
$pFormat = 'number';
|
||||
$a += 1;
|
||||
}
|
||||
while(!ctype_space($chr = substr($query, $a, 1)) && $a < strlen($query))
|
||||
{
|
||||
$paramName .= $chr;
|
||||
$a += 1;
|
||||
}
|
||||
if($pFormat == 'number')
|
||||
$result .= ' '.($parameters[$paramName]+0).' ';
|
||||
else
|
||||
$result .= ' "'.DB::Safe($parameters[$paramName]).'" ';
|
||||
}
|
||||
else
|
||||
$result .= $chr;
|
||||
}
|
||||
}
|
||||
else
|
||||
$result = $query;
|
||||
$q = str_replace('#', cfg('db/prefix'), $result);
|
||||
self::$lastQuery = $q;
|
||||
return($q);
|
||||
}
|
||||
|
||||
static function Safe($raw)
|
||||
{
|
||||
if(!self::$link)
|
||||
return(addslashes($raw));
|
||||
else
|
||||
return(mysqli_real_escape_string(self::$link, $raw));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DB::connect();
|
||||
|
||||
Reference in New Issue
Block a user