BxDolDb.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. <?php defined('BX_DOL') or defined('BX_DOL_INSTALL') or die('hack attempt');
  2. /**
  3. * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
  4. * CC-BY License - http://creativecommons.org/licenses/by/3.0/
  5. *
  6. * @defgroup DolphinCore Dolphin Core
  7. * @{
  8. */
  9. class BxDolDb extends BxDol implements iBxDolSingleton
  10. {
  11. protected $_bErrorChecking = true;
  12. protected $_sErrorMessage;
  13. protected $_sHost, $_sPort, $_sSocket, $_sDbname, $_sUser, $_sPassword;
  14. protected $_rLink, $_rCurrentRes, $_iCurrentResType;
  15. protected $_oDbCacheObject = null;
  16. protected $_aParams = null;
  17. protected $_sParamsCacheName = 'sys_options';
  18. protected $_sStorageEngine = 'MYISAM';
  19. /**
  20. * set database parameters and connect to it
  21. */
  22. protected function __construct($aDbConf = false)
  23. {
  24. if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
  25. trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
  26. parent::__construct();
  27. if (false === $aDbConf) {
  28. $this->_sHost = BX_DATABASE_HOST;
  29. $this->_sPort = BX_DATABASE_PORT;
  30. $this->_sSocket = BX_DATABASE_SOCK;
  31. $this->_sDbname = BX_DATABASE_NAME;
  32. $this->_sUser = BX_DATABASE_USER;
  33. $this->_sPassword = BX_DATABASE_PASS;
  34. } else {
  35. $this->_sHost = $aDbConf['host'];
  36. $this->_sPort = $aDbConf['port'];
  37. $this->_sSocket = $aDbConf['sock'];
  38. $this->_sDbname = $aDbConf['name'];
  39. $this->_sUser = $aDbConf['user'];
  40. $this->_sPassword = $aDbConf['pwd'];
  41. $this->_bErrorChecking = isset($aDbConf['error_checking']) ? $aDbConf['error_checking'] : true;
  42. }
  43. $this->_iCurrentResType = MYSQL_ASSOC;
  44. // connect to db automatically
  45. if (empty($GLOBALS['bx_db__rLink'])) {
  46. $this->connect();
  47. $GLOBALS['gl_db_cache'] = array();
  48. } else {
  49. $this->_rLink = $GLOBALS['bx_db__rLink'];
  50. }
  51. }
  52. /**
  53. * Prevent cloning the instance
  54. */
  55. public function __clone()
  56. {
  57. if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
  58. trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
  59. }
  60. /**
  61. * Get singleton instance of the class
  62. */
  63. public static function getInstance($aDbConf = false, &$sError = null)
  64. {
  65. if (!isset($GLOBALS['bxDolClasses'][__CLASS__])) {
  66. if (false === $aDbConf && !defined('BX_DATABASE_HOST'))
  67. return null;
  68. $o = new BxDolDb($aDbConf);
  69. $sErrorMessage = $o->connect();
  70. if ($sErrorMessage) {
  71. if ($sError !== null)
  72. $sError = $sErrorMessage;
  73. return null;
  74. } else {
  75. $GLOBALS['bxDolClasses'][__CLASS__] = $o;
  76. }
  77. }
  78. return $GLOBALS['bxDolClasses'][__CLASS__];
  79. }
  80. /**
  81. * connect to database with appointed parameters
  82. */
  83. function connect()
  84. {
  85. $full_host = $this->_sHost;
  86. $full_host .= $this->_sPort ? ':'.$this->_sPort : '';
  87. $full_host .= $this->_sSocket ? ':'.$this->_sSocket : '';
  88. $this->_rLink = @mysql_pconnect($full_host, $this->_sUser, $this->_sPassword);
  89. if (!$this->_rLink)
  90. return 'Database connect failed';
  91. if (!$this->select_db())
  92. return 'Database select failed';
  93. mysql_query("SET NAMES 'utf8'", $this->_rLink);
  94. mysql_query("SET sql_mode = ''", $this->_rLink);
  95. mysql_query("SET storage_engine=" . $this->_sStorageEngine, $this->_rLink);
  96. $GLOBALS['bx_db__rLink'] = $this->_rLink;
  97. return '';
  98. }
  99. function select_db()
  100. {
  101. return @mysql_select_db($this->_sDbname, $this->_rLink);
  102. }
  103. /**
  104. * close mysql connection
  105. */
  106. function close()
  107. {
  108. mysql_close($this->_rLink);
  109. }
  110. /**
  111. * get mysql server info
  112. */
  113. function getServerInfo()
  114. {
  115. return mysql_get_server_info($this->_rLink);
  116. }
  117. /**
  118. * get mysql option
  119. */
  120. function getOption($sName)
  121. {
  122. return $this->getOne("SELECT @@{$sName}");
  123. }
  124. /**
  125. * execute sql query and return one row result
  126. */
  127. function getRow($query, $arr_type = MYSQL_ASSOC)
  128. {
  129. if(!$query)
  130. return array();
  131. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM && $arr_type != MYSQL_BOTH)
  132. $arr_type = MYSQL_ASSOC;
  133. $res = $this->res ($query);
  134. $arr_res = array();
  135. if($res && mysql_num_rows($res)) {
  136. $arr_res = mysql_fetch_array($res, $arr_type);
  137. mysql_free_result($res);
  138. }
  139. return $arr_res;
  140. }
  141. /**
  142. * execute sql query and return a column as result
  143. */
  144. function getColumn($sQuery)
  145. {
  146. if(!$sQuery)
  147. return array();
  148. $rResult = $this->res($sQuery);
  149. $aResult = array();
  150. if($rResult) {
  151. while($aRow = mysql_fetch_array($rResult, MYSQL_NUM))
  152. $aResult[] = $aRow[0];
  153. mysql_free_result($rResult);
  154. }
  155. return $aResult;
  156. }
  157. /**
  158. * execute sql query and return one value result
  159. */
  160. function getOne($query, $index = 0)
  161. {
  162. if(!$query)
  163. return false;
  164. $res = $this->res ($query);
  165. $arr_res = array();
  166. if($res && mysql_num_rows($res))
  167. $arr_res = mysql_fetch_array($res);
  168. if(count($arr_res))
  169. return $arr_res[$index];
  170. else
  171. return false;
  172. }
  173. /**
  174. * execute sql query and return the first row of result
  175. * and keep $array type and poiter to all data
  176. */
  177. function getFirstRow($query, $arr_type = MYSQL_ASSOC)
  178. {
  179. if(!$query)
  180. return array();
  181. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM)
  182. $this->_iCurrentResType = MYSQL_ASSOC;
  183. else
  184. $this->_iCurrentResType = $arr_type;
  185. $this->_rCurrentRes = $this->res ($query);
  186. $arr_res = array();
  187. if($this->_rCurrentRes && mysql_num_rows($this->_rCurrentRes))
  188. $arr_res = mysql_fetch_array($this->_rCurrentRes, $this->_iCurrentResType);
  189. return $arr_res;
  190. }
  191. /**
  192. * return next row of pointed last getFirstRow calling data
  193. */
  194. function getNextRow()
  195. {
  196. $arr_res = mysql_fetch_array($this->_rCurrentRes, $this->_iCurrentResType);
  197. if($arr_res)
  198. return $arr_res;
  199. else {
  200. mysql_free_result($this->_rCurrentRes);
  201. $this->_iCurrentResType = MYSQL_ASSOC;
  202. return array();
  203. }
  204. }
  205. /**
  206. * return number of affected rows in current mysql result
  207. */
  208. function getNumRows($res = false)
  209. {
  210. if ($res)
  211. return (int)@mysql_num_rows($res);
  212. elseif (!$this->_rCurrentRes)
  213. return (int)@mysql_num_rows($this->_rCurrentRes);
  214. else
  215. return 0;
  216. }
  217. /**
  218. * execute any query return number of rows affected/false
  219. */
  220. function getAffectedRows()
  221. {
  222. return mysql_affected_rows($this->_rLink);
  223. }
  224. /**
  225. * execute any query return number of rows affected/false
  226. */
  227. function query($query)
  228. {
  229. $res = $this->res($query);
  230. if ($res)
  231. return mysql_affected_rows($this->_rLink);
  232. return false;
  233. }
  234. /**
  235. * execute any query
  236. */
  237. function res($query, $bErrorChecking = true)
  238. {
  239. if(!$query)
  240. return false;
  241. if (isset($GLOBALS['bx_profiler'])) $GLOBALS['bx_profiler']->beginQuery($query);
  242. $res = @mysql_query($query, $this->_rLink);
  243. if (false === $res)
  244. $this->_sErrorMessage = @mysql_error($this->_rLink); // we need to remeber last error message since mysql_ping will reset it on the next line !
  245. else
  246. $this->_sErrorMessage = '';
  247. if (!$res && !@mysql_ping($this->_rLink)) { // if mysql connection is lost - reconnect and try again
  248. @mysql_close($this->_rLink);
  249. $sErrorMessage = $this->connect();
  250. if ($sErrorMessage)
  251. $this->error($sErrorMessage, true);
  252. $res = mysql_query($query, $this->_rLink);
  253. }
  254. if (isset($GLOBALS['bx_profiler'])) $GLOBALS['bx_profiler']->endQuery($res);
  255. if (!$res && $bErrorChecking)
  256. $this->error('Database query error', false, $query);
  257. return $res;
  258. }
  259. /**
  260. * execute sql query and return table of records as result
  261. */
  262. function getAll($query, $arr_type = MYSQL_ASSOC)
  263. {
  264. if(!$query)
  265. return array();
  266. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM && $arr_type != MYSQL_BOTH)
  267. $arr_type = MYSQL_ASSOC;
  268. $res = $this->res ($query);
  269. $arr_res = array();
  270. if($res) {
  271. while($row = mysql_fetch_array($res, $arr_type))
  272. $arr_res[] = $row;
  273. mysql_free_result($res);
  274. }
  275. return $arr_res;
  276. }
  277. /**
  278. * execute sql query and return table of records as result
  279. */
  280. function fillArray($res, $arr_type = MYSQL_ASSOC)
  281. {
  282. if(!$res)
  283. return array();
  284. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM && $arr_type != MYSQL_BOTH)
  285. $arr_type = MYSQL_ASSOC;
  286. $arr_res = array();
  287. while($row = mysql_fetch_array($res, $arr_type))
  288. $arr_res[] = $row;
  289. mysql_free_result($res);
  290. return $arr_res;
  291. }
  292. /**
  293. * execute sql query and return table of records as result
  294. */
  295. function getAllWithKey($query, $sFieldKey)
  296. {
  297. if(!$query)
  298. return array();
  299. $res = $this->res ($query);
  300. $arr_res = array();
  301. if($res) {
  302. while($row = mysql_fetch_array($res, MYSQL_ASSOC)) {
  303. $arr_res[$row[$sFieldKey]] = $row;
  304. }
  305. mysql_free_result($res);
  306. }
  307. return $arr_res;
  308. }
  309. /**
  310. * execute sql query and return table of records as result
  311. */
  312. function getPairs($query, $sFieldKey, $sFieldValue)
  313. {
  314. if(!$query)
  315. return array();
  316. $res = $this->res ($query);
  317. $arr_res = array();
  318. if($res) {
  319. while($row = mysql_fetch_array($res, MYSQL_ASSOC)) {
  320. $arr_res[$row[$sFieldKey]] = $row[$sFieldValue];
  321. }
  322. mysql_free_result($res);
  323. }
  324. return $arr_res;
  325. }
  326. function lastId()
  327. {
  328. return mysql_insert_id($this->_rLink);
  329. }
  330. function getErrorMessage ()
  331. {
  332. $s = mysql_error($this->_rLink);
  333. if ($s)
  334. return $s;
  335. else
  336. return $this->_sErrorMessage;
  337. }
  338. function error($text, $isForceErrorChecking = false, $sSqlQuery = '')
  339. {
  340. if ($this->_bErrorChecking || $isForceErrorChecking)
  341. $this->genMySQLErr ($text, $sSqlQuery);
  342. else
  343. $this->log($text . ': ' . $this->getErrorMessage());
  344. }
  345. protected function isParamInCache($sKey)
  346. {
  347. return isset($this->_aParams[$sKey]);
  348. }
  349. protected function cacheParams($bForceCacheInvalidate = false)
  350. {
  351. if ($bForceCacheInvalidate)
  352. $this->cacheParamsClear();
  353. $this->_aParams = $this->fromCache($this->_sParamsCacheName, 'getPairs', "SELECT `name`, `value` FROM `sys_options`", "name", "value");
  354. if (empty($this->_aParams)) {
  355. $this->_aParams = array ();
  356. return false;
  357. }
  358. return true;
  359. }
  360. public function cacheParamsClear()
  361. {
  362. return $this->cleanCache($this->_sParamsCacheName);
  363. }
  364. public function isParam($sKey, $bFromCache = true)
  365. {
  366. if ($bFromCache && $this->isParamInCache($sKey))
  367. return true;
  368. $sQuery = $this->prepare("SELECT `name` FROM `sys_options` WHERE `name` = ? LIMIT 1", $sKey);
  369. return $this->getOne($sQuery) == $sKey;
  370. }
  371. function addParam($sName, $sValue, $iKateg, $sDesc, $sType)
  372. {
  373. $sQuery = $this->prepare("INSERT INTO `sys_options` SET `category_id` = ?, `name` = ?, `caption` = ?, `value` = ?, `type` = ?", $iKateg, $sName, $sDesc, $sValue, $sType);
  374. $this->query($sQuery);
  375. // renew params cache
  376. $this->cacheParams(true);
  377. }
  378. function getParam($sKey, $bFromCache = true)
  379. {
  380. if (!$sKey)
  381. return false;
  382. if ($bFromCache && $this->isParamInCache($sKey)) {
  383. return $this->_aParams[$sKey];
  384. } else {
  385. $sQuery = $this->prepare("SELECT `value` FROM `sys_options` WHERE `name` = ? LIMIT 1", $sKey);
  386. return $this->getOne($sQuery);
  387. }
  388. }
  389. function setParam($sKey, $mixedValue)
  390. {
  391. $sQuery = $this->prepare("UPDATE `sys_options` SET `value` = ? WHERE `name` = ? LIMIT 1", $mixedValue, $sKey);
  392. $this->query($sQuery);
  393. // renew params cache
  394. $this->cacheParams(true);
  395. }
  396. function listTables()
  397. {
  398. return mysql_list_tables($GLOBALS['db']['db'], $this->_rLink);
  399. }
  400. function getFields($sTable)
  401. {
  402. $rFields = mysql_list_fields($this->_sDbname, $sTable, $this->_rLink);
  403. $iFields = mysql_num_fields($rFields);
  404. $aResult = array('original' => array(), 'uppercase' => array());
  405. for($i = 0; $i < $iFields; $i++) {
  406. $sName = mysql_field_name($rFields, $i);
  407. $aResult['original'][] = $sName;
  408. $aResult['uppercase'][] = strtoupper($sName);
  409. }
  410. return $aResult;
  411. }
  412. function isFieldExists($sTable, $sFieldName)
  413. {
  414. $aFields = $this->getFields($sTable);
  415. return in_array(strtoupper($sFieldName), $aFields['uppercase']);
  416. }
  417. function getEncoding()
  418. {
  419. return mysql_client_encoding($this->_rLink) or $this->error('Database get encoding error');
  420. }
  421. function genMySQLErr( $out, $query ='' )
  422. {
  423. $sParamsOutput = false;
  424. $sFoundError = '';
  425. $aBackTrace = debug_backtrace();
  426. unset( $aBackTrace[0] );
  427. if( $query ) {
  428. //try help to find error
  429. $aFoundError = array();
  430. foreach( $aBackTrace as $aCall ) {
  431. // truncating global settings since it repeated many times and output it separately
  432. if (isset($aCall['object']) && property_exists($aCall['object'], '_aParams')) {
  433. if (false === $sParamsOutput)
  434. $sParamsOutput = var_export($aCall['object']->_aParams, true);
  435. $aCall['object']->_aParams = '[truncated]';
  436. }
  437. if (isset($aCall['args']) && is_array($aCall['args'])) {
  438. foreach( $aCall['args'] as $argNum => $argVal ) {
  439. if( is_string($argVal) and strcmp( $argVal, $query ) == 0 ) {
  440. $aFoundError['file'] = isset($aCall['file']) ? $aCall['file'] : (isset($aCall['class']) ? 'class: ' . $aCall['class'] : 'undefined');
  441. $aFoundError['line'] = isset($aCall['line']) ? $aCall['line'] : 'undefined';
  442. $aFoundError['function'] = $aCall['function'];
  443. $aFoundError['arg'] = $argNum;
  444. }
  445. }
  446. }
  447. }
  448. if( $aFoundError ) {
  449. $sFoundError = <<<EOJ
  450. Found error in the file '<b>{$aFoundError['file']}</b>' at line <b>{$aFoundError['line']}</b>.<br />
  451. Called '<b>{$aFoundError['function']}</b>' function with erroneous argument #<b>{$aFoundError['arg']}</b>.<br /><br />
  452. EOJ;
  453. }
  454. }
  455. bx_import('BxDolConfig');
  456. if (BxDolConfig::getInstance()->get('db', 'visual_processing')) {
  457. ?>
  458. <div style="border:2px solid red;padding:4px;width:600px;margin:0px auto;">
  459. <div style="text-align:center;background-color:red;color:white;font-weight:bold;">Error</div>
  460. <div style="text-align:center;"><?php echo $out?></div>
  461. <?php
  462. if(BxDolConfig::getInstance()->get('db', 'debug_mode')) {
  463. if( strlen( $query ) )
  464. echo "<div><b>Query:</b><br />{$query}</div>";
  465. if ($this->_rLink)
  466. echo '<div><b>Mysql error:</b><br />' . $this->getErrorMessage() . '</div>';
  467. echo '<div style="overflow:scroll;height:300px;border:1px solid gray;">';
  468. echo $sFoundError;
  469. echo "<b>Debug backtrace:</b><br />";
  470. $sBackTrace = print_r($aBackTrace, true);
  471. $sBackTrace = str_replace('[password] => ' . BX_DATABASE_PASS, '[password] => *****', $sBackTrace);
  472. $sBackTrace = str_replace('[user] => ' . BX_DATABASE_USER, '[user] => *****', $sBackTrace);
  473. echo '<pre>' . $sBackTrace . '</pre>';
  474. if ($sParamsOutput) {
  475. echo '<hr />';
  476. echo "<b>Settings:</b><br />";
  477. echo '<pre>' . htmlspecialchars_adv($sParamsOutput) . '</pre>';
  478. }
  479. echo "<b>Called script:</b> " . $_SERVER['PHP_SELF'] . "<br />";
  480. echo "<b>Request parameters:</b><br />";
  481. echoDbg( $_REQUEST );
  482. echo '</div>';
  483. }
  484. ?>
  485. </div>
  486. <?php
  487. } else
  488. echo $out;
  489. if(BxDolConfig::getInstance()->get('db', 'error_remort_by_email')) {
  490. $sSiteTitle = $this->getParam('site_title');
  491. $sMailBody = "Database error in " . $sSiteTitle . "<br /><br /> \n";
  492. if( strlen( $query ) )
  493. $sMailBody .= "Query: <pre>" . htmlspecialchars_adv($query) . "</pre> ";
  494. if ($this->_rLink)
  495. $sMailBody .= "Mysql error: " . $this->getErrorMessage() . "<br /><br /> ";
  496. $sMailBody .= $sFoundError. '<br /> ';
  497. $sBackTrace = print_r($aBackTrace, true);
  498. $sBackTrace = str_replace('[password] => ' . BX_DATABASE_PASS, '[password] => *****', $sBackTrace);
  499. $sBackTrace = str_replace('[user] => ' . BX_DATABASE_USER, '[user] => *****', $sBackTrace);
  500. $sMailBody .= "Debug backtrace:\n <pre>" . htmlspecialchars_adv($sBackTrace) . "</pre> ";
  501. if ($sParamsOutput)
  502. $sMailBody .= "<hr />Settings:\n <pre>" . htmlspecialchars_adv($sParamsOutput) . "</pre> ";
  503. $sMailBody .= "<hr />Called script: " . $_SERVER['PHP_SELF'] . "<br /> ";
  504. $sMailBody .= "<hr />Request parameters: <pre>" . print_r( $_REQUEST, true ) . " </pre>";
  505. $sMailBody .= "--\nAuto-report system\n";
  506. sendMail($this->getParam('site_email'), "Database error in " . $sSiteTitle, $sMailBody, 0, array(), BX_EMAIL_SYSTEM, 'html', true);
  507. }
  508. exit;
  509. }
  510. function setErrorChecking ($b)
  511. {
  512. $this->_bErrorChecking = $b;
  513. }
  514. function getDbCacheObject ()
  515. {
  516. if ($this->_oDbCacheObject != null) {
  517. return $this->_oDbCacheObject;
  518. } else {
  519. $sEngine = $this->getParam('sys_db_cache_engine');
  520. $this->_oDbCacheObject = bx_instance ('BxDolCache'.$sEngine);
  521. if (!$this->_oDbCacheObject->isAvailable())
  522. $this->_oDbCacheObject = bx_instance ('BxDolCacheFile');
  523. return $this->_oDbCacheObject;
  524. }
  525. }
  526. function genDbCacheKey ($sName)
  527. {
  528. return 'db_' . $sName . '_' . bx_site_hash() . '.php';
  529. }
  530. function fromCache ($sName, $sFunc)
  531. {
  532. $aArgs = func_get_args();
  533. array_shift ($aArgs); // shift $sName
  534. array_shift ($aArgs); // shift $sFunc
  535. if (!$this->getParam('sys_db_cache_enable'))
  536. return call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  537. $oCache = $this->getDbCacheObject ();
  538. $sKey = $this->genDbCacheKey($sName);
  539. $mixedRet = $oCache->getData($sKey);
  540. if ($mixedRet !== null) {
  541. return $mixedRet;
  542. } else {
  543. $mixedRet = call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  544. $oCache->setData($sKey, $mixedRet);
  545. }
  546. return $mixedRet;
  547. }
  548. function cleanCache ($sName)
  549. {
  550. if (!$this->getParam('sys_db_cache_enable'))
  551. return true;
  552. $oCache = $this->getDbCacheObject ();
  553. $sKey = $this->genDbCacheKey($sName);
  554. return $oCache->delData($sKey);
  555. }
  556. function & fromMemory ($sName, $sFunc)
  557. {
  558. if (array_key_exists($sName, $GLOBALS['gl_db_cache'])) {
  559. return $GLOBALS['gl_db_cache'][$sName];
  560. } else {
  561. $aArgs = func_get_args();
  562. array_shift ($aArgs); // shift $sName
  563. array_shift ($aArgs); // shift $sFunc
  564. $GLOBALS['gl_db_cache'][$sName] = call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  565. return $GLOBALS['gl_db_cache'][$sName];
  566. }
  567. }
  568. function cleanMemory ($sName)
  569. {
  570. if (isset($GLOBALS['gl_db_cache'][$sName])) {
  571. unset($GLOBALS['gl_db_cache'][$sName]);
  572. return true;
  573. }
  574. return false;
  575. }
  576. /**
  577. * It escapes string to pass to mysql query.
  578. * Try to use "prepare" function always (@see BxDolDb::prepare), use "escape" only if "prepare" function is not possible at all.
  579. * Also consider using "implode_escape" function (@see BxDolDb::implode_escape).
  580. *
  581. * @param string $s string to escape
  582. * @return escaped string whcich is ready to pass to SQL query.
  583. */
  584. function escape ($s)
  585. {
  586. return mysql_real_escape_string($s, $this->_rLink);
  587. }
  588. /**
  589. * This function is usefull when you need to form array of parameters to pass to IN(...) SQL construction.
  590. * Example:
  591. * @code
  592. * $a = array(2, 4.5, 'apple', 'car');
  593. * $s = "SELECT * FROM `t` WHERE `a` IN (" . $oDb->implode_escape($a) . ")";
  594. * echo $s; // outputs: SELECT * FROM `t` WHERE `a` IN (2, 4.5, 'apple', 'car')
  595. * @endcode
  596. *
  597. * @param $mixed array or parameters or just one paramter
  598. * @return string which is ready to pass to IN(...) SQL construction
  599. */
  600. function implode_escape ($mixed)
  601. {
  602. if (is_array($mixed)) {
  603. $s = '';
  604. foreach ($mixed as $v)
  605. $s .= (is_numeric($v) ? $v : "'" . mysql_real_escape_string($v, $this->_rLink) . "'") . ',';
  606. if ($s)
  607. return substr($s, 0, -1);
  608. else
  609. return 'NULL';
  610. }
  611. return is_numeric($mixed) ? $mixed : ($mixed ? "'" . mysql_real_escape_string($mixed, $this->_rLink) . "'" : 'NULL');
  612. }
  613. /**
  614. * @deprecated
  615. */
  616. function unescape ($mixed)
  617. {
  618. if (is_array($mixed)) {
  619. foreach ($mixed as $k => $v)
  620. $mixed[$k] = $this->getOne("SELECT '$v'");
  621. return $mixed;
  622. } else {
  623. return $this->getOne("SELECT '$mixed'");
  624. }
  625. }
  626. /**
  627. * Prepare SQL query before execution if some arguments are need to be passed to it.
  628. * All parameters marked with question (?) symbol in SQL query are replaced with parameters passed after SQL query parameter.
  629. * Parameters are properly excaped and surrounded by qutes if needed.
  630. * Example:
  631. * @code
  632. * $sSql = $oDb->prepare("SELECT `a`, `b` from `t` WHERE `c` = ? and `d` = ?", 12, 'aa');
  633. * echo $sSql;// outputs: SELECT `a`, `b` from `t` WHERE `c` = 12 and `d` = 'aa'
  634. * $a = $oDb->getAll($sSql);
  635. * @endcode
  636. *
  637. * @param string $sQuery SQL query, parameters for replacing are marked with ? symbol
  638. * @param mixed $mixed any number if parameters to replace, number of parameters whould match number of ? symbols in SQL query
  639. * @return string with SQL query ready for execution
  640. */
  641. function prepare ($sQuery)
  642. {
  643. $aArgs = func_get_args();
  644. $sQuery = array_shift($aArgs);
  645. $iPos = 0;
  646. foreach ($aArgs as $mixedArg) {
  647. if (is_null($mixedArg))
  648. $s = 'NULL';
  649. elseif (is_numeric($mixedArg))
  650. $s = $mixedArg;
  651. else
  652. $s = "'" . mysql_real_escape_string($mixedArg) . "'";
  653. $i = bx_mb_strpos($sQuery, '?', $iPos);
  654. $sQuery = bx_mb_substr_replace($sQuery, $s, $i, 1);
  655. $iPos = $i + get_mb_len($s);
  656. }
  657. return $sQuery;
  658. }
  659. /**
  660. * Convert array of key => values to SQL query.
  661. * Array keys are field names and array values are field values.
  662. * @param $a array
  663. * @param $sDiv fields separator, by default it is ',', another useful value is ' AND '
  664. * @return part of SQL query string
  665. */
  666. function arrayToSQL ($a, $sDiv = ',')
  667. {
  668. $s = '';
  669. foreach ($a as $k => $v)
  670. $s .= "`{$k}` = '" . $this->escape($v) . "'" . $sDiv;
  671. return trim($s, $sDiv);
  672. }
  673. function log ($s)
  674. {
  675. return file_put_contents(BX_DIRECTORY_PATH_ROOT . 'logs/db.err.log', date('Y-m-d H:i:s') . "\t" . $s . "\n", FILE_APPEND);
  676. }
  677. function executeSQL($sPath, $aReplace = array (), $isBreakOnError = true)
  678. {
  679. if(!file_exists($sPath) || !($rHandler = fopen($sPath, "r")))
  680. return array(array ('query' => "fopen($sPath, 'r')", 'error' => 'file not found or permission denied'));
  681. $sQuery = "";
  682. $sDelimiter = ';';
  683. $aResult = array();
  684. while(!feof($rHandler)) {
  685. $sStr = trim(fgets($rHandler));
  686. if(empty($sStr) || $sStr[0] == "" || $sStr[0] == "#" || ($sStr[0] == "-" && $sStr[1] == "-"))
  687. continue;
  688. //--- Change delimiter ---//
  689. if(strpos($sStr, "DELIMITER //") !== false || strpos($sStr, "DELIMITER ;") !== false) {
  690. $sDelimiter = trim(str_replace('DELIMITER', '', $sStr));
  691. continue;
  692. }
  693. $sQuery .= $sStr;
  694. //--- Check for multiline query ---//
  695. if(substr($sStr, -strlen($sDelimiter)) != $sDelimiter)
  696. continue;
  697. //--- Execute query ---//
  698. if ($aReplace)
  699. $sQuery = str_replace($aReplace['from'], $aReplace['to'], $sQuery);
  700. if($sDelimiter != ';')
  701. $sQuery = str_replace($sDelimiter, "", $sQuery);
  702. $rResult = $this->res(trim($sQuery), false);
  703. if(!$rResult) {
  704. $aResult[] = array('query' => $sQuery, 'error' => $this->getErrorMessage());
  705. if ($isBreakOnError)
  706. break;
  707. }
  708. $sQuery = "";
  709. }
  710. fclose($rHandler);
  711. return empty($aResult) ? true : $aResult;
  712. }
  713. }
  714. function getParam($sParamName, $bUseCache = true)
  715. {
  716. return BxDolDb::getInstance()->getParam($sParamName, $bUseCache);
  717. }
  718. function setParam($sParamName, $sParamVal)
  719. {
  720. return BxDolDb::getInstance()->setParam($sParamName, $sParamVal);
  721. }
  722. /** @} */