BxDolDb.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. <?php defined('BX_DOL') 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. bx_import('BxDolParams');
  10. class BxDolDb extends BxDol implements iBxDolSingleton {
  11. var $error_checking = true;
  12. var $error_message;
  13. var $host, $port, $socket, $dbname, $user, $password, $link;
  14. var $current_res, $current_arr_type;
  15. var $oParams = null;
  16. var $oDbCacheObject = null;
  17. /**
  18. * set database parameters and connect to it
  19. */
  20. protected function BxDolDb() {
  21. if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
  22. trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
  23. parent::BxDol();
  24. $this->host = BX_DATABASE_HOST;
  25. $this->port = BX_DATABASE_PORT;
  26. $this->socket = BX_DATABASE_SOCK;
  27. $this->dbname = BX_DATABASE_NAME;
  28. $this->user = BX_DATABASE_USER;
  29. $this->password = BX_DATABASE_PASS;
  30. $this->current_arr_type = MYSQL_ASSOC;
  31. // connect to db automatically
  32. if (empty($GLOBALS['bx_db_link'])) {
  33. $this->connect();
  34. $GLOBALS['gl_db_cache'] = array();
  35. } else {
  36. $this->link = $GLOBALS['bx_db_link'];
  37. }
  38. $this->oParams = BxDolParams::getInstance($this);
  39. }
  40. /**
  41. * Prevent cloning the instance
  42. */
  43. public function __clone() {
  44. if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
  45. trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
  46. }
  47. /**
  48. * Get singleton instance of the class
  49. */
  50. public static function getInstance() {
  51. if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
  52. $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolDb();
  53. return $GLOBALS['bxDolClasses'][__CLASS__];
  54. }
  55. /**
  56. * connect to database with appointed parameters
  57. */
  58. function connect()
  59. {
  60. $full_host = $this->host;
  61. $full_host .= $this->port ? ':'.$this->port : '';
  62. $full_host .= $this->socket ? ':'.$this->socket : '';
  63. $this->link = @mysql_pconnect($full_host, $this->user, $this->password);
  64. if (!$this->link)
  65. $this->error('Database connect failed', true);
  66. if (!$this->select_db())
  67. $this->error('Database select failed', true);
  68. mysql_query("SET NAMES 'utf8'", $this->link);
  69. mysql_query("SET sql_mode = ''", $this->link);
  70. $GLOBALS['bx_db_link'] = $this->link;
  71. }
  72. function select_db()
  73. {
  74. return @mysql_select_db($this->dbname, $this->link) or $this->error('Cannot complete query (select_db)');
  75. }
  76. /**
  77. * close mysql connection
  78. */
  79. function close()
  80. {
  81. mysql_close($this->link);
  82. }
  83. /**
  84. * get mysql server info
  85. */
  86. function getServerInfo()
  87. {
  88. return mysql_get_server_info($this->link);
  89. }
  90. /**
  91. * get mysql option
  92. */
  93. function getOption($sName)
  94. {
  95. return $this->getOne("SELECT @@{$sName}");
  96. }
  97. /**
  98. * execute sql query and return one row result
  99. */
  100. function getRow($query, $arr_type = MYSQL_ASSOC)
  101. {
  102. if(!$query)
  103. return array();
  104. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM && $arr_type != MYSQL_BOTH)
  105. $arr_type = MYSQL_ASSOC;
  106. $res = $this->res ($query);
  107. $arr_res = array();
  108. if($res && mysql_num_rows($res))
  109. {
  110. $arr_res = mysql_fetch_array($res, $arr_type);
  111. mysql_free_result($res);
  112. }
  113. return $arr_res;
  114. }
  115. /**
  116. * execute sql query and return a column as result
  117. */
  118. function getColumn($sQuery) {
  119. if(!$sQuery)
  120. return array();
  121. $rResult = $this->res($sQuery);
  122. $aResult = array();
  123. if($rResult) {
  124. while($aRow = mysql_fetch_array($rResult, MYSQL_NUM))
  125. $aResult[] = $aRow[0];
  126. mysql_free_result($rResult);
  127. }
  128. return $aResult;
  129. }
  130. /**
  131. * execute sql query and return one value result
  132. */
  133. function getOne($query, $index = 0)
  134. {
  135. if(!$query)
  136. return false;
  137. $res = $this->res ($query);
  138. $arr_res = array();
  139. if($res && mysql_num_rows($res))
  140. $arr_res = mysql_fetch_array($res);
  141. if(count($arr_res))
  142. return $arr_res[$index];
  143. else
  144. return false;
  145. }
  146. /**
  147. * execute sql query and return the first row of result
  148. * and keep $array type and poiter to all data
  149. */
  150. function getFirstRow($query, $arr_type = MYSQL_ASSOC)
  151. {
  152. if(!$query)
  153. return array();
  154. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM)
  155. $this->current_arr_type = MYSQL_ASSOC;
  156. else
  157. $this->current_arr_type = $arr_type;
  158. $this->current_res = $this->res ($query);
  159. $arr_res = array();
  160. if($this->current_res && mysql_num_rows($this->current_res))
  161. $arr_res = mysql_fetch_array($this->current_res, $this->current_arr_type);
  162. return $arr_res;
  163. }
  164. /**
  165. * return next row of pointed last getFirstRow calling data
  166. */
  167. function getNextRow()
  168. {
  169. $arr_res = mysql_fetch_array($this->current_res, $this->current_arr_type);
  170. if($arr_res)
  171. return $arr_res;
  172. else
  173. {
  174. mysql_free_result($this->current_res);
  175. $this->current_arr_type = MYSQL_ASSOC;
  176. return array();
  177. }
  178. }
  179. /**
  180. * return number of affected rows in current mysql result
  181. */
  182. function getNumRows($res = false)
  183. {
  184. if ($res)
  185. return (int)@mysql_num_rows($res);
  186. elseif (!$this->current_res)
  187. return (int)@mysql_num_rows($this->current_res);
  188. else
  189. return 0;
  190. }
  191. /**
  192. * execute any query return number of rows affected/false
  193. */
  194. function getAffectedRows()
  195. {
  196. return mysql_affected_rows($this->link);
  197. }
  198. /**
  199. * execute any query return number of rows affected/false
  200. */
  201. function query($query)
  202. {
  203. $res = $this->res($query);
  204. if ($res)
  205. return mysql_affected_rows($this->link);
  206. return false;
  207. }
  208. /**
  209. * execute any query
  210. */
  211. function res($query, $error_checking = true)
  212. {
  213. if(!$query)
  214. return false;
  215. if (isset($GLOBALS['bx_profiler'])) $GLOBALS['bx_profiler']->beginQuery($query);
  216. $res = @mysql_query($query, $this->link);
  217. if (false === $res)
  218. $this->error_message = @mysql_error($this->link); // we need to remeber last error message since mysql_ping will reset it on the next line !
  219. else
  220. $this->error_message = '';
  221. if (false === $res && !@mysql_ping($this->link)) { // if mysql connection is lost - reconnect and try again
  222. @mysql_close($this->link);
  223. $this->connect();
  224. $res = mysql_query($query, $this->link);
  225. }
  226. if (isset($GLOBALS['bx_profiler'])) $GLOBALS['bx_profiler']->endQuery($res);
  227. if (!$res)
  228. $this->error('Database query error', false, $query);
  229. return $res;
  230. }
  231. /**
  232. * execute sql query and return table of records as result
  233. */
  234. function getAll($query, $arr_type = MYSQL_ASSOC)
  235. {
  236. if(!$query)
  237. return array();
  238. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM && $arr_type != MYSQL_BOTH)
  239. $arr_type = MYSQL_ASSOC;
  240. $res = $this->res ($query);
  241. $arr_res = array();
  242. if($res)
  243. {
  244. while($row = mysql_fetch_array($res, $arr_type))
  245. $arr_res[] = $row;
  246. mysql_free_result($res);
  247. }
  248. return $arr_res;
  249. }
  250. /**
  251. * execute sql query and return table of records as result
  252. */
  253. function fillArray($res, $arr_type = MYSQL_ASSOC)
  254. {
  255. if(!$res)
  256. return array();
  257. if($arr_type != MYSQL_ASSOC && $arr_type != MYSQL_NUM && $arr_type != MYSQL_BOTH)
  258. $arr_type = MYSQL_ASSOC;
  259. $arr_res = array();
  260. while($row = mysql_fetch_array($res, $arr_type))
  261. $arr_res[] = $row;
  262. mysql_free_result($res);
  263. return $arr_res;
  264. }
  265. /**
  266. * execute sql query and return table of records as result
  267. */
  268. function getAllWithKey($query, $sFieldKey)
  269. {
  270. if(!$query)
  271. return array();
  272. $res = $this->res ($query);
  273. $arr_res = array();
  274. if($res)
  275. {
  276. while($row = mysql_fetch_array($res, MYSQL_ASSOC))
  277. {
  278. $arr_res[$row[$sFieldKey]] = $row;
  279. }
  280. mysql_free_result($res);
  281. }
  282. return $arr_res;
  283. }
  284. /**
  285. * execute sql query and return table of records as result
  286. */
  287. function getPairs($query, $sFieldKey, $sFieldValue, $arr_type = MYSQL_ASSOC)
  288. {
  289. if(!$query)
  290. return array();
  291. $res = $this->res ($query);
  292. $arr_res = array();
  293. if($res)
  294. {
  295. while($row = mysql_fetch_array($res, MYSQL_ASSOC))
  296. {
  297. $arr_res[$row[$sFieldKey]] = $row[$sFieldValue];
  298. }
  299. mysql_free_result($res);
  300. }
  301. return $arr_res;
  302. }
  303. function lastId()
  304. {
  305. return mysql_insert_id($this->link);
  306. }
  307. function getErrorMessage () {
  308. $s = mysql_error($this->link);
  309. if ($s)
  310. return $s;
  311. else
  312. return $this->error_message;
  313. }
  314. function error($text, $isForceErrorChecking = false, $sSqlQuery = '')
  315. {
  316. if ($this->error_checking || $isForceErrorChecking)
  317. $this->genMySQLErr ($text, $sSqlQuery);
  318. else
  319. $this->log($text.': ' . $this->getErrorMessage());
  320. }
  321. function isParam($sName, $bCache = true) {
  322. return $this->oParams->exists($sName, $bCache);
  323. }
  324. function addParam($sName, $sValue, $iKateg, $sDesc, $sType) {
  325. return $this->oParams->add($sName, $sValue, $iKateg, $sDesc, $sType);
  326. }
  327. function getParam($sName, $bCache = true) {
  328. return $this->oParams->get($sName, $bCache);
  329. }
  330. function setParam($sName, $sValue ) {
  331. $this->oParams->set($sName, $sValue);
  332. return true;
  333. }
  334. function listTables() {
  335. return mysql_list_tables($GLOBALS['db']['db'], $this->link);
  336. //return mysql_list_tables($GLOBALS['db']['db'], $this->link) or $this->error('Database get encoding error');
  337. }
  338. function getFields($sTable) {
  339. $rFields = mysql_list_fields($this->dbname, $sTable, $this->link);
  340. $iFields = mysql_num_fields($rFields);
  341. $aResult = array('original' => array(), 'uppercase' => array());
  342. for($i = 0; $i < $iFields; $i++) {
  343. $sName = mysql_field_name($rFields, $i);
  344. $aResult['original'][] = $sName;
  345. $aResult['uppercase'][] = strtoupper($sName);
  346. }
  347. return $aResult;
  348. }
  349. function isFieldExists($sTable, $sFieldName) {
  350. $aFields = $this->getFields($sTable);
  351. return in_array(strtoupper($sFieldName), $aFields['uppercase']);
  352. }
  353. function getEncoding() {
  354. return mysql_client_encoding($this->link) or $this->error('Database get encoding error');
  355. }
  356. function genMySQLErr( $out, $query ='' ) {
  357. $sParamsOutput = false;
  358. $sFoundError = '';
  359. $aBackTrace = debug_backtrace();
  360. unset( $aBackTrace[0] );
  361. if( $query )
  362. {
  363. //try help to find error
  364. $aFoundError = array();
  365. foreach( $aBackTrace as $aCall )
  366. {
  367. // truncating global settings since it repeated many times and output it separately
  368. if (isset($aCall['object']) && property_exists($aCall['object'], 'oParams') && property_exists($aCall['object']->oParams, '_aParams')) {
  369. if (false === $sParamsOutput)
  370. $sParamsOutput = var_export($aCall['object']->oParams->_aParams, true);
  371. $aCall['object']->oParams->_aParams = '[truncated]';
  372. }
  373. if (isset($aCall['args']) && is_array($aCall['args']))
  374. {
  375. foreach( $aCall['args'] as $argNum => $argVal )
  376. {
  377. if( is_string($argVal) and strcmp( $argVal, $query ) == 0 )
  378. {
  379. $aFoundError['file'] = isset($aCall['file']) ? $aCall['file'] : (isset($aCall['class']) ? 'class: ' . $aCall['class'] : 'undefined');
  380. $aFoundError['line'] = isset($aCall['line']) ? $aCall['line'] : 'undefined';
  381. $aFoundError['function'] = $aCall['function'];
  382. $aFoundError['arg'] = $argNum;
  383. }
  384. }
  385. }
  386. }
  387. if( $aFoundError )
  388. {
  389. $sFoundError = <<<EOJ
  390. Found error in the file '<b>{$aFoundError['file']}</b>' at line <b>{$aFoundError['line']}</b>.<br />
  391. Called '<b>{$aFoundError['function']}</b>' function with erroneous argument #<b>{$aFoundError['arg']}</b>.<br /><br />
  392. EOJ;
  393. }
  394. }
  395. bx_import('BxDolConfig');
  396. if (BxDolConfig::getInstance()->get('db', 'visual_processing')) {
  397. ?>
  398. <div style="border:2px solid red;padding:4px;width:600px;margin:0px auto;">
  399. <div style="text-align:center;background-color:red;color:white;font-weight:bold;">Error</div>
  400. <div style="text-align:center;"><?=$out?></div>
  401. <?
  402. if(BxDolConfig::getInstance()->get('db', 'debug_mode')) {
  403. if( strlen( $query ) )
  404. echo "<div><b>Query:</b><br />{$query}</div>";
  405. if ($this->link)
  406. echo '<div><b>Mysql error:</b><br />' . $this->getErrorMessage() . '</div>';
  407. echo '<div style="overflow:scroll;height:300px;border:1px solid gray;">';
  408. echo $sFoundError;
  409. echo "<b>Debug backtrace:</b><br />";
  410. $sBackTrace = print_r($aBackTrace, true);
  411. $sBackTrace = str_replace('[password] => ' . BX_DATABASE_PASS, '[password] => *****', $sBackTrace);
  412. $sBackTrace = str_replace('[user] => ' . BX_DATABASE_USER, '[user] => *****', $sBackTrace);
  413. echo '<pre>' . $sBackTrace . '</pre>';
  414. if ($sParamsOutput) {
  415. echo '<hr />';
  416. echo "<b>Settings:</b><br />";
  417. echo '<pre>' . htmlspecialchars_adv($sParamsOutput) . '</pre>';
  418. }
  419. echo "<b>Called script:</b> " . $_SERVER['PHP_SELF'] . "<br />";
  420. echo "<b>Request parameters:</b><br />";
  421. echoDbg( $_REQUEST );
  422. echo '</div>';
  423. }
  424. ?>
  425. </div>
  426. <?
  427. }
  428. else
  429. echo $out;
  430. if(BxDolConfig::getInstance()->get('db', 'error_remort_by_email')) {
  431. $sSiteTitle = getParam('site_title');
  432. $sMailBody = "Database error in " . $sSiteTitle . "<br /><br /> \n";
  433. if( strlen( $query ) )
  434. $sMailBody .= "Query: <pre>" . htmlspecialchars_adv($query) . "</pre> ";
  435. if ($this->link)
  436. $sMailBody .= "Mysql error: " . $this->getErrorMessage() . "<br /><br /> ";
  437. $sMailBody .= $sFoundError. '<br /> ';
  438. $sBackTrace = print_r($aBackTrace, true);
  439. $sBackTrace = str_replace('[password] => ' . BX_DATABASE_PASS, '[password] => *****', $sBackTrace);
  440. $sBackTrace = str_replace('[user] => ' . BX_DATABASE_USER, '[user] => *****', $sBackTrace);
  441. $sMailBody .= "Debug backtrace:\n <pre>" . htmlspecialchars_adv($sBackTrace) . "</pre> ";
  442. if ($sParamsOutput)
  443. $sMailBody .= "<hr />Settings:\n <pre>" . htmlspecialchars_adv($sParamsOutput) . "</pre> ";
  444. $sMailBody .= "<hr />Called script: " . $_SERVER['PHP_SELF'] . "<br /> ";
  445. $sMailBody .= "<hr />Request parameters: <pre>" . print_r( $_REQUEST, true ) . " </pre>";
  446. $sMailBody .= "--\nAuto-report system\n";
  447. sendMail(getParam('site_email_bug_report'), "Database error in " . $sSiteTitle, $sMailBody, 0, array(), BX_EMAIL_SYSTEM, 'html', true);
  448. }
  449. exit;
  450. }
  451. function setErrorChecking ($b) {
  452. $this->error_checking = $b;
  453. }
  454. function getDbCacheObject () {
  455. if ($this->oDbCacheObject != null) {
  456. return $this->oDbCacheObject;
  457. } else {
  458. $sEngine = getParam('sys_db_cache_engine');
  459. $this->oDbCacheObject = bx_instance ('BxDolCache'.$sEngine);
  460. if (!$this->oDbCacheObject->isAvailable())
  461. $this->oDbCacheObject = bx_instance ('BxDolCacheFile');
  462. return $this->oDbCacheObject;
  463. }
  464. }
  465. function genDbCacheKey ($sName) {
  466. return 'db_' . $sName . '_' . md5(BX_DOL_VERSION . BX_DOL_BUILD . BX_DOL_URL_ROOT) . '.php';
  467. }
  468. function fromCache ($sName, $sFunc) {
  469. $aArgs = func_get_args();
  470. array_shift ($aArgs); // shift $sName
  471. array_shift ($aArgs); // shift $sFunc
  472. if (!getParam('sys_db_cache_enable'))
  473. return call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  474. $oCache = $this->getDbCacheObject ();
  475. $sKey = $this->genDbCacheKey($sName);
  476. $mixedRet = $oCache->getData($sKey);
  477. if ($mixedRet !== null) {
  478. return $mixedRet;
  479. } else {
  480. $mixedRet = call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  481. $oCache->setData($sKey, $mixedRet);
  482. }
  483. return $mixedRet;
  484. }
  485. function cleanCache ($sName) {
  486. if (!getParam('sys_db_cache_enable'))
  487. return true;
  488. $oCache = $this->getDbCacheObject ();
  489. $sKey = $this->genDbCacheKey($sName);
  490. return $oCache->delData($sKey);
  491. }
  492. function & fromMemory ($sName, $sFunc) {
  493. if (array_key_exists($sName, $GLOBALS['gl_db_cache'])) {
  494. return $GLOBALS['gl_db_cache'][$sName];
  495. } else {
  496. $aArgs = func_get_args();
  497. array_shift ($aArgs); // shift $sName
  498. array_shift ($aArgs); // shift $sFunc
  499. $GLOBALS['gl_db_cache'][$sName] = call_user_func_array (array ($this, $sFunc), $aArgs); // pass other function parameters as database function parameters
  500. return $GLOBALS['gl_db_cache'][$sName];
  501. }
  502. }
  503. function cleanMemory ($sName) {
  504. if (isset($GLOBALS['gl_db_cache'][$sName])) {
  505. unset($GLOBALS['gl_db_cache'][$sName]);
  506. return true;
  507. }
  508. return false;
  509. }
  510. /**
  511. * It escapes string to pass to mysql query.
  512. * Try to use "prepare" function always (@see BxDolDb::prepare), use "escape" only if "prepare" function is not possible at all.
  513. * Also consider using "implode_escape" function (@see BxDolDb::implode_escape).
  514. *
  515. * @param string $s string to escape
  516. * @return escaped string whcich is ready to pass to SQL query.
  517. */
  518. function escape ($s) {
  519. return mysql_real_escape_string($s);
  520. }
  521. /**
  522. * This function is usefull when you need to form array of parameters to pass to IN(...) SQL construction.
  523. * Example:
  524. * @code
  525. * $a = array(2, 4.5, 'apple', 'car');
  526. * $s = "SELECT * FROM `t` WHERE `a` IN (" . $oDb->implode_escape($a) . ")";
  527. * echo $s; // outputs: SELECT * FROM `t` WHERE `a` IN (2, 4.5, 'apple', 'car')
  528. * @endcode
  529. *
  530. * @param $mixed array or parameters or just one paramter
  531. * @return string which is ready to pass to IN(...) SQL construction
  532. */
  533. function implode_escape ($mixed) {
  534. if (is_array($mixed)) {
  535. $s = '';
  536. foreach ($mixed as $v)
  537. $s .= (is_numeric($v) ? $v : "'" . mysql_real_escape_string($v) . "'") . ',';
  538. if ($s)
  539. return substr($s, 0, -1);
  540. else
  541. return 'NULL';
  542. }
  543. return is_numeric($mixed) ? $mixed : ($mixed ? "'" . mysql_real_escape_string($mixed) . "'" : 'NULL');
  544. }
  545. /**
  546. * @deprecated
  547. */
  548. function unescape ($mixed) {
  549. if (is_array($mixed)) {
  550. foreach ($mixed as $k => $v)
  551. $mixed[$k] = $this->getOne("SELECT '$v'");
  552. return $mixed;
  553. } else {
  554. return $this->getOne("SELECT '$mixed'");
  555. }
  556. }
  557. /**
  558. * Prepare SQL query before execution if some arguments are need to be passed to it.
  559. * All parameters marked with question (?) symbol in SQL query are replaced with parameters passed after SQL query parameter.
  560. * Parameters are properly excaped and surrounded by qutes if needed.
  561. * Example:
  562. * @code
  563. * $sSql = $oDb->prepare("SELECT `a`, `b` from `t` WHERE `c` = ? and `d` = ?", 12, 'aa');
  564. * echo $sSql;// outputs: SELECT `a`, `b` from `t` WHERE `c` = 12 and `d` = 'aa'
  565. * $a = $oDb->getAll($sSql);
  566. * @endcode
  567. *
  568. * @param string $sQuery SQL query, parameters for replacing are marked with ? symbol
  569. * @param mixed $mixed any number if parameters to replace, number of parameters whould match number of ? symbols in SQL query
  570. * @return string with SQL query ready for execution
  571. */
  572. function prepare ($sQuery) {
  573. $aArgs = func_get_args();
  574. $sQuery = array_shift($aArgs);
  575. $iPos = 0;
  576. foreach ($aArgs as $mixedArg) {
  577. if (is_null($mixedArg))
  578. $s = 'NULL';
  579. elseif (is_numeric($mixedArg))
  580. $s = $mixedArg;
  581. else
  582. $s = "'" . mysql_real_escape_string($mixedArg) . "'";
  583. $i = bx_mb_strpos($sQuery, '?', $iPos);
  584. $sQuery = bx_mb_substr_replace($sQuery, $s, $i, 1);
  585. $iPos = $i + get_mb_len($s);
  586. }
  587. return $sQuery;
  588. }
  589. function log ($s) {
  590. return file_put_contents(BX_DIRECTORY_PATH_ROOT . 'tmp/db.err.log', date('Y-m-d H:i:s') . "\t" . $s . "\n", FILE_APPEND);
  591. }
  592. }
  593. /** @} */