1647 lines
61 KiB
PHP
1647 lines
61 KiB
PHP
<?php
|
|
|
|
namespace BRSystems\Core\Library\cDb;
|
|
|
|
use BRSystems\Core\Library\cDbLog\cDbLog;
|
|
use BRSystems\Core\Library\cJSON\cJSON;
|
|
use BRSystems\Core\Library\cSysConsole\cSysConsole;
|
|
use mysqli;
|
|
|
|
/**
|
|
* A PHP class to access MySQLi database with convenient methods
|
|
*
|
|
* @version 1.1
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
*
|
|
*/
|
|
class cDb{
|
|
|
|
var $mtStart; // INTERNAL: The start time, in milliseconds.
|
|
var $nbQueries; // INTERNAL: The number of executed queries.
|
|
var $lastResult; // INTERNAL: The last result resource of a query().
|
|
var $link;
|
|
|
|
public $history = array();
|
|
|
|
private $debug = false;
|
|
public $mysqli = false;
|
|
|
|
/**
|
|
* @var cDbLog $oDBLog
|
|
*/
|
|
public $oDBLog = false;
|
|
private $bDBLogSkip = false;
|
|
|
|
private $sTransactionSql = "";
|
|
private $lTransactionCount = 0;
|
|
private $lMAxTransactionCount = 0;
|
|
private $bTransactionActive = false;
|
|
|
|
const OP = 'o';
|
|
const VAL = 'v';
|
|
const OP_IN = 'IN';
|
|
const DEF_WHERE = "1 = 1";
|
|
|
|
private $oConsole;
|
|
|
|
private static $callCounter = 0;
|
|
private static $instances = array();
|
|
|
|
/**
|
|
* Class singleton constructor
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param bool|string $host - Db host domain or IP
|
|
* @param bool|string $user - Connection user
|
|
* @param bool|string $password - Connection user password
|
|
* @param bool|string $dbName - Database name
|
|
* @param bool|string $port - Connection port to use or default 3306
|
|
* @param string $sKeyAddIn - instance key add-in
|
|
*
|
|
* @return cDb $this - instance of cDb class
|
|
*/
|
|
public static function getInstance($host = false, $user = false, $password = false, $port = false, $dbName = false, $sKeyAddIn = ''){
|
|
|
|
if(!($host || $user || $password || $dbName || $port)){
|
|
$host = ($host ? $host : DB_HOST);
|
|
$user = ($user ? $user : DB_USR);
|
|
$password = ($password ? $password : DB_PWD);
|
|
$port = ($port ? $port : DB_PORT);
|
|
$dbName = ($dbName ? $dbName : (defined('COMP_DB_NAME') ? COMP_DB_NAME : DB_NAME));
|
|
}
|
|
|
|
// Create key
|
|
$key = "{$host}|{$user}|{$password}|{$port}|{$dbName}" . ($sKeyAddIn ? "|{$sKeyAddIn}" : "");
|
|
|
|
// Singleton initiation
|
|
if(empty(self::$instances[$key])){
|
|
self::$instances[$key] = new self($host, $user, $password, $port, $dbName);
|
|
}
|
|
self::$callCounter++;
|
|
|
|
return self::$instances[$key];
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Class constructor
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param bool|string $host - Db host domain or IP
|
|
* @param bool|string $user - Connection user
|
|
* @param bool|string $password - Connection user password
|
|
* @param bool|string $dbName - Database name
|
|
* @param bool|string $port - Connection port to use or default 3306
|
|
*/
|
|
public function __construct($host = false, $user = false, $password = false, $port = false, $dbName = false){
|
|
|
|
if(!($host || $user || $password || $dbName || $port)){
|
|
$host = ($host ? $host : DB_HOST);
|
|
$user = ($user ? $user : DB_USR);
|
|
$password = ($password ? $password : DB_PWD);
|
|
$port = ($port ? $port : DB_PORT);
|
|
$dbName = ($dbName ? $dbName : (defined('COMP_DB_NAME') ? COMP_DB_NAME : DB_NAME));
|
|
}
|
|
|
|
$this->debug = (defined('DB_DEBUG') ? DB_DEBUG : false);
|
|
$this->mtStart = $this->getMicroTime();
|
|
$this->nbQueries = 0;
|
|
$this->lastResult = NULL;
|
|
|
|
// Establish connection
|
|
$this->mysqli = new mysqli($host, $user, $password, $dbName, $port);
|
|
|
|
// check connection
|
|
if($this->mysqli->connect_errno) {
|
|
printf("Connect failed: %s\n", ($this->debug ? $this->mysqli->connect_error : 'Server connexion not possible.'));
|
|
exit();
|
|
}
|
|
|
|
// Charset
|
|
$this->mysqli->set_charset("utf8");
|
|
|
|
// Setup console output object - singleton
|
|
if($this->debug){
|
|
$this->oConsole = cSysConsole::getInstance();
|
|
$this->oConsole->addOutputLine(array(
|
|
'Connection established', "host: {$host}", "user: {$user}", "password: " . preg_replace("/./im","*",$password), "db: {$dbName}"
|
|
));
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient method for mysqli_multi_query().
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $query - The query.
|
|
* @param bool $bBufferForFurtherUser - buffer query.
|
|
* @param bool|string $sTable - logger set table for convenience
|
|
* @param bool|string $sWhere - logger set where statement for data shift
|
|
* @return Bool result of the query.
|
|
*/
|
|
public function executeMulti($query, $bBufferForFurtherUser = false, $sTable = false, $sWhere = false){
|
|
$this->queryMulti($query, $sTable, $sWhere);
|
|
return $this->freeMulti($bBufferForFurtherUser);
|
|
}
|
|
private function queryMulti($query, $sTable = false, $sWhere = false){
|
|
|
|
$iLogId = 0;
|
|
$this->nbQueries++;
|
|
|
|
// Log query
|
|
if(!$this->bDBLogSkip && $this->oDBLog)
|
|
$iLogId = $this->oDBLog->log($query, $sTable, $sWhere);
|
|
|
|
|
|
// Exec query
|
|
$iStart = microtime(true);
|
|
$this->mysqli->multi_query($query) or $this->debugAndDie($query);
|
|
$iEnd = microtime(true);
|
|
|
|
|
|
// Update exec time
|
|
if(!$this->bDBLogSkip && $this->oDBLog && $iLogId)
|
|
$this->oDBLog->updRecordData($iLogId, array('s' => ($iEnd - $iStart)));
|
|
$this->bDBLogSkip = false;
|
|
|
|
// Save history in debug mode
|
|
if($this->debug){
|
|
$this->history[] = array(
|
|
'query' => $query,
|
|
'time' => ($iEnd - $iStart) . 's'
|
|
);
|
|
$this->oConsole->addOutputLine(array(
|
|
'SQL', "Exec time: " . ($iEnd - $iStart) . "s", "<b class='sql'>{$query}</b>"
|
|
), 'sql');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Convenient method for mysqli_query().
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $query - The query.
|
|
* @param mixed $sTable - logger set table for convenience
|
|
* @param bool|string $sWhere - logger set where statement for data shift
|
|
* @return bool|array result of the query.
|
|
*/
|
|
public function execute($query, $sTable = false, $sWhere = false){
|
|
return $this->query($query, $sTable, $sWhere);
|
|
}
|
|
|
|
/**
|
|
* Convenient method for mysqli_query().
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $query - The query.
|
|
* @param mixed $sTable - logger set table for convenience
|
|
* @param bool|string $sWhere - logger set where statement for data shift
|
|
* @return bool|array result of the query.
|
|
*/
|
|
private $iLogId = false;
|
|
|
|
public function query($query, $sTable = false, $sWhere = false)
|
|
{
|
|
// Check if transaction active
|
|
if ($this->bTransactionActive) {
|
|
$this->addTransactionSql($query);
|
|
return true;
|
|
}
|
|
|
|
$this->iLogId = 0;
|
|
$this->nbQueries++;
|
|
|
|
// Log query
|
|
if (!$this->bDBLogSkip && $this->oDBLog) {
|
|
$this->iLogId = $this->oDBLog->log($query, $sTable, $sWhere);
|
|
}
|
|
|
|
// Exec query
|
|
$iStart = microtime(true);
|
|
$this->lastResult = $this->mysqli->query($query) or $this->debugAndDie($query);
|
|
$iEnd = microtime(true);
|
|
|
|
|
|
// Update exec time
|
|
if (!$this->bDBLogSkip && $this->oDBLog && $this->iLogId)
|
|
$this->oDBLog->updRecordData($this->iLogId, array('s' => ($iEnd - $iStart)));
|
|
$this->bDBLogSkip = false;
|
|
|
|
// Save history in debug mode
|
|
if ($this->debug) {
|
|
$this->history[] = array(
|
|
'query' => $query,
|
|
'time' => ($iEnd - $iStart) . 's'
|
|
);
|
|
$this->oConsole->addOutputLine(array(
|
|
'SQL', "Exec time: " . ($iEnd - $iStart) . "s", "<b class='sql'>{$query}</b>"
|
|
), 'sql');
|
|
}
|
|
|
|
return $this->lastResult;
|
|
}
|
|
|
|
/**
|
|
* Convenient method for clearing special characters from passed variables
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param mixed $data - data
|
|
* @param bool $pHtml - preserve html structure
|
|
* @return mixed $data - clean data
|
|
*/
|
|
public function prepData($data, $pHtml = false){
|
|
|
|
if(is_array($data) && !!$data){
|
|
foreach($data as &$v)
|
|
$v = $this->prepData($v, $pHtml);
|
|
unset($v);
|
|
}else if(!!$data){
|
|
if($pHtml)
|
|
$data = $this->mysqli->escape_string(trim($data));
|
|
else
|
|
$data = $this->mysqli->escape_string(htmlspecialchars(trim($data), ENT_QUOTES, 'UTF-8'));
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convenient constants for query table field genaration
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @category CMS
|
|
* @version 1.1
|
|
*/
|
|
const TF_TITLE = 'title';
|
|
const TF_CTITLE = 'custom_title';
|
|
const TF_SORT = 'sort';
|
|
const TF_SEARCH = 'search';
|
|
const TF_TYPE = 'type';
|
|
const TF_T_DATE = 'date';
|
|
const TF_T_DROPBOX = 'dropBox';
|
|
const TF_T_AJAX_DROPBOX = 'ajaxDropBox';
|
|
const TF_T_SELECT = 'select';
|
|
const TF_T_INPUT = 'input';
|
|
const TF_DROPBOX_DATA = 'data';
|
|
const TF_CLASS = 'class';
|
|
const TF_DB_FIELD = 'db_field';
|
|
const TF_DB_UPDATE_FIELD = 'field';
|
|
const TF_BUTTONS = 'btnset';
|
|
const TF_DEFAULT_VALUE = 'default';
|
|
|
|
const TF_S_TYPE = 'searchType'; // SEARCH ARRAY TYPE
|
|
const TF_ST_BETWEEN = 1;
|
|
const TF_ST_FROM_TILL = 2;
|
|
const TF_S_LINK_FIELD = 'field'; // SEARCH ARRAY FIELD
|
|
const TF_S_OPTIONS = 'options'; // SEARCH ARRAY OPTIONS
|
|
const TF_SO_TILL = 1;
|
|
const TF_SO_FROM = 2;
|
|
|
|
/**
|
|
* Convenient method for building search field query
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @category CMS
|
|
* @param array $data - search value data array
|
|
* @param array $fields - all available search fields
|
|
* @param bool $startWithAND - start statement with AND
|
|
* @param bool $pHtml - preserve html structure
|
|
* @return string query
|
|
* @version 1.1
|
|
*/
|
|
public function genSearchFieldQuery(&$data, &$fields, $startWithAND = true, $pHtml = false){
|
|
|
|
if(count($data) && count($fields)){
|
|
|
|
$sql = "";
|
|
|
|
// Construct query
|
|
foreach($data as $k => $v){
|
|
if($v !=='' && isset($fields[$k])){
|
|
$v = $this->prepData($v, $pHtml);
|
|
switch ($fields[$k]['type']) {
|
|
case self::TF_T_INPUT :
|
|
if(!empty($fields[$k][self::TF_DB_FIELD])){
|
|
if(!is_array($fields[$k][self::TF_DB_FIELD])){
|
|
$fields[$k][self::TF_DB_FIELD] = array('0' => $fields[$k][self::TF_DB_FIELD]);
|
|
}
|
|
|
|
$for = "";
|
|
$flink = (!empty($fields[$k]['db_link']) ? $fields[$k]['db_link'] : 'AND');
|
|
$operation = (!empty($fields[$k]['operation']) ? $fields[$k]['operation'] : '');
|
|
|
|
// Search whole words
|
|
$bWholeWord = false;
|
|
$vTypes = array('\'', '"');
|
|
if(in_array(substr($v, 0, 1), $vTypes) && in_array(substr($v, -1), $vTypes)){
|
|
$bWholeWord = true;
|
|
$v = substr($v, 1, strlen($v)-2);
|
|
}
|
|
|
|
foreach($fields[$k][self::TF_DB_FIELD] as $db_f){
|
|
if($operation){
|
|
$for .= "{$flink} {$db_f} {$operation} '{$v}' \n";
|
|
}elseif($bWholeWord){
|
|
$for .= "{$flink} " . $db_f . " LIKE '{$v}' \n";
|
|
}else{
|
|
$for .= "{$flink} {$db_f} LIKE '%{$v}%' \n";
|
|
}
|
|
}
|
|
|
|
$sql .= "AND (" . substr($for, strlen($flink)) . ")";
|
|
}
|
|
break;
|
|
|
|
case self::TF_T_SELECT:
|
|
if(!empty($fields[$k]['data'][$v][self::TF_DB_FIELD])){
|
|
$sql .= "AND {$fields[$k]['data'][$v][self::TF_DB_FIELD]} = '{$v}' \n";
|
|
}else if(!empty($fields[$k][self::TF_DB_FIELD])){
|
|
$sql .= "AND {$fields[$k][self::TF_DB_FIELD]} LIKE '{$v}' \n";
|
|
}
|
|
break;
|
|
|
|
case self::TF_T_DROPBOX:
|
|
if(!empty($fields[$k]['data'][$v])){
|
|
$sql .= "AND {$fields[$k][self::TF_DB_FIELD]} = '{$v}' \n";
|
|
}
|
|
break;
|
|
|
|
case self::TF_T_AJAX_DROPBOX:
|
|
if(!is_array($fields[$k][self::TF_DB_FIELD]))
|
|
$fields[$k][self::TF_DB_FIELD] = array('0' => $fields[$k][self::TF_DB_FIELD]);
|
|
|
|
$for = '';
|
|
$flink = (!empty($fields[$k]['db_link']) ? $fields[$k]['db_link'] : 'AND');
|
|
$likePattern = (!empty($fields[$k]['db_like_pattern']) ? $fields[$k]['db_like_pattern'] : ''); // LIKE '%__VALUE__%' pattern is --> %__VALUE__%
|
|
$operation = (!empty($fields[$k]['operation']) ? $fields[$k]['operation'] : '');
|
|
|
|
foreach($fields[$k][self::TF_DB_FIELD] as $db_f){
|
|
if($operation){
|
|
$for .= "{$flink} {$db_f} {$operation} '{$v}' \n";
|
|
}else{
|
|
$for .= "{$flink} {$db_f} LIKE " . (strlen($likePattern) ? "'" . str_replace('__VALUE__',$v, $likePattern) . "'" : "'%{$v}%'") . " \n";
|
|
}
|
|
}
|
|
|
|
$sql .= "AND (" . substr($for, strlen($flink)) . ")";
|
|
break;
|
|
|
|
case self::TF_T_DATE:
|
|
$s = $fields[$k];
|
|
if(!!$s[self::TF_SEARCH] && is_array($s[self::TF_SEARCH]))
|
|
$s = &$s[self::TF_SEARCH];
|
|
|
|
// Check if db fields exists & data fields exists
|
|
if(!!$s && !empty($s[self::TF_DB_FIELD]) && !empty($s[self::TF_S_LINK_FIELD]) && isset($data[$s[self::TF_S_LINK_FIELD]])){
|
|
|
|
$sLinkFieldKey = $s[self::TF_S_LINK_FIELD];
|
|
$sLinkFieldValue = $data[$sLinkFieldKey];
|
|
|
|
switch($s[self::TF_S_TYPE]){
|
|
case self::TF_ST_BETWEEN:
|
|
|
|
$d1 = strtotime(str_replace("/", "-", $v));
|
|
$d2 = strtotime(str_replace("/", "-", $sLinkFieldValue));
|
|
|
|
if($d1 > $d2){
|
|
$t = $d2;
|
|
$d2 = $d1;
|
|
$d1 = $t;
|
|
}
|
|
// Set oldest date closest border
|
|
$d2 = strtotime(date("d-m-Y", $d2) . " 23:59:59");
|
|
|
|
//pr(date('d/m/Y H:i:s', $d1),date('d/m/Y h:i:s', $d2));
|
|
unset($data[$sLinkFieldKey]); // Remove linked 2nd field
|
|
$sql .= "AND ({$s[self::TF_DB_FIELD]} BETWEEN {$d1} AND {$d2}) \n";
|
|
break;
|
|
|
|
case self::TF_ST_FROM_TILL:
|
|
|
|
if(isset($s[self::TF_S_OPTIONS]) && $s[self::TF_S_OPTIONS] == self::TF_SO_FROM){
|
|
$d1 = strtotime(str_replace("/", "-", $v));
|
|
$d2 = strtotime(str_replace("/", "-", $sLinkFieldValue));
|
|
}else{
|
|
$d1 = strtotime(str_replace("/", "-", $sLinkFieldValue));
|
|
$d2 = strtotime(str_replace("/", "-", $v));
|
|
}
|
|
|
|
if($d1 > 0 && $d2 > 0){
|
|
if($d1 > $d2){
|
|
$t = $d2;
|
|
$d2 = $d1;
|
|
$d1 = $t;
|
|
}
|
|
}
|
|
|
|
// Set oldest date closest border
|
|
if($d2 > 0) $d2 = strtotime(date("d-m-Y", $d2) . " 23:59:59");
|
|
|
|
//pr(date('d/m/Y H:i:s', $d1) . "<-- \n",date('d/m/Y h:i:s', $d2) . "<-- \n");
|
|
unset($data[$sLinkFieldKey]); // Remove linked 2nd field
|
|
|
|
if($d1 > 0 && $d2 > 0)
|
|
$sql .= "AND ({$s[self::TF_DB_FIELD]} >= {$d1} OR {$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} >= {$d1}) AND ({$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} <= {$d2} OR {$s[self::TF_DB_FIELD]} <= {$d2})";
|
|
elseif($d1 > 0 && $s[self::TF_S_OPTIONS] == self::TF_SO_FROM)
|
|
$sql .= "AND ({$s[self::TF_DB_FIELD]} >= {$d1} OR {$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} >= {$d1}) ";
|
|
elseif($d2 > 0 && $s[self::TF_S_OPTIONS] == self::TF_SO_TILL)
|
|
$sql .= "AND ({$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} <= {$d2} OR {$s[self::TF_DB_FIELD]} <= {$d2})";
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return $startWithAND ? ' ' . $sql : substr($sql, 3);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for building sort by field query
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @category CMS
|
|
* @param string $sortBy - field key sort by
|
|
* @param bool $sortWay - field sort order true / false
|
|
* @param array $fieldData - fields available in table
|
|
* @return string query
|
|
* @version 1.1
|
|
*/
|
|
public function genOrderByQuery($sortBy, $sortWay, $fieldData){
|
|
|
|
if($sortBy && isset($fieldData[$sortBy][self::TF_DB_FIELD]) && !!$fieldData[$sortBy][self::TF_DB_FIELD]){
|
|
|
|
$sql = "";
|
|
|
|
$sortWay = ($sortWay ? ' ASC ' : ' DESC ');
|
|
if(!is_array($fieldData[$sortBy][self::TF_DB_FIELD]))
|
|
$fieldData[$sortBy][self::TF_DB_FIELD] = array($fieldData[$sortBy][self::TF_DB_FIELD]);
|
|
|
|
foreach($fieldData[$sortBy][self::TF_DB_FIELD] as $dbField){
|
|
$sql .= ", {$dbField} {$sortWay}";
|
|
}
|
|
|
|
|
|
return substr($sql, 1);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching one
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The ressource returned by query()
|
|
* @return bool true / false or array with data
|
|
*/
|
|
public function getOne($vPrepCfg = false, $result = NULL){
|
|
if ($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if($result && $result->num_rows){
|
|
$row = $result->fetch_assoc();
|
|
$field = array_shift($row);
|
|
unset($row);
|
|
}else{
|
|
$field = false;
|
|
}
|
|
|
|
$this->free();
|
|
return $this->prepRespData($field, $vPrepCfg);
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching row
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The resource returned by query()
|
|
* @return mixed true / false / array with data
|
|
*/
|
|
public function getRow($vPrepCfg = false, $result = NULL){
|
|
if($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if($result == NULL || $result->num_rows < 1){
|
|
return NULL;
|
|
}else{
|
|
$row = $result->fetch_assoc();
|
|
$result->free();
|
|
|
|
return $this->prepRespData($row, $vPrepCfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching an array
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The resource returned by query()
|
|
* @return bool|array true / false or array with data
|
|
*/
|
|
public function getArray($vPrepCfg = false, $result = NULL){
|
|
if($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if($result == NULL || $result->num_rows < 1){
|
|
return NULL;
|
|
}else{
|
|
$arr = array();
|
|
while($row = $result->fetch_assoc())
|
|
$arr[] = $row;
|
|
|
|
unset($row);
|
|
$this->free($result);
|
|
|
|
return $this->prepRespData($arr, $vPrepCfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching an field based array
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $field - field by which to group
|
|
* @param string|bool $subArrField - sub-field by which to group
|
|
* @param bool $simpleRewrite - simply rewrite each similar id
|
|
* @param string|bool $fieldKey - resource field to group by
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The resource returned by query()
|
|
* @return bool|array true / false or array with data
|
|
*/
|
|
public function getFieldBasedArray($field, $subArrField = false, $simpleRewrite = true, $fieldKey = false, $vPrepCfg = false, $result = NULL){
|
|
if ($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if ($result == NULL || $result->num_rows < 1)
|
|
return NULL;
|
|
else {
|
|
$arr = array();
|
|
while ($row = $result->fetch_assoc()) {
|
|
if(!$subArrField){
|
|
if($simpleRewrite){
|
|
$arr[$row[$field]] = ($fieldKey ? @$row[$fieldKey] : $row);
|
|
}elseif($fieldKey){
|
|
$arr[$row[$field]][] = @$row[$fieldKey];
|
|
}else{
|
|
$arr[$row[$field]][] = $row;
|
|
}
|
|
}else{
|
|
if($simpleRewrite){
|
|
$arr[$row[$field]][$row[$subArrField]] = ($fieldKey ? @$row[$fieldKey] : $row);
|
|
}elseif($fieldKey){
|
|
$arr[$row[$field]][$row[$subArrField]][] = @$row[$fieldKey];
|
|
}else{
|
|
$arr[$row[$field]][$row[$subArrField]][] = $row;
|
|
}
|
|
}
|
|
}
|
|
|
|
unset($row);
|
|
$this->free($result);
|
|
return $this->prepRespData($arr, $vPrepCfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching an field based array NEW
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $key - field by which to group
|
|
* @param string|bool $subKey - sub-field by which to group
|
|
* @param array|string|bool $fields - resource field to select
|
|
* @param bool $simpleRewrite - simply rewrite each similar id
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The resource returned by query()
|
|
* @return bool|array true / false or array with data
|
|
*/
|
|
public function getFieldBasedArrayFields($key, $subKey = false, $fields = false, $simpleRewrite = true, $vPrepCfg = false, $result = NULL){
|
|
if ($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if ($result == NULL || $result->num_rows < 1)
|
|
return NULL;
|
|
else {
|
|
$arr = array();
|
|
while ($row = $result->fetch_assoc()) {
|
|
|
|
if(!$subKey){
|
|
if($simpleRewrite){
|
|
if($simpleRewrite === true)
|
|
$arr[$row[$key]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
|
|
else
|
|
$arr[$row[$key]][$row[$simpleRewrite]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
|
|
}elseif(!!$fields && is_array($fields)){
|
|
$arr[$row[$key]][] = array_intersect_key($row, array_flip($fields));
|
|
}else{
|
|
$arr[$row[$key]][] = (isset($row[$fields]) ? $row[$fields] : $row);
|
|
}
|
|
}else{
|
|
if($simpleRewrite){
|
|
if($simpleRewrite === true)
|
|
$arr[$row[$key]][$row[$subKey]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
|
|
else
|
|
$arr[$row[$key]][$row[$subKey]][$row[$simpleRewrite]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
|
|
}elseif(!!$fields && is_array($fields)){
|
|
$arr[$row[$key]][$row[$subKey]][] = array_intersect_key($row, array_flip($fields));
|
|
}else{
|
|
$arr[$row[$key]][$row[$subKey]][] = (isset($row[$fields]) ? $row[$fields] : $row);
|
|
}
|
|
}
|
|
}
|
|
|
|
unset($row);
|
|
$this->free($result);
|
|
return $this->prepRespData($arr, $vPrepCfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching an field based array advanced & optimized
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string|array $keys - field/s by which to group
|
|
* @param array|string|bool $fields - resource field to select
|
|
* @param bool $simpleRewrite - simply rewrite each similar id
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The resource returned by query()
|
|
* @return bool|array true / false or array with data
|
|
*/
|
|
public function getFieldBasedArrayFieldsAdv($keys, $fields = false, $simpleRewrite = true, $vPrepCfg = false, $result = NULL){
|
|
|
|
$bArray = false;
|
|
$keys = (is_array($keys) ? $keys : array($keys));
|
|
if(!!$fields && is_array($fields)){
|
|
$bArray = true;
|
|
$flipArray = array_flip($fields);
|
|
}
|
|
|
|
if ($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if ($result == NULL || $result->num_rows < 1)
|
|
return NULL;
|
|
else {
|
|
$arr = array();
|
|
while ($row = $result->fetch_assoc()){
|
|
$ref = &$arr;
|
|
foreach($keys as $key){
|
|
if(!isset($ref[$row[$key]]))
|
|
$ref[$row[$key]] = array();
|
|
$ref = &$ref[$row[$key]];
|
|
}
|
|
if($simpleRewrite){
|
|
$ref = ($bArray ? array_intersect_key($row, $flipArray) : ($fields ? @$row[$fields] : $row));
|
|
}elseif($bArray){
|
|
$ref[] = array_intersect_key($row, $flipArray);
|
|
}else{
|
|
$ref[] = ($fields ? @$row[$fields] : $row);
|
|
}
|
|
}
|
|
|
|
unset($row);
|
|
$this->free($result);
|
|
return $this->prepRespData($arr, $vPrepCfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for manipulating globally data
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param mixed $vData - data to prepare
|
|
* @param mixed $vPrepData - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @return mixed manipulated data
|
|
*/
|
|
const PREP_DATA_ENCODE = 'bPrepData_encode';
|
|
const PREP_DATA_DECODE = 'bPrepData_decode';
|
|
const PREP_DATA_DECODE_ORIGINAL = 'bPrepData_decode_original';
|
|
public function prepRespData($vData = array(), $vPrepData){
|
|
|
|
if($vPrepData){
|
|
if($vPrepData === true)
|
|
$vPrepData = array('type' => self::PREP_DATA_ENCODE);
|
|
if(is_string($vPrepData))
|
|
$vPrepData = array('type' => $vPrepData);
|
|
|
|
// Data manipulations
|
|
if(!!$vData && !!$vPrepData){
|
|
switch($vPrepData['type']){
|
|
case self::PREP_DATA_ENCODE;
|
|
$vData = $this->prepData($vData);
|
|
break;
|
|
case self::PREP_DATA_DECODE;
|
|
$vData = prepForDisplayHtml($vData);
|
|
break;
|
|
case self::PREP_DATA_DECODE_ORIGINAL;
|
|
$vData = prepForOriginalHtml($vData);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $vData;
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching key => value field based array.
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $keyF - result array field key
|
|
* @param string $valF - result array filed value key
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The resource returned by query()
|
|
* @return array - containing select data
|
|
*/
|
|
public function getKeyValBasedArray($keyF, $valF, $vPrepCfg = false, $result = NULL){
|
|
if ($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if ($result == NULL || $result->num_rows < 1)
|
|
return NULL;
|
|
else {
|
|
$arr = array();
|
|
while ($row = $result->fetch_assoc()) {
|
|
$arr[@$row[$keyF]] = @$row[$valF];
|
|
}
|
|
|
|
unset($row);
|
|
$this->free($result);
|
|
return $this->prepRespData($arr, $vPrepCfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for fetching data & return grouped.
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $gr_field - group field
|
|
* @param string $empty_key - empty other gr field
|
|
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
|
|
* @param instance $result - The resource returned by query()
|
|
* @return bool true / false or array with data
|
|
*/
|
|
public function getGroupArray($gr_field, $empty_key = 'Others', $vPrepCfg = false, $result = NULL){
|
|
if ($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
if ($result == NULL || $result->num_rows < 1)
|
|
return NULL;
|
|
else {
|
|
$arr = array();
|
|
$curr_field = '';
|
|
|
|
while ($row = $result->fetch_assoc()) {
|
|
|
|
if($curr_field != $row[$gr_field]){
|
|
$curr_field = $row[$gr_field];
|
|
}
|
|
|
|
if(!$curr_field){
|
|
$curr_field = $empty_key;
|
|
}
|
|
$arr[$curr_field][] = $row;
|
|
}
|
|
|
|
unset($row);
|
|
$this->free($result);
|
|
return $this->prepRespData($arr, $vPrepCfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient method for getting last select found row count
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param bool $debug - indicates debug mode
|
|
* @return cleared object value
|
|
*/
|
|
public function getSelectedRecordsCount($debug = false){
|
|
|
|
$this->bDBLogSkip = true;
|
|
$this->query("SELECT FOUND_ROWS()", $debug);
|
|
return $this->getOne();
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient method for setting logger class
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param mixed $loggerObject - logger class reference
|
|
* @returns void
|
|
*/
|
|
public function setLogger(&$loggerObject){
|
|
|
|
if(is_callable(array($loggerObject, 'log')))
|
|
$this->oDBLog = $loggerObject;
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient method for initializing logger class
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param int $iUserId - user id to link to log
|
|
* @returns void
|
|
*/
|
|
public function initLogger($iUserId = 0){
|
|
|
|
if($iUserId) $this->oDBLog = new cDbLog($iUserId);
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient method for mysqli_free_result()
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param instance $result - The resource returned by query()
|
|
* @return bool true / false or array with data
|
|
*/
|
|
public function free($result = NULL){
|
|
if ($result == NULL)
|
|
$result = $this->lastResult;
|
|
|
|
return ($result && is_callable(array($result, 'free'), true) ? $result->free() : false);
|
|
}
|
|
private function freeMulti($bBuffer = false){
|
|
// flush multi_queries
|
|
if(!$bBuffer){
|
|
while ($this->mysqli->more_results() && $this->mysqli->next_result()){
|
|
if (!$this->mysqli->more_results()) break;
|
|
}
|
|
}else{
|
|
do{
|
|
/* store first result set */
|
|
if($result = $this->mysqli->store_result()) {
|
|
/* while($row = $result->fetch_row()) {
|
|
// printf("%s\n", $row[0]);
|
|
}*/
|
|
$result->free_result();
|
|
}
|
|
/* print divider */
|
|
//if($this->mysqli->more_results()) {
|
|
// printf("-----------------\n");
|
|
// }
|
|
}while($this->mysqli->next_result());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convenient method for getting id of the very last inserted row.
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @return int $rowId - the id of the very last inserted row (in any table).
|
|
*/
|
|
function lastInsertedId(){
|
|
|
|
return $this->mysqli->insert_id;
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient method for getting affected row count
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @return int $rowId - the id of the very last inserted row (in any table).
|
|
*/
|
|
function affectedRowCount(){
|
|
|
|
return $this->mysqli->affected_rows;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function to get the number of queries executed from the begin of this object
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @return int $count - The number of queries executed
|
|
*/
|
|
function getQueriesCount(){
|
|
|
|
return $this->nbQueries;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function to get current time.
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @return int $time - current time in seconds with microseconds (in float format).
|
|
*/
|
|
function getMicroTime(){
|
|
|
|
list($msec, $sec) = explode(' ', microtime());
|
|
return floor($sec / 1000) + $msec;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function to get execution time since beginning of object creation.
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @return int $time - execution time in seconds.
|
|
*/
|
|
function getExecTime(){
|
|
return round(($this->getMicroTime() - $this->mtStart) * 1000) / 1000;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************************************************
|
|
* DEBUG FUNCTIONS
|
|
*
|
|
* Internal function to debug when MySQL encountered an error
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $query The SQL query to echo before dying.
|
|
*/
|
|
private function debugAndDie($query){
|
|
if($this->debug){
|
|
$this->debugQuery($query, "Error");
|
|
if(POST_REQ){
|
|
die("\n\n" . $this->mysqli->error);
|
|
}else{
|
|
die("<p style='margin: 14px;'>" . $this->mysqli->error . "</p></div>");
|
|
}
|
|
}
|
|
}
|
|
private function debugQuery($query, $reason = "Debug"){
|
|
$color = ($reason == "Error" ? "red" : "orange");
|
|
if(POST_REQ){
|
|
echo "$reason\n\n" .
|
|
"$query";
|
|
}else{
|
|
echo "<div style='border: solid $color 1px; margin: 2px;font-family: arial;line-height: 22px;'>" .
|
|
"<p style='margin: 0 0 2px 0; padding: 0;background-color: #DDDDFF;text-shadow: -1px 1px 0 rgba(255, 255, 255, 0.39);color: #1A1A1A;'>" .
|
|
"<strong style='padding: 0 8px; background-color: {$color}; color: white;display: inline-block;letter-spacing:2px;'>$reason:</strong> " .
|
|
"<span style='font-family: monospace;display: block;margin: 0 100px;padding-bottom: 18px;'>" . ($this->getFormattedSQL($query)) . "</span></p>";
|
|
}
|
|
}
|
|
private function getFormattedSQL($sql_raw){
|
|
if( empty($sql_raw) || !is_string($sql_raw) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
$sql_reserved_all = array (
|
|
'ACCESSIBLE', 'ACTION', 'ADD', 'AFTER', 'AGAINST', 'AGGREGATE', 'ALGORITHM', 'ALL', 'ALTER', 'ANALYSE', 'ANALYZE', 'AND', 'AS', 'ASC',
|
|
'AUTOCOMMIT', 'AUTO_INCREMENT', 'AVG_ROW_LENGTH', 'BACKUP', 'BEGIN', 'BETWEEN', 'BINLOG', 'BOTH', 'BY', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED',
|
|
'CHARSET', 'CHECK', 'CHECKSUM', 'COLLATE', 'COLLATION', 'COLUMN', 'COLUMNS', 'COMMENT', 'COMMIT', 'COMMITTED', 'COMPRESSED', 'CONCURRENT',
|
|
'CONSTRAINT', 'CONTAINS', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATABASES', 'DAY', 'DAY_HOUR', 'DAY_MINUTE',
|
|
'DAY_SECOND', 'DEFINER', 'DELAYED', 'DELAY_KEY_WRITE', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV',
|
|
'DO', 'DROP', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', 'ELSE', 'ENCLOSED', 'END', 'ENGINE', 'ENGINES', 'ESCAPE', 'ESCAPED', 'EVENTS', 'EXECUTE',
|
|
'EXISTS', 'EXPLAIN', 'EXTENDED', 'FAST', 'FIELDS', 'FILE', 'FIRST', 'FIXED', 'FLUSH', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULL', 'FULLTEXT',
|
|
'FUNCTION', 'GEMINI', 'GEMINI_SPIN_RETRIES', 'GLOBAL', 'GRANT', 'GRANTS', 'GROUP', 'HAVING', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', 'HOUR', 'HOUR_MINUTE',
|
|
'HOUR_SECOND', 'IDENTIFIED', 'IF', 'IGNORE', 'IN', 'INDEX', 'INDEXES', 'INFILE', 'INNER', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', 'INTERVAL',
|
|
'INTO', 'INVOKER', 'IS', 'ISOLATION', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', 'LEFT', 'LEVEL', 'LIKE', 'LIMIT', 'LINEAR',
|
|
'LINES', 'LOAD', 'LOCAL', 'LOCK', 'LOCKS', 'LOGS', 'LOW_PRIORITY', 'MARIA', 'MASTER', 'MASTER_CONNECT_RETRY', 'MASTER_HOST', 'MASTER_LOG_FILE',
|
|
'MASTER_LOG_POS', 'MASTER_PASSWORD', 'MASTER_PORT', 'MASTER_USER', 'MATCH', 'MAX_CONNECTIONS_PER_HOUR', 'MAX_QUERIES_PER_HOUR',
|
|
'MAX_ROWS', 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 'MEDIUM', 'MERGE', 'MINUTE', 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', 'MODIFY',
|
|
'MONTH', 'MRG_MYISAM', 'MYISAM', 'NAMES', 'NATURAL', 'NOT', 'NULL', 'OFFSET', 'ON', 'OPEN', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR',
|
|
'ORDER', 'OUTER', 'OUTFILE', 'PACK_KEYS', 'PAGE', 'PARTIAL', 'PARTITION', 'PARTITIONS', 'PASSWORD', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE',
|
|
'PROCESS', 'PROCESSLIST', 'PURGE', 'QUICK', 'RAID0', 'RAID_CHUNKS', 'RAID_CHUNKSIZE', 'RAID_TYPE', 'RANGE', 'READ', 'READ_ONLY',
|
|
'READ_WRITE', 'REFERENCES', 'REGEXP', 'RELOAD', 'RENAME', 'REPAIR', 'REPEATABLE', 'REPLACE', 'REPLICATION', 'RESET', 'RESTORE', 'RESTRICT',
|
|
'RETURN', 'RETURNS', 'REVOKE', 'RIGHT', 'RLIKE', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'SECOND', 'SECURITY', 'SELECT', 'SEPARATOR',
|
|
'SERIALIZABLE', 'SESSION', 'SET', 'SHARE', 'SHOW', 'SHUTDOWN', 'SLAVE', 'SONAME', 'SOUNDS', 'SQL', 'SQL_AUTO_IS_NULL', 'SQL_BIG_RESULT',
|
|
'SQL_BIG_SELECTS', 'SQL_BIG_TABLES', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_CALC_FOUND_ROWS', 'SQL_LOG_BIN', 'SQL_LOG_OFF',
|
|
'SQL_LOG_UPDATE', 'SQL_LOW_PRIORITY_UPDATES', 'SQL_MAX_JOIN_SIZE', 'SQL_NO_CACHE', 'SQL_QUOTE_SHOW_CREATE', 'SQL_SAFE_UPDATES',
|
|
'SQL_SELECT_LIMIT', 'SQL_SLAVE_SKIP_COUNTER', 'SQL_SMALL_RESULT', 'SQL_WARNINGS', 'START', 'STARTING', 'STATUS', 'STOP', 'STORAGE',
|
|
'STRAIGHT_JOIN', 'STRING', 'STRIPED', 'SUPER', 'TABLE', 'TABLES', 'TEMPORARY', 'TERMINATED', 'THEN', 'TO', 'TRAILING', 'TRANSACTIONAL',
|
|
'TRUNCATE', 'TYPE', 'TYPES', 'UNCOMMITTED', 'UNION', 'UNIQUE', 'UNLOCK', 'UPDATE', 'USAGE', 'USE', 'USING', 'VALUES', 'VARIABLES',
|
|
'VIEW', 'WHEN', 'WHERE', 'WITH', 'WORK', 'WRITE', 'XOR', 'YEAR_MONTH'
|
|
);
|
|
$sql_break_before = array('AND');
|
|
$sql_break_after = array('SELECT', 'ON', 'WHERE');
|
|
$sql_set_in_bold = array('ON', 'AS', 'AND');
|
|
$sql_skip_reserved_words = array('AS', 'ON', 'USING', 'AND');
|
|
$sql_special_reserved_words = array('(', ')');
|
|
|
|
$sql_raw = str_replace("\n", " ", $sql_raw);
|
|
|
|
$sql_formatted = "";
|
|
|
|
$prev_word = "";
|
|
$word = "";
|
|
$tab = ' ';
|
|
|
|
for( $i=0, $j = strlen($sql_raw); $i < $j; $i++ )
|
|
{
|
|
$word .= $sql_raw[$i];
|
|
|
|
$word_trimmed = trim($word);
|
|
|
|
if($sql_raw[$i] == " " || in_array($sql_raw[$i], $sql_special_reserved_words))
|
|
{
|
|
$word_trimmed = trim($word);
|
|
|
|
$trimmed_special = false;
|
|
|
|
if( in_array($sql_raw[$i], $sql_special_reserved_words) )
|
|
{
|
|
$word_trimmed = substr($word_trimmed, 0, -1);
|
|
$trimmed_special = true;
|
|
}
|
|
|
|
$word_trimmed = strtoupper($word_trimmed);
|
|
|
|
if(in_array($word_trimmed, $sql_reserved_all) && !in_array($word_trimmed, $sql_skip_reserved_words)){
|
|
if(in_array($prev_word, $sql_reserved_all)){
|
|
$sql_formatted .= '<b>'.strtoupper(trim($word)).'</b>'.' ';
|
|
}else{
|
|
$sql_formatted .= '<br/> ';
|
|
$sql_formatted .= '<b>'.strtoupper(trim($word)).'</b>'.' ';
|
|
}
|
|
|
|
$prev_word = $word_trimmed;
|
|
$word = "";
|
|
}else{
|
|
if(trim($word)){
|
|
|
|
// Add line breaks for subfields
|
|
if(in_array($word_trimmed, $sql_break_before)){
|
|
$sql_formatted .= "<br/>{$tab}";
|
|
}
|
|
if(substr($prev_word, strlen($prev_word)-1, 1) == ',' || in_array($prev_word, $sql_break_after)){
|
|
$sql_formatted .= "<br/>{$tab}";
|
|
}
|
|
|
|
// Set words in bold
|
|
if(in_array($word_trimmed, $sql_set_in_bold)){
|
|
$sql_formatted .= '<b>' . trim($word).'</b> ';
|
|
}else{
|
|
$sql_formatted .= trim($word).' ';
|
|
}
|
|
|
|
$prev_word = $word_trimmed;
|
|
$word = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$sql_formatted .= trim($word);
|
|
|
|
return $sql_formatted;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************************************************
|
|
* FAST QUERY REQUEST FUNCTIONS
|
|
*
|
|
*
|
|
* Function to build query based on passed data
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array|bool $fields - fields to select
|
|
* @param array|bool $where - where clause
|
|
* @param array|bool $order - order clause
|
|
* @return bool true / false
|
|
*/
|
|
private function buildQuery($table, $fields = false, $where = false, $order = false){
|
|
|
|
if (is_array($fields)) {
|
|
$fields = implode(',', $fields);
|
|
} else {
|
|
$fields = "*";
|
|
}
|
|
|
|
$where = $this->buildWhereStatement($where);
|
|
|
|
if (is_array($order)) {
|
|
$d = '';
|
|
foreach($order as $k => $v){
|
|
$d .= ", " . $k . " " . $this->prepData($v) . " ";
|
|
}
|
|
|
|
$order = substr($d, 1);
|
|
} else {
|
|
$order = " 1 ";
|
|
}
|
|
|
|
return "
|
|
SELECT {$fields}
|
|
FROM {$table}
|
|
WHERE {$where}
|
|
ORDER BY {$order}";
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient function for building where statement for query
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param array|bool $where - where clause
|
|
* @return string - built query
|
|
*/
|
|
public function buildWhereStatement($where = false){
|
|
|
|
if (!!$where && is_array($where)) {
|
|
$d = '';
|
|
foreach($where as $k => $v){
|
|
if(is_array($v)){
|
|
if(!empty($v[self::OP])){
|
|
if(is_array($v[self::VAL]))
|
|
$d .= "AND `" . $k . "` {$v[self::OP]} ('" . implode("','", $this->prepData($v[self::VAL])) . "') ";
|
|
else
|
|
$d .= "AND `" . $k . "` {$v[self::OP]} '" . $this->prepData($v[self::VAL]) . "' ";
|
|
}else
|
|
$d .= "AND `" . $k . "` IN ('" . implode("','", $this->prepData($v)) . "') ";
|
|
}else{
|
|
$d .= "AND `" . $k . "` = '" . $this->prepData($v) . "' ";
|
|
}
|
|
}
|
|
|
|
$where = substr($d, 3);
|
|
} else {
|
|
$where = self::DEF_WHERE;
|
|
}
|
|
|
|
return $where;
|
|
}
|
|
|
|
/**
|
|
* Convenient function for loading row data from db connection by passing query data
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array|bool $fields - fields to select
|
|
* @param array|bool $where - where clause
|
|
* @param array|bool $order - order clause
|
|
* @return bool|array true / false
|
|
*/
|
|
public function _querySelectRow($table, $fields = false, $where = false, $order = false){
|
|
if(!!$table){
|
|
|
|
// Build query
|
|
$query = $this->buildQuery($table, $fields, $where, $order);
|
|
|
|
$this->query($query, $table);
|
|
return $this->getRow();
|
|
}else{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convenient function for loading array of data from db connection by passing query data
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array|bool $fields - fields to select
|
|
* @param array|bool $where - where clause
|
|
* @param array|bool $order - order clause
|
|
* @param bool $debug - debug parameter
|
|
* @param bool $return - return parameter
|
|
* @return bool|array true / false
|
|
*/
|
|
public function _querySelect($table, $fields = false, $where = false, $order = false, $debug = false, $return = true){
|
|
|
|
if(!!$table){
|
|
|
|
// Build query
|
|
$query = $this->buildQuery($table, $fields, $where, $order);
|
|
|
|
$this->query($query, $table);
|
|
if($return)
|
|
return $this->getArray();
|
|
}else{
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient function for loading field from db connection by passing query data
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array|bool $fields - fields to select
|
|
* @param array|bool $where - where clause
|
|
* @param array|bool $order - order clause
|
|
* @return bool true / false
|
|
*/
|
|
public function _querySelectOne($table, $fields = false, $where = false, $order = false){
|
|
|
|
if(!!$table){
|
|
|
|
// Build query
|
|
$query = $this->buildQuery($table, $fields, $where, $order);
|
|
|
|
$this->query($query, $table);
|
|
return $this->getOne();
|
|
}else{
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Convenient method for truncate table
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table to truncate
|
|
* @param bool $debug - indicates debug mode
|
|
* @return mixed - cleared object value
|
|
*/
|
|
public function _truncate($table ,$debug = false){
|
|
|
|
$query = "TRUNCATE TABLE {$table}";
|
|
|
|
$this->query($query, $table);
|
|
return $this->getOne();
|
|
|
|
}
|
|
|
|
/**
|
|
* Function to exec insert
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array $data - fields to insert with key to field structure
|
|
* @param bool $debug - indicates debug mode
|
|
* @param bool $pHTML - preserver html
|
|
* @return int - last inserted id on exec else false
|
|
*/
|
|
public function _queryInsert($table, $data = array(), $debug = false, $pHTML = false){
|
|
|
|
if (count($data)) {
|
|
|
|
$sFields = '';
|
|
$sValues = '';
|
|
|
|
// Escaping insert values
|
|
foreach ($data as $k => $v) {
|
|
$sFields .= ",`" . $k . "`";
|
|
|
|
$sValues .= ",'" . $this->prepData($v, $pHTML) . "'";
|
|
}
|
|
|
|
// Create query
|
|
$query = 'INSERT INTO ' . $table . '(' . substr($sFields,1) . ') VALUES (' . substr($sValues, 1) . ')';
|
|
|
|
// Exec query
|
|
if($this->execute($query, $table)) {
|
|
$vResult = $this->getMultiInsertRowIds();
|
|
return array_pop($vResult);
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function to exec insert with data array
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array $rowData - fields to insert with key to field structure
|
|
* @param bool $debug - indicates debug mode
|
|
* @param bool $pHTML - preserver html
|
|
* @return array|bool - array with ids
|
|
*/
|
|
public function _queryInsertArray($table, $rowData = array(), $debug = false, $pHTML = false){
|
|
|
|
if (count($rowData)) {
|
|
|
|
$sFields = '';
|
|
$sValues = '';
|
|
|
|
// Escaping insert values
|
|
$first_row = true;
|
|
foreach($rowData as $v) {
|
|
|
|
if(count($v)){
|
|
|
|
$sRow ='';
|
|
foreach($v as $kk => $vv) {
|
|
if($first_row){
|
|
$sFields .= ",`" . $kk . "`";
|
|
}
|
|
|
|
$sRow .= ",'" . $this->prepData($vv, $pHTML) . "'";
|
|
}
|
|
|
|
$sValues .= ',(' . substr($sRow, 1) . ')';
|
|
$first_row = false;
|
|
}
|
|
}
|
|
|
|
// Create query
|
|
$query = 'INSERT INTO ' . $table . '(' . substr($sFields,1) . ') VALUES ' . substr($sValues, 1) . ';';
|
|
|
|
// Exec query
|
|
if($this->execute($query, $table)){
|
|
return $this->getMultiInsertRowIds(count($rowData));
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
/**
|
|
* Function to get query || multi-query inserted ids
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param int $iInsertRowsCount - from insert row count
|
|
* @return array - inserted id on query's
|
|
*/
|
|
private function getMultiInsertRowIds($iInsertRowsCount = 0){
|
|
$vReturnD = array();
|
|
|
|
// Check upon inserted rows what to return
|
|
if($iInsertRowsCount == $this->mysqli->affected_rows){
|
|
//Generate id array
|
|
$i = 0;
|
|
while($i < $iInsertRowsCount) {
|
|
$vReturnD[] = $this->mysqli->insert_id + $i++;
|
|
}
|
|
}else{
|
|
$vReturnD[] = $this->mysqli->insert_id;
|
|
while($this->mysqli->more_results()){
|
|
$this->mysqli->next_result();
|
|
$vReturnD[] = $this->mysqli->insert_id;
|
|
}
|
|
}
|
|
|
|
// Update log affected ids
|
|
if(!$this->bDBLogSkip && $this->oDBLog && $this->iLogId){
|
|
$this->oDBLog->updRecordData($this->iLogId, array(
|
|
'json_data' => cJSON::encode(array('id' => $vReturnD))
|
|
));
|
|
}
|
|
|
|
return $vReturnD;
|
|
}
|
|
|
|
/**
|
|
* Function to exec delete
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array $where - fields to match before delete
|
|
* @param bool $debug - indicates debug mode
|
|
* @return bool - last inserted id on exec else false
|
|
*/
|
|
public function _queryDelete($table, $where = array(), $debug = false): bool
|
|
{
|
|
if (count($where)) {
|
|
|
|
// Create where clause
|
|
if (is_array($where) && count($where)) {
|
|
$d = '';
|
|
foreach($where as $k => $v){
|
|
if(is_array($v)){
|
|
if(!empty($v[self::OP]))
|
|
$d .= "AND `" . $k . "` {$v[self::OP]} '" . $this->prepData($v[self::VAL]) . "' ";
|
|
else
|
|
$d .= "AND `" . $k . "` IN ('" . implode("','", $this->prepData($v)) . "') ";
|
|
}else
|
|
$d .= "AND `" . $k . "` = '" . $this->prepData($v) . "' ";
|
|
}
|
|
|
|
$sWhere = substr($d, 3);
|
|
|
|
// Create query
|
|
$query = 'DELETE FROM ' . $table . ' WHERE ' . $sWhere;
|
|
|
|
if($this->execute($query, $table, $sWhere)){
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function to exec update
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array $data - fields to insert with key to field structure
|
|
* @param array|bool $where - fields to match the update
|
|
* @param bool $pHTML - indicates to preserve HTML
|
|
* @param bool $debug - indicates debug mode
|
|
* @return bool - last inserted id on exec else false
|
|
*/
|
|
public function _queryUpdate($table, $data = array(), $where = false, $pHTML = false, $debug = false): bool
|
|
{
|
|
$array = array();
|
|
|
|
if (count($data)) {
|
|
|
|
$sFields = '';
|
|
$sValues = '';
|
|
|
|
// Escaping update values
|
|
foreach ($data as $k => $v)
|
|
$sFields .= ",`" . $k . "` = '" . $this->prepData($v, $pHTML) . "'";
|
|
|
|
|
|
// Create where clause
|
|
if (is_array($where)){
|
|
$d = '';
|
|
foreach($where as $k => $v){
|
|
if(is_array($v) && count($v)){
|
|
if(!empty($v[self::OP]))
|
|
$d .= "AND `" . $k . "` {$v[self::OP]} '" . $this->prepData($v[self::VAL], $pHTML) . "' ";
|
|
else
|
|
$d .= "AND `" . $k . "` IN ('" . implode("','", $this->prepData($v, $pHTML)) . "')";
|
|
}else{
|
|
$d .= "AND `" . $k . "` = '" . $this->prepData($v, $pHTML) . "'";
|
|
}
|
|
}
|
|
|
|
$sWhere = substr($d, 3);
|
|
} else {
|
|
$sWhere = self::DEF_WHERE;
|
|
}
|
|
|
|
// Create query
|
|
$query = 'UPDATE ' . $table . ' SET ' . substr($sFields,1) . ' WHERE ' . $sWhere;
|
|
|
|
if($this->execute($query, $table, $sWhere)){
|
|
return true;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function to exec update multi with case
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $table - table name
|
|
* @param array $data - fields to insert with key to field structure
|
|
* @param string $sKey - main key to look in $data array
|
|
* @param array $where - additional where condition
|
|
* @param boolean $pHTML - indicates to preserve HTML
|
|
* @return boolean - true if query executed else false;
|
|
*/
|
|
public function _queryUpdateMulti($table, $data = array(), $sKey, $where = array(), $pHTML = false){
|
|
|
|
$bIsString = false;
|
|
if (count($data) && $sKey) {
|
|
$sKey = $this->prepData($sKey, $pHTML);
|
|
$data = $this->prepData($data, $pHTML);
|
|
$where = $this->prepData($where, $pHTML);
|
|
|
|
$keys = array($sKey => 1) + (!!$where ? $where : array());
|
|
|
|
$fields = array();
|
|
$ids = array();
|
|
foreach($data as $v){
|
|
$temp = array_diff_key($v, $keys);
|
|
|
|
// gather all ids;
|
|
$ids[] = $v[$sKey];
|
|
if(!is_numeric($v[$sKey]))
|
|
$bIsString = true;
|
|
if(empty($fields)){
|
|
$fields = array_diff_key($temp, array());
|
|
foreach($fields as &$vv)
|
|
$vv = " WHEN '{$v[$sKey]}' THEN '{$vv}' ";
|
|
unset($vv);
|
|
}else{
|
|
foreach($temp as $k=>$vv)
|
|
$fields[$k] .= " WHEN '{$v[$sKey]}' THEN '{$vv}' ";
|
|
}
|
|
unset($vv);
|
|
}
|
|
|
|
|
|
// Create query
|
|
$sSql = "";
|
|
foreach($fields as $k=>$v)
|
|
$sSql .= ", `{$k}` = CASE `{$sKey}` {$v} END";
|
|
|
|
|
|
$sWhere = "`{$sKey}` IN (". ($bIsString ? "'" . implode("','", $ids) . "'" : implode(",", $ids)) .") ";
|
|
|
|
if(!empty($where)){
|
|
foreach($where as $k => $v)
|
|
$sWhere .= " AND `{$k}` = '{$v}'";
|
|
}
|
|
// Complete query
|
|
$sSql = "UPDATE `{$table}` SET " . substr($sSql, 1) . " WHERE " . $sWhere;
|
|
|
|
|
|
if($this->execute($sSql, $table, $sWhere))
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function to start transition
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param int $maxQueriesInBatch - count of transactions in send batch
|
|
* @return bool - status
|
|
*/
|
|
public function startTransaction($maxQueriesInBatch = 20){
|
|
|
|
$this->lMAxTransactionCount = $maxQueriesInBatch;
|
|
return $this->bTransactionActive = true;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function to end transition and exec script
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @return bool - status
|
|
*/
|
|
public function endTransactionAndExec(){
|
|
|
|
if($this->bTransactionActive)
|
|
$this->chkExecSqlTransactionData(true);
|
|
|
|
$this->bTransactionActive = false;
|
|
return true;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function to add sql to transaction
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param string $sSql - sql to add to transaction batch
|
|
* @return bool - status
|
|
*/
|
|
public function addTransactionSql($sSql){
|
|
|
|
if($this->bTransactionActive){
|
|
$sSql = trim($sSql);
|
|
// Add semicolon at the end if none found
|
|
if(substr($sSql,-1) != ';')
|
|
$sSql .= ';';
|
|
|
|
$this->lTransactionCount++;
|
|
$this->sTransactionSql .= "{$sSql}\n";
|
|
|
|
// Check if limit reached
|
|
$this->chkExecSqlTransactionData();
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function to check if transaction limit reached and exec sql batch
|
|
*
|
|
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
|
|
* @param bool $bExec - exec sql data or check limit reach
|
|
* @return bool - status
|
|
*/
|
|
public function chkExecSqlTransactionData($bExec = false){
|
|
|
|
if($this->bTransactionActive){
|
|
if($this->lTransactionCount && strlen($this->sTransactionSql)){
|
|
if($bExec || ($this->lTransactionCount >= $this->lMAxTransactionCount)){
|
|
if($this->executeMulti($this->sTransactionSql)){
|
|
$this->sTransactionSql = "";
|
|
$this->lTransactionCount = 0;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}elseif($bExec){
|
|
|
|
// Clear data if sth went wrong
|
|
$this->sTransactionSql = "";
|
|
$this->lTransactionCount = 0;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|