BxDolDb.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  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 is_array($this->_aParams) && 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. $bResult = (int)$this->query($sQuery) > 0;
  393. // renew params cache
  394. $bResult &= $this->cacheParams(true);
  395. return $bResult;
  396. }
  397. function listTables()
  398. {
  399. return mysql_list_tables($GLOBALS['db']['db'], $this->_rLink);
  400. }
  401. function getFields($sTable)
  402. {
  403. $rFields = mysql_list_fields($this->_sDbname, $sTable, $this->_rLink);
  404. $iFields = mysql_num_fields($rFields);
  405. $aResult = array('original' => array(), 'uppercase' => array());
  406. for($i = 0; $i < $iFields; $i++) {
  407. $sName = mysql_field_name($rFields, $i);
  408. $aResult['original'][] = $sName;
  409. $aResult['uppercase'][] = strtoupper($sName);
  410. }
  411. return $aResult;
  412. }
  413. function isFieldExists($sTable, $sFieldName)
  414. {
  415. $aFields = $this->getFields($sTable);
  416. return in_array(strtoupper($sFieldName), $aFields['uppercase']);
  417. }
  418. function getEncoding()
  419. {
  420. return mysql_client_encoding($this->_rLink) or $this->error('Database get encoding error');
  421. }
  422. function genMySQLErr($sOutput, $query = '')
  423. {
  424. $sParamsOutput = false;
  425. $sFoundError = '';
  426. $aBackTrace = debug_backtrace();
  427. unset( $aBackTrace[0] );
  428. if( $query ) {
  429. //try help to find error
  430. $aFoundError = array();
  431. foreach( $aBackTrace as $aCall ) {
  432. // truncating global settings since it repeated many times and output it separately
  433. if (isset($aCall['object']) && property_exists($aCall['object'], '_aParams')) {
  434. if (false === $sParamsOutput)
  435. $sParamsOutput = var_export($aCall['object']->_aParams, true);
  436. $aCall['object']->_aParams = '[truncated]';
  437. }
  438. if (isset($aCall['args']) && is_array($aCall['args'])) {
  439. foreach( $aCall['args'] as $argNum => $argVal ) {
  440. if( is_string($argVal) and strcmp( $argVal, $query ) == 0 ) {
  441. $aFoundError['file'] = isset($aCall['file']) ? $aCall['file'] : (isset($aCall['class']) ? 'class: ' . $aCall['class'] : 'undefined');
  442. $aFoundError['line'] = isset($aCall['line']) ? $aCall['line'] : 'undefined';
  443. $aFoundError['function'] = $aCall['function'];
  444. $aFoundError['arg'] = $argNum;
  445. }
  446. }
  447. }
  448. }
  449. if( $aFoundError ) {
  450. $sFoundError = <<<EOJ
  451. Found error in the file '<b>{$aFoundError['file']}</b>' at line <b>{$aFoundError['line']}</b>.<br />
  452. Called '<b>{$aFoundError['function']}</b>' function with erroneous argument #<b>{$aFoundError['arg']}</b>.<br /><br />
  453. EOJ;
  454. }
  455. }
  456. bx_import('BxDolConfig');
  457. if (defined('BX_DB_FULL_VISUAL_PROCESSING') && BX_DB_FULL_VISUAL_PROCESSING) {
  458. ob_start();
  459. ?>
  460. <div style="border:2px solid red;padding:4px;width:600px;margin:0px auto;">
  461. <div style="text-align:center;background-color:red;color:white;font-weight:bold;">Error</div>
  462. <div style="text-align:center;"><?php echo $sOutput; ?></div>
  463. <?php
  464. if (defined('BX_DB_FULL_DEBUG_MODE') && BX_DB_FULL_DEBUG_MODE) {
  465. if (!empty($query))
  466. echo "<div><b>Query:</b><br />{$query}</div>";
  467. if ($this->_rLink)
  468. echo '<div><b>Mysql error:</b><br />' . $this->getErrorMessage() . '</div>';
  469. echo '<div style="overflow:scroll;height:300px;border:1px solid gray;">';
  470. echo $sFoundError;
  471. echo "<b>Debug backtrace:</b><br />";
  472. $sBackTrace = print_r($aBackTrace, true);
  473. $sBackTrace = str_replace('[password] => ' . BX_DATABASE_PASS, '[password] => *****', $sBackTrace);
  474. $sBackTrace = str_replace('[user] => ' . BX_DATABASE_USER, '[user] => *****', $sBackTrace);
  475. echo '<pre>' . $sBackTrace . '</pre>';
  476. if ($sParamsOutput) {
  477. echo '<hr />';
  478. echo "<b>Settings:</b><br />";
  479. echo '<pre>' . htmlspecialchars_adv($sParamsOutput) . '</pre>';
  480. }
  481. echo "<b>Called script:</b> " . $_SERVER['PHP_SELF'] . "<br />";
  482. echo "<b>Request parameters:</b><br />";
  483. echoDbg( $_REQUEST );
  484. echo '</div>';
  485. }
  486. ?>
  487. </div>
  488. <?php
  489. $sOutput = ob_get_clean();
  490. }
  491. if (defined('BX_DB_DO_EMAIL_ERROR_REPORT') && BX_DB_DO_EMAIL_ERROR_REPORT) {
  492. $sSiteTitle = $this->getParam('site_title');
  493. $sMailBody = "Database error in " . $sSiteTitle . "<br /><br /> \n";
  494. if( strlen( $query ) )
  495. $sMailBody .= "Query: <pre>" . htmlspecialchars_adv($query) . "</pre> ";
  496. if ($this->_rLink)
  497. $sMailBody .= "Mysql error: " . $this->getErrorMessage() . "<br /><br /> ";
  498. $sMailBody .= $sFoundError. '<br /> ';
  499. $sBackTrace = print_r($aBackTrace, true);
  500. $sBackTrace = str_replace('[password] => ' . BX_DATABASE_PASS, '[password] => *****', $sBackTrace);
  501. $sBackTrace = str_replace('[user] => ' . BX_DATABASE_USER, '[user] => *****', $sBackTrace);
  502. $sMailBody .= "Debug backtrace:\n <pre>" . htmlspecialchars_adv($sBackTrace) . "</pre> ";
  503. if ($sParamsOutput)
  504. $sMailBody .= "<hr />Settings:\n <pre>" . htmlspecialchars_adv($sParamsOutput) . "</pre> ";
  505. $sMailBody .= "<hr />Called script: " . $_SERVER['PHP_SELF'] . "<br /> ";
  506. $sMailBody .= "<hr />Request parameters: <pre>" . print_r( $_REQUEST, true ) . " </pre>";
  507. $sMailBody .= "--\nAuto-report system\n";
  508. sendMail($this->getParam('site_email'), "Database error in " . $sSiteTitle, $sMailBody, 0, array(), BX_EMAIL_SYSTEM, 'html', true);
  509. }
  510. bx_show_service_unavailable_error_and_exit($sOutput);
  511. }
  512. function setErrorChecking ($b)
  513. {
  514. $this->_bErrorChecking = $b;
  515. }
  516. function getDbCacheObject ()
  517. {
  518. if ($this->_oDbCacheObject != null) {
  519. return $this->_oDbCacheObject;
  520. } else {
  521. $sEngine = $this->getParam('sys_db_cache_engine');
  522. $this->_oDbCacheObject = bx_instance ('BxDolCache'.$sEngine);
  523. if (!$this->_oDbCacheObject->isAvailable())
  524. $this->_oDbCacheObject = bx_instance ('BxDolCacheFile');
  525. return $this->_oDbCacheObject;
  526. }
  527. }
  528. function genDbCacheKey ($sName)
  529. {
  530. return 'db_' . $sName . '_' . bx_site_hash() . '.php';
  531. }
  532. function fromCache ($sName, $sFunc)
  533. {
  534. $aArgs = func_get_args();
  535. array_shift ($aArgs); // shift $sName
  536. array_shift ($aArgs); // shift $sFunc
  537. if (!$this->getParam('sys_db_cache_enable'))
  538. return call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  539. $oCache = $this->getDbCacheObject ();
  540. $sKey = $this->genDbCacheKey($sName);
  541. $mixedRet = $oCache->getData($sKey);
  542. if ($mixedRet !== null) {
  543. return $mixedRet;
  544. } else {
  545. $mixedRet = call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  546. $oCache->setData($sKey, $mixedRet);
  547. }
  548. return $mixedRet;
  549. }
  550. function cleanCache ($sName)
  551. {
  552. if (!$this->getParam('sys_db_cache_enable'))
  553. return true;
  554. $oCache = $this->getDbCacheObject ();
  555. $sKey = $this->genDbCacheKey($sName);
  556. return $oCache->delData($sKey);
  557. }
  558. function & fromMemory ($sName, $sFunc)
  559. {
  560. if (array_key_exists($sName, $GLOBALS['gl_db_cache'])) {
  561. return $GLOBALS['gl_db_cache'][$sName];
  562. } else {
  563. $aArgs = func_get_args();
  564. array_shift ($aArgs); // shift $sName
  565. array_shift ($aArgs); // shift $sFunc
  566. $GLOBALS['gl_db_cache'][$sName] = call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  567. return $GLOBALS['gl_db_cache'][$sName];
  568. }
  569. }
  570. function cleanMemory ($sName)
  571. {
  572. if (isset($GLOBALS['gl_db_cache'][$sName])) {
  573. unset($GLOBALS['gl_db_cache'][$sName]);
  574. return true;
  575. }
  576. return false;
  577. }
  578. /**
  579. * It escapes string to pass to mysql query.
  580. * Try to use "prepare" function always (@see BxDolDb::prepare), use "escape" only if "prepare" function is not possible at all.
  581. * Also consider using "implode_escape" function (@see BxDolDb::implode_escape).
  582. *
  583. * @param string $s string to escape
  584. * @return escaped string whcich is ready to pass to SQL query.
  585. */
  586. function escape ($s)
  587. {
  588. return mysql_real_escape_string($s, $this->_rLink);
  589. }
  590. /**
  591. * This function is usefull when you need to form array of parameters to pass to IN(...) SQL construction.
  592. * Example:
  593. * @code
  594. * $a = array(2, 4.5, 'apple', 'car');
  595. * $s = "SELECT * FROM `t` WHERE `a` IN (" . $oDb->implode_escape($a) . ")";
  596. * echo $s; // outputs: SELECT * FROM `t` WHERE `a` IN (2, 4.5, 'apple', 'car')
  597. * @endcode
  598. *
  599. * @param $mixed array or parameters or just one paramter
  600. * @return string which is ready to pass to IN(...) SQL construction
  601. */
  602. function implode_escape ($mixed)
  603. {
  604. if (is_array($mixed)) {
  605. $s = '';
  606. foreach ($mixed as $v)
  607. $s .= (is_numeric($v) ? $v : "'" . mysql_real_escape_string($v, $this->_rLink) . "'") . ',';
  608. if ($s)
  609. return substr($s, 0, -1);
  610. else
  611. return 'NULL';
  612. }
  613. return is_numeric($mixed) ? $mixed : ($mixed ? "'" . mysql_real_escape_string($mixed, $this->_rLink) . "'" : 'NULL');
  614. }
  615. /**
  616. * @deprecated
  617. */
  618. function unescape ($mixed)
  619. {
  620. if (is_array($mixed)) {
  621. foreach ($mixed as $k => $v)
  622. $mixed[$k] = $this->getOne("SELECT '$v'");
  623. return $mixed;
  624. } else {
  625. return $this->getOne("SELECT '$mixed'");
  626. }
  627. }
  628. /**
  629. * Prepare SQL query before execution if some arguments are need to be passed to it.
  630. * All parameters marked with question (?) symbol in SQL query are replaced with parameters passed after SQL query parameter.
  631. * Parameters are properly excaped and surrounded by qutes if needed.
  632. * Example:
  633. * @code
  634. * $sSql = $oDb->prepare("SELECT `a`, `b` from `t` WHERE `c` = ? and `d` = ?", 12, 'aa');
  635. * echo $sSql;// outputs: SELECT `a`, `b` from `t` WHERE `c` = 12 and `d` = 'aa'
  636. * $a = $oDb->getAll($sSql);
  637. * @endcode
  638. *
  639. * @param string $sQuery SQL query, parameters for replacing are marked with ? symbol
  640. * @param mixed $mixed any number if parameters to replace, number of parameters whould match number of ? symbols in SQL query
  641. * @return string with SQL query ready for execution
  642. */
  643. function prepare ($sQuery)
  644. {
  645. $aArgs = func_get_args();
  646. $sQuery = array_shift($aArgs);
  647. $iPos = 0;
  648. foreach ($aArgs as $mixedArg) {
  649. if (is_null($mixedArg))
  650. $s = 'NULL';
  651. elseif (is_numeric($mixedArg))
  652. $s = $mixedArg;
  653. else
  654. $s = "'" . mysql_real_escape_string($mixedArg) . "'";
  655. $i = bx_mb_strpos($sQuery, '?', $iPos);
  656. $sQuery = bx_mb_substr_replace($sQuery, $s, $i, 1);
  657. $iPos = $i + get_mb_len($s);
  658. }
  659. return $sQuery;
  660. }
  661. /**
  662. * Convert array of key => values to SQL query.
  663. * Array keys are field names and array values are field values.
  664. * @param $a array
  665. * @param $sDiv fields separator, by default it is ',', another useful value is ' AND '
  666. * @return part of SQL query string
  667. */
  668. function arrayToSQL ($a, $sDiv = ',')
  669. {
  670. $s = '';
  671. foreach ($a as $k => $v)
  672. $s .= "`{$k}` = '" . $this->escape($v) . "'" . $sDiv;
  673. return trim($s, $sDiv);
  674. }
  675. function log ($s)
  676. {
  677. return file_put_contents(BX_DIRECTORY_PATH_ROOT . 'logs/db.err.log', date('Y-m-d H:i:s') . "\t" . $s . "\n", FILE_APPEND);
  678. }
  679. function executeSQL($sPath, $aReplace = array (), $isBreakOnError = true)
  680. {
  681. if(!file_exists($sPath) || !($rHandler = fopen($sPath, "r")))
  682. return array(array ('query' => "fopen($sPath, 'r')", 'error' => 'file not found or permission denied'));
  683. $sQuery = "";
  684. $sDelimiter = ';';
  685. $aResult = array();
  686. while(!feof($rHandler)) {
  687. $sStr = trim(fgets($rHandler));
  688. if(empty($sStr) || $sStr[0] == "" || $sStr[0] == "#" || ($sStr[0] == "-" && $sStr[1] == "-"))
  689. continue;
  690. //--- Change delimiter ---//
  691. if(strpos($sStr, "DELIMITER //") !== false || strpos($sStr, "DELIMITER ;") !== false) {
  692. $sDelimiter = trim(str_replace('DELIMITER', '', $sStr));
  693. continue;
  694. }
  695. $sQuery .= $sStr;
  696. //--- Check for multiline query ---//
  697. if(substr($sStr, -strlen($sDelimiter)) != $sDelimiter)
  698. continue;
  699. //--- Execute query ---//
  700. if ($aReplace)
  701. $sQuery = str_replace($aReplace['from'], $aReplace['to'], $sQuery);
  702. if($sDelimiter != ';')
  703. $sQuery = str_replace($sDelimiter, "", $sQuery);
  704. $rResult = $this->res(trim($sQuery), false);
  705. if(!$rResult) {
  706. $aResult[] = array('query' => $sQuery, 'error' => $this->getErrorMessage());
  707. if ($isBreakOnError)
  708. break;
  709. }
  710. $sQuery = "";
  711. }
  712. fclose($rHandler);
  713. return empty($aResult) ? true : $aResult;
  714. }
  715. }
  716. function getParam($sParamName, $bUseCache = true)
  717. {
  718. return BxDolDb::getInstance()->getParam($sParamName, $bUseCache);
  719. }
  720. function setParam($sParamName, $sParamVal)
  721. {
  722. return BxDolDb::getInstance()->setParam($sParamName, $sParamVal);
  723. }
  724. /** @} */