PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/extensions/ezSQL/ez_sql_core.php

https://gitlab.com/fork/hotarucms
PHP | 702 lines | 402 code | 140 blank | 160 comment | 58 complexity | a32cec15b4fd769f6f548b866b5392ac MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**********************************************************************
  3. * Author: Justin Vincent (jv@vip.ie)
  4. * Web...: http://justinvincent.com
  5. * Name..: ezSQL
  6. * Desc..: ezSQL Core module - database abstraction library to make
  7. * it very easy to deal with databases. ezSQLcore can not be used by
  8. * itself (it is designed for use by database specific modules).
  9. *
  10. */
  11. /**********************************************************************
  12. * ezSQL Constants
  13. */
  14. define('EZSQL_VERSION','2.17');
  15. define('OBJECT','OBJECT',true);
  16. define('ARRAY_A','ARRAY_A',true);
  17. define('ARRAY_N','ARRAY_N',true);
  18. /**********************************************************************
  19. * Core class containg common functions to manipulate query result
  20. * sets once returned
  21. */
  22. class ezSQLcore
  23. {
  24. var $trace = false; // same as $debug_all
  25. var $debug_all = false; // same as $trace
  26. var $debug_called = false;
  27. var $vardump_called = false;
  28. var $show_errors = true;
  29. var $num_queries = 0;
  30. var $num_cache_queries= 0;
  31. var $last_query = null;
  32. var $last_error = null;
  33. var $col_info = null;
  34. var $captured_errors = array();
  35. var $cache_dir = false;
  36. var $cache_queries = false;
  37. var $cache_inserts = false;
  38. var $use_disk_cache = false;
  39. var $cache_timeout = 24; // hours
  40. var $timers = array();
  41. var $total_query_time = 0;
  42. var $db_connect_time = 0;
  43. var $trace_log = array();
  44. var $use_trace_log = false;
  45. var $sql_log_file = false;
  46. var $do_profile = false;
  47. var $profile_times = array();
  48. // == TJH == default now needed for echo of debug function
  49. var $debug_echo_is_on = true;
  50. /**********************************************************************
  51. * Constructor
  52. */
  53. function ezSQLcore()
  54. {
  55. }
  56. function register_error($err_str)
  57. {
  58. // Keep track of last error
  59. $this->last_error = $err_str;
  60. // Capture all errors to an error array no matter what happens
  61. $this->captured_errors[] = array
  62. (
  63. 'error_str' => $err_str,
  64. 'query' => $this->last_query
  65. );
  66. }
  67. /**********************************************************************
  68. * Turn error handling on or off..
  69. */
  70. function show_errors()
  71. {
  72. $this->show_errors = true;
  73. }
  74. function hide_errors()
  75. {
  76. $this->show_errors = false;
  77. }
  78. /**********************************************************************
  79. * Kill cached query results
  80. */
  81. function flush()
  82. {
  83. // Get rid of these
  84. $this->last_result = null;
  85. $this->col_info = null;
  86. $this->last_query = null;
  87. $this->from_disk_cache = false;
  88. }
  89. /**********************************************************************
  90. * Get one variable from the DB - see docs for more detail
  91. */
  92. function get_var($query=null,$x=0,$y=0)
  93. {
  94. // Log how the function was called
  95. $this->func_call = "\$db->get_var(\"$query\",$x,$y)";
  96. // If there is a query then perform it if not then use cached results..
  97. if ( $query )
  98. {
  99. $this->query($query);
  100. }
  101. // Extract var out of cached results based x,y vals
  102. if ( $this->last_result[$y] )
  103. {
  104. $values = array_values(get_object_vars($this->last_result[$y]));
  105. }
  106. // If there is a value return it else return null
  107. return (isset($values[$x]) && $values[$x]!=='')?$values[$x]:null;
  108. }
  109. /**********************************************************************
  110. * Get one row from the DB - see docs for more detail
  111. */
  112. function get_row($query=null,$output=OBJECT,$y=0)
  113. {
  114. // Log how the function was called
  115. $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
  116. // If there is a query then perform it if not then use cached results..
  117. if ( $query )
  118. {
  119. $this->query($query);
  120. }
  121. // If the output is an object then return object using the row offset..
  122. if ( $output == OBJECT )
  123. {
  124. return $this->last_result[$y]?$this->last_result[$y]:null;
  125. }
  126. // If the output is an associative array then return row as such..
  127. elseif ( $output == ARRAY_A )
  128. {
  129. return $this->last_result[$y]?get_object_vars($this->last_result[$y]):null;
  130. }
  131. // If the output is an numerical array then return row as such..
  132. elseif ( $output == ARRAY_N )
  133. {
  134. return $this->last_result[$y]?array_values(get_object_vars($this->last_result[$y])):null;
  135. }
  136. // If invalid output type was specified..
  137. else
  138. {
  139. $this->show_errors ? trigger_error(" \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N",E_USER_WARNING) : null;
  140. }
  141. }
  142. /**********************************************************************
  143. * Function to get 1 column from the cached result set based in X index
  144. * see docs for usage and info
  145. */
  146. function get_col($query=null,$x=0)
  147. {
  148. $new_array = array();
  149. // If there is a query then perform it if not then use cached results..
  150. if ( $query )
  151. {
  152. $this->query($query);
  153. }
  154. // Extract the column values
  155. for ( $i=0; $i < count($this->last_result); $i++ )
  156. {
  157. $new_array[$i] = $this->get_var(null,$x,$i);
  158. }
  159. return $new_array;
  160. }
  161. /**********************************************************************
  162. * Return the the query as a result set - see docs for more details
  163. */
  164. function get_results($query=null, $output = OBJECT)
  165. {
  166. // Log how the function was called
  167. $this->func_call = "\$db->get_results(\"$query\", $output)";
  168. // If there is a query then perform it if not then use cached results..
  169. if ( $query )
  170. {
  171. $this->query($query);
  172. }
  173. // Send back array of objects. Each row is an object
  174. if ( $output == OBJECT )
  175. {
  176. return $this->last_result;
  177. }
  178. elseif ( $output == ARRAY_A || $output == ARRAY_N )
  179. {
  180. if ( $this->last_result )
  181. {
  182. $i=0;
  183. foreach( $this->last_result as $row )
  184. {
  185. $new_array[$i] = get_object_vars($row);
  186. if ( $output == ARRAY_N )
  187. {
  188. $new_array[$i] = array_values($new_array[$i]);
  189. }
  190. $i++;
  191. }
  192. return $new_array;
  193. }
  194. else
  195. {
  196. return array();
  197. }
  198. }
  199. }
  200. /**********************************************************************
  201. * Function to get column meta data info pertaining to the last query
  202. * see docs for more info and usage
  203. */
  204. function get_col_info($info_type="name",$col_offset=-1)
  205. {
  206. if ( $this->col_info )
  207. {
  208. if ( $col_offset == -1 )
  209. {
  210. $i=0;
  211. foreach($this->col_info as $col )
  212. {
  213. $new_array[$i] = $col->{$info_type};
  214. $i++;
  215. }
  216. return $new_array;
  217. }
  218. else
  219. {
  220. return $this->col_info[$col_offset]->{$info_type};
  221. }
  222. }
  223. }
  224. /**********************************************************************
  225. * store_cache
  226. */
  227. function store_cache($query,$is_insert)
  228. {
  229. // The would be cache file for this query
  230. $cache_file = $this->cache_dir.'/'.md5($query);
  231. // disk caching of queries
  232. if ( $this->use_disk_cache && ( $this->cache_queries && ! $is_insert ) || ( $this->cache_inserts && $is_insert ))
  233. {
  234. if ( ! is_dir($this->cache_dir) )
  235. {
  236. $this->register_error("Could not open cache dir: $this->cache_dir");
  237. $this->show_errors ? trigger_error("Could not open cache dir: $this->cache_dir",E_USER_WARNING) : null;
  238. }
  239. else
  240. {
  241. // Cache all result values
  242. $result_cache = array
  243. (
  244. 'col_info' => $this->col_info,
  245. 'last_result' => $this->last_result,
  246. 'num_rows' => $this->num_rows,
  247. 'return_value' => $this->num_rows,
  248. );
  249. file_put_contents($cache_file, serialize($result_cache));
  250. if( file_exists($cache_file . ".updating") )
  251. unlink($cache_file . ".updating");
  252. }
  253. }
  254. }
  255. /**********************************************************************
  256. * get_cache
  257. */
  258. function get_cache($query)
  259. {
  260. // The would be cache file for this query
  261. $cache_file = $this->cache_dir.'/'.md5($query);
  262. // Try to get previously cached version
  263. if ( $this->use_disk_cache && file_exists($cache_file) )
  264. {
  265. // Only use this cache file if less than 'cache_timeout' (hours)
  266. if ( (time() - filemtime($cache_file)) > ($this->cache_timeout*3600) &&
  267. !(file_exists($cache_file . ".updating") && (time() - filemtime($cache_file . ".updating") < 60)) )
  268. {
  269. touch($cache_file . ".updating"); // Show that we in the process of updating the cache
  270. }
  271. else
  272. {
  273. $result_cache = unserialize(file_get_contents($cache_file));
  274. $this->col_info = $result_cache['col_info'];
  275. $this->last_result = $result_cache['last_result'];
  276. $this->num_rows = $result_cache['num_rows'];
  277. $this->from_disk_cache = true;
  278. // If debug ALL queries
  279. $this->trace || $this->debug_all ? $this->debug() : null ;
  280. return $result_cache['return_value'];
  281. }
  282. }
  283. }
  284. /**********************************************************************
  285. * Dumps the contents of any input variable to screen in a nicely
  286. * formatted and easy to understand way - any type: Object, Var or Array
  287. */
  288. function vardump($mixed='')
  289. {
  290. // Start outup buffering
  291. ob_start();
  292. echo "<p><table><tr><td bgcolor=ffffff><blockquote><font color=000090>";
  293. echo "<pre><font face=arial>";
  294. if ( ! $this->vardump_called )
  295. {
  296. echo "<font color=800080><b>ezSQL</b> (v".EZSQL_VERSION.") <b>Variable Dump..</b></font>\n\n";
  297. }
  298. $var_type = gettype ($mixed);
  299. print_r(($mixed?$mixed:"<font color=red>No Value / False</font>"));
  300. echo "\n\n<b>Type:</b> " . ucfirst($var_type) . "\n";
  301. echo "<b>Last Query</b> [$this->num_queries]<b>:</b> ".($this->last_query?$this->last_query:"NULL")."\n";
  302. echo "<b>Last Function Call:</b> " . ($this->func_call?$this->func_call:"None")."\n";
  303. echo "<b>Last Rows Returned:</b> ".count($this->last_result)."\n";
  304. echo "</font></pre></font></blockquote></td></tr></table>".$this->donation();
  305. echo "\n<hr size=1 noshade color=dddddd>";
  306. // Stop output buffering and capture debug HTML
  307. $html = ob_get_contents();
  308. ob_end_clean();
  309. // Only echo output if it is turned on
  310. if ( $this->debug_echo_is_on )
  311. {
  312. echo $html;
  313. }
  314. $this->vardump_called = true;
  315. return $html;
  316. }
  317. /**********************************************************************
  318. * Alias for the above function
  319. */
  320. function dumpvar($mixed)
  321. {
  322. $this->vardump($mixed);
  323. }
  324. /**********************************************************************
  325. * Displays the last query string that was sent to the database & a
  326. * table listing results (if there were any).
  327. * (abstracted into a seperate file to save server overhead).
  328. */
  329. function debug($print_to_screen=true)
  330. {
  331. // Start outup buffering
  332. ob_start();
  333. echo "<blockquote>";
  334. // Only show ezSQL credits once..
  335. if ( ! $this->debug_called )
  336. {
  337. echo "<font color=800080 face=arial size=2><b>ezSQL</b> (v".EZSQL_VERSION.") <b>Debug..</b></font><p>\n";
  338. }
  339. if ( $this->last_error )
  340. {
  341. echo "<font face=arial size=2 color=000099><b>Last Error --</b> [<font color=000000><b>$this->last_error</b></font>]<p>";
  342. }
  343. if ( $this->from_disk_cache )
  344. {
  345. echo "<font face=arial size=2 color=000099><b>Results retrieved from disk cache</b></font><p>";
  346. }
  347. echo "<font face=arial size=2 color=000099><b>Query</b> [$this->num_queries] <b>--</b> ";
  348. echo "[<font color=000000><b>$this->last_query</b></font>]</font><p>";
  349. echo "<font face=arial size=2 color=000099><b>Query Result..</b></font>";
  350. echo "<blockquote>";
  351. if ( $this->col_info )
  352. {
  353. // =====================================================
  354. // Results top rows
  355. echo "<table cellpadding=5 cellspacing=1 bgcolor=555555>";
  356. echo "<tr bgcolor=eeeeee><td nowrap valign=bottom><font color=555599 face=arial size=2><b>(row)</b></font></td>";
  357. for ( $i=0; $i < count($this->col_info); $i++ )
  358. {
  359. echo "<td nowrap align=left valign=top><font size=1 color=555599 face=arial>{$this->col_info[$i]->type} {$this->col_info[$i]->max_length}</font><br><span style='font-family: arial; font-size: 10pt; font-weight: bold;'>{$this->col_info[$i]->name}</span></td>";
  360. }
  361. echo "</tr>";
  362. // ======================================================
  363. // print main results
  364. if ( $this->last_result )
  365. {
  366. $i=0;
  367. foreach ( $this->get_results(null,ARRAY_N) as $one_row )
  368. {
  369. $i++;
  370. echo "<tr bgcolor=ffffff><td bgcolor=eeeeee nowrap align=middle><font size=2 color=555599 face=arial>$i</font></td>";
  371. foreach ( $one_row as $item )
  372. {
  373. echo "<td nowrap><font face=arial size=2>$item</font></td>";
  374. }
  375. echo "</tr>";
  376. }
  377. } // if last result
  378. else
  379. {
  380. echo "<tr bgcolor=ffffff><td colspan=".(count($this->col_info)+1)."><font face=arial size=2>No Results</font></td></tr>";
  381. }
  382. echo "</table>";
  383. } // if col_info
  384. else
  385. {
  386. echo "<font face=arial size=2>No Results</font>";
  387. }
  388. echo "</blockquote></blockquote>".$this->donation()."<hr noshade color=dddddd size=1>";
  389. // Stop output buffering and capture debug HTML
  390. $html = ob_get_contents();
  391. ob_end_clean();
  392. // Only echo output if it is turned on
  393. if ( $this->debug_echo_is_on && $print_to_screen)
  394. {
  395. echo $html;
  396. }
  397. $this->debug_called = true;
  398. return $html;
  399. }
  400. /**********************************************************************
  401. * Naughty little function to ask for some remuniration!
  402. */
  403. function donation()
  404. {
  405. return "<font size=1 face=arial color=000000>If ezSQL has helped <a href=\"https://www.paypal.com/xclick/business=justin%40justinvincent.com&item_name=ezSQL&no_note=1&tax=0\" style=\"color: 0000CC;\">make a donation!?</a> &nbsp;&nbsp;<!--[ go on! you know you want to! ]--></font>";
  406. }
  407. /**********************************************************************
  408. * Timer related functions
  409. */
  410. function timer_get_cur()
  411. {
  412. list($usec, $sec) = explode(" ",microtime());
  413. return ((float)$usec + (float)$sec);
  414. }
  415. function timer_start($timer_name)
  416. {
  417. $this->timers[$timer_name] = $this->timer_get_cur();
  418. }
  419. function timer_elapsed($timer_name)
  420. {
  421. return round($this->timer_get_cur() - $this->timers[$timer_name],2);
  422. }
  423. function timer_update_global($timer_name)
  424. {
  425. if ( $this->do_profile )
  426. {
  427. $this->profile_times[] = array
  428. (
  429. 'query' => $this->last_query,
  430. 'time' => $this->timer_elapsed($timer_name)
  431. );
  432. }
  433. $this->total_query_time += $this->timer_elapsed($timer_name);
  434. }
  435. /**********************************************************************
  436. * Creates a SET nvp sql string from an associative array (and escapes all values)
  437. *
  438. * Usage:
  439. *
  440. * $db_data = array('login'=>'jv','email'=>'jv@vip.ie', 'user_id' => 1, 'created' => 'NOW()');
  441. *
  442. * $db->query("INSERT INTO users SET ".$db->get_set($db_data));
  443. *
  444. * ...OR...
  445. *
  446. * $db->query("UPDATE users SET ".$db->get_set($db_data)." WHERE user_id = 1");
  447. *
  448. * Output:
  449. *
  450. * login = 'jv', email = 'jv@vip.ie', user_id = 1, created = NOW()
  451. */
  452. function get_set($params)
  453. {
  454. if( !is_array( $params ) )
  455. {
  456. $this->register_error( 'get_set() parameter invalid. Expected array in '.__FILE__.' on line '.__LINE__);
  457. return;
  458. }
  459. $sql = array();
  460. foreach ( $params as $field => $val )
  461. {
  462. if ( $val === 'true' || $val === true )
  463. $val = 1;
  464. if ( $val === 'false' || $val === false )
  465. $val = 0;
  466. switch( $val ){
  467. case 'NOW()' :
  468. case 'NULL' :
  469. $sql[] = "$field = $val";
  470. break;
  471. default :
  472. $sql[] = "$field = '".$this->escape( $val )."'";
  473. }
  474. }
  475. return implode( ', ' , $sql );
  476. }
  477. /**********************************************************************
  478. * Prepares a SQL query for safe use, using sprintf() syntax.
  479. *
  480. * Added for Hotaru
  481. *
  482. * @link http://php.net/sprintf See for syntax to use for query string.
  483. * @since 2.3.0
  484. *
  485. * @param null|string $args If string, first parameter must be query statement
  486. * @param mixed $args, If additional parameters, they will be set inserted into the query.
  487. * @return null|string Sanitized query string
  488. */
  489. function escape_by_ref(&$s)
  490. {
  491. $s = $this->escape($s);
  492. }
  493. function prepare($args=null)
  494. {
  495. if (is_null( $args ))
  496. return;
  497. $args = func_get_args();
  498. // This is a Hotaru hack, enabling args to be built on the fly.
  499. if(is_array($args[0]))
  500. {
  501. // See Submit plugin: class.post.php get_posts() for an example.
  502. $args = $args[0];
  503. }
  504. $query = array_shift($args);
  505. // in case someone mistakenly already singlequoted it
  506. $query = str_replace("'%s'", '%s', $query);
  507. $query = str_replace('"%s"', '%s', $query); // doublequote unquoting
  508. $query = str_replace('%s', "'%s'", $query); // quote the strings
  509. array_walk($args, array(&$this, 'escape_by_ref'));
  510. return @vsprintf($query, $args);
  511. }
  512. /**
  513. * Check if table exists
  514. *
  515. * @param string $table2check
  516. * @return bool
  517. *
  518. * Notes: This is a custom function for Hotaru CMS
  519. */
  520. function table_exists($table2check) {
  521. $tables = $this->get_col("SHOW TABLES",0);
  522. if (in_array(DB_PREFIX . $table2check, $tables)) { return true; }
  523. return false;
  524. }
  525. /**
  526. * Check if table empty
  527. *
  528. * @param string $table2check
  529. * @return bool
  530. *
  531. * Notes: This is a custom function for Hotaru CMS
  532. */
  533. function table_empty($table2check) {
  534. $rowcount = $this->get_var($this->prepare("SELECT COUNT(*) FROM " . DB_PREFIX . $table2check));
  535. if($rowcount && $rowcount > 0) {
  536. return false; // table not empty
  537. } else {
  538. return true; // table is empty
  539. }
  540. }
  541. /**
  542. * Check if table column exists
  543. *
  544. * @param string $table2check
  545. * @param string $column
  546. * @return bool
  547. *
  548. * Notes: This is a custom function for Hotaru CMS
  549. */
  550. function column_exists($table2check, $column)
  551. {
  552. $sql = "SHOW COLUMNS FROM " . DB_PREFIX . $table2check;
  553. foreach ($this->get_col($sql,0) as $column_name)
  554. {
  555. if ($column_name == $column) {
  556. return true;
  557. }
  558. }
  559. return false;
  560. }
  561. }
  562. ?>