PageRenderTime 60ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/textpattern/lib/txplib_db.php

https://github.com/nope/textpattern
PHP | 505 lines | 392 code | 68 blank | 45 comment | 55 complexity | d3513237a8b5ec5df85cba92c4cf13cd MD5 | raw file
  1. <?php
  2. /*
  3. $HeadURL$
  4. $LastChangedRevision$
  5. */
  6. if (!defined('PFX')) {
  7. if (!empty($txpcfg['table_prefix'])) {
  8. define ("PFX",$txpcfg['table_prefix']);
  9. } else define ("PFX",'');
  10. }
  11. if (version_compare(PHP_VERSION, '5.3.0') < 0)
  12. {
  13. // We are deliberately using a deprecated function for PHP 4 compatibility
  14. if (get_magic_quotes_runtime())
  15. {
  16. set_magic_quotes_runtime(0);
  17. }
  18. }
  19. class DB {
  20. function DB()
  21. {
  22. global $txpcfg;
  23. $this->host = $txpcfg['host'];
  24. $this->db = $txpcfg['db'];
  25. $this->user = $txpcfg['user'];
  26. $this->pass = $txpcfg['pass'];
  27. $this->client_flags = isset($txpcfg['client_flags']) ? $txpcfg['client_flags'] : 0;
  28. $this->link = @mysql_connect($this->host, $this->user, $this->pass, false, $this->client_flags);
  29. if (!$this->link) die(db_down());
  30. $this->version = mysql_get_server_info();
  31. if (!$this->link) {
  32. $GLOBALS['connected'] = false;
  33. } else $GLOBALS['connected'] = true;
  34. @mysql_select_db($this->db) or die(db_down());
  35. $version = $this->version;
  36. // be backwardscompatible
  37. if ( isset($txpcfg['dbcharset']) && (intval($version[0]) >= 5 || preg_match('#^4\.[1-9]#',$version)) )
  38. mysql_query("SET NAMES ". $txpcfg['dbcharset']);
  39. }
  40. }
  41. $DB = new DB;
  42. //-------------------------------------------------------------
  43. function safe_pfx($table) {
  44. $name = PFX.$table;
  45. if (preg_match('@[^\w._$]@', $name))
  46. return '`'.$name.'`';
  47. return $name;
  48. }
  49. //-------------------------------------------------------------
  50. function safe_pfx_j($table)
  51. {
  52. $ts = array();
  53. foreach (explode(',', $table) as $t) {
  54. $name = PFX.trim($t);
  55. if (preg_match('@[^\w._$]@', $name))
  56. $ts[] = "`$name`".(PFX ? " as `$t`" : '');
  57. else
  58. $ts[] = "$name".(PFX ? " as $t" : '');
  59. }
  60. return join(', ', $ts);
  61. }
  62. //-------------------------------------------------------------
  63. function safe_query($q='',$debug='',$unbuf='')
  64. {
  65. global $DB, $txpcfg, $qcount, $qtime, $production_status;
  66. $method = (!$unbuf) ? 'mysql_query' : 'mysql_unbuffered_query';
  67. if (!$q) return false;
  68. if ($debug or TXP_DEBUG === 1) dmp($q);
  69. $start = getmicrotime();
  70. $result = $method($q,$DB->link);
  71. $time = getmicrotime() - $start;
  72. @$qtime += $time;
  73. @$qcount++;
  74. if ($result === false and (txpinterface === 'admin' or @$production_status == 'debug' or @$production_status == 'testing')) {
  75. $caller = ($production_status == 'debug') ? n . join("\n", get_caller()) : '';
  76. trigger_error(mysql_error() . n . $q . $caller, E_USER_WARNING);
  77. }
  78. trace_add("[SQL ($time): $q]");
  79. if(!$result) return false;
  80. return $result;
  81. }
  82. // -------------------------------------------------------------
  83. function safe_delete($table, $where, $debug='')
  84. {
  85. $q = "delete from ".safe_pfx($table)." where $where";
  86. if ($r = safe_query($q,$debug)) {
  87. return true;
  88. }
  89. return false;
  90. }
  91. // -------------------------------------------------------------
  92. function safe_update($table, $set, $where, $debug='')
  93. {
  94. $q = "update ".safe_pfx($table)." set $set where $where";
  95. if ($r = safe_query($q,$debug)) {
  96. return true;
  97. }
  98. return false;
  99. }
  100. // -------------------------------------------------------------
  101. function safe_insert($table,$set,$debug='')
  102. {
  103. global $DB;
  104. $q = "insert into ".safe_pfx($table)." set $set";
  105. if ($r = safe_query($q,$debug)) {
  106. $id = mysql_insert_id($DB->link);
  107. return ($id === 0 ? true : $id);
  108. }
  109. return false;
  110. }
  111. // -------------------------------------------------------------
  112. // insert or update
  113. function safe_upsert($table,$set,$where,$debug='')
  114. {
  115. // FIXME: lock the table so this is atomic?
  116. $r = safe_update($table, $set, $where, $debug);
  117. if ($r and (mysql_affected_rows() or safe_count($table, $where, $debug)))
  118. return $r;
  119. else
  120. return safe_insert($table, join(', ', array($where, $set)), $debug);
  121. }
  122. // -------------------------------------------------------------
  123. function safe_alter($table, $alter, $debug='')
  124. {
  125. $q = "alter table ".safe_pfx($table)." $alter";
  126. if ($r = safe_query($q,$debug)) {
  127. return true;
  128. }
  129. return false;
  130. }
  131. // -------------------------------------------------------------
  132. function safe_optimize($table, $debug='')
  133. {
  134. $q = "optimize table ".safe_pfx($table)."";
  135. if ($r = safe_query($q,$debug)) {
  136. return true;
  137. }
  138. return false;
  139. }
  140. // -------------------------------------------------------------
  141. function safe_repair($table, $debug='')
  142. {
  143. $q = "repair table ".safe_pfx($table)."";
  144. if ($r = safe_query($q,$debug)) {
  145. return true;
  146. }
  147. return false;
  148. }
  149. // -------------------------------------------------------------
  150. function safe_field($thing, $table, $where, $debug='')
  151. {
  152. $q = "select $thing from ".safe_pfx_j($table)." where $where";
  153. $r = safe_query($q,$debug);
  154. if (@mysql_num_rows($r) > 0) {
  155. $f = mysql_result($r,0);
  156. mysql_free_result($r);
  157. return $f;
  158. }
  159. return false;
  160. }
  161. // -------------------------------------------------------------
  162. function safe_column($thing, $table, $where, $debug='')
  163. {
  164. $q = "select $thing from ".safe_pfx_j($table)." where $where";
  165. $rs = getRows($q,$debug);
  166. if ($rs) {
  167. foreach($rs as $a) {
  168. $v = array_shift($a);
  169. $out[$v] = $v;
  170. }
  171. return $out;
  172. }
  173. return array();
  174. }
  175. // -------------------------------------------------------------
  176. function safe_row($things, $table, $where, $debug='')
  177. {
  178. $q = "select $things from ".safe_pfx_j($table)." where $where";
  179. $rs = getRow($q,$debug);
  180. if ($rs) {
  181. return $rs;
  182. }
  183. return array();
  184. }
  185. // -------------------------------------------------------------
  186. function safe_rows($things, $table, $where, $debug='')
  187. {
  188. $q = "select $things from ".safe_pfx_j($table)." where $where";
  189. $rs = getRows($q,$debug);
  190. if ($rs) {
  191. return $rs;
  192. }
  193. return array();
  194. }
  195. // -------------------------------------------------------------
  196. function safe_rows_start($things, $table, $where, $debug='')
  197. {
  198. $q = "select $things from ".safe_pfx_j($table)." where $where";
  199. return startRows($q,$debug);
  200. }
  201. //-------------------------------------------------------------
  202. function safe_count($table, $where, $debug='')
  203. {
  204. return getThing("select count(*) from ".safe_pfx_j($table)." where $where",$debug);
  205. }
  206. // -------------------------------------------------------------
  207. function safe_show($thing, $table, $debug='')
  208. {
  209. $q = "show $thing from ".safe_pfx($table)."";
  210. $rs = getRows($q,$debug);
  211. if ($rs) {
  212. return $rs;
  213. }
  214. return array();
  215. }
  216. //-------------------------------------------------------------
  217. function fetch($col,$table,$key,$val,$debug='')
  218. {
  219. $key = doSlash($key);
  220. $val = (is_int($val)) ? $val : "'".doSlash($val)."'";
  221. $q = "select $col from ".safe_pfx($table)." where `$key` = $val limit 1";
  222. if ($r = safe_query($q,$debug)) {
  223. $thing = (mysql_num_rows($r) > 0) ? mysql_result($r,0) : '';
  224. mysql_free_result($r);
  225. return $thing;
  226. }
  227. return false;
  228. }
  229. //-------------------------------------------------------------
  230. function getRow($query,$debug='')
  231. {
  232. if ($r = safe_query($query,$debug)) {
  233. $row = (mysql_num_rows($r) > 0) ? mysql_fetch_assoc($r) : false;
  234. mysql_free_result($r);
  235. return $row;
  236. }
  237. return false;
  238. }
  239. //-------------------------------------------------------------
  240. function getRows($query,$debug='')
  241. {
  242. if ($r = safe_query($query,$debug)) {
  243. if (mysql_num_rows($r) > 0) {
  244. while ($a = mysql_fetch_assoc($r)) $out[] = $a;
  245. mysql_free_result($r);
  246. return $out;
  247. }
  248. }
  249. return false;
  250. }
  251. //-------------------------------------------------------------
  252. function startRows($query,$debug='')
  253. {
  254. return safe_query($query,$debug);
  255. }
  256. //-------------------------------------------------------------
  257. function nextRow($r)
  258. {
  259. $row = mysql_fetch_assoc($r);
  260. if ($row === false)
  261. mysql_free_result($r);
  262. return $row;
  263. }
  264. //-------------------------------------------------------------
  265. function numRows($r)
  266. {
  267. return mysql_num_rows($r);
  268. }
  269. //-------------------------------------------------------------
  270. function getThing($query,$debug='')
  271. {
  272. if ($r = safe_query($query,$debug)) {
  273. $thing = (mysql_num_rows($r) != 0) ? mysql_result($r,0) : '';
  274. mysql_free_result($r);
  275. return $thing;
  276. }
  277. return false;
  278. }
  279. //-------------------------------------------------------------
  280. function getThings($query,$debug='')
  281. // return values of one column from multiple rows in an num indexed array
  282. {
  283. $rs = getRows($query,$debug);
  284. if ($rs) {
  285. foreach($rs as $a) $out[] = array_shift($a);
  286. return $out;
  287. }
  288. return array();
  289. }
  290. //-------------------------------------------------------------
  291. function getCount($table,$where,$debug='')
  292. {
  293. return getThing("select count(*) from ".safe_pfx_j($table)." where $where",$debug);
  294. }
  295. // -------------------------------------------------------------
  296. function getTree($root, $type, $where='1=1', $tbl='txp_category')
  297. {
  298. $root = doSlash($root);
  299. $type = doSlash($type);
  300. $rs = safe_row(
  301. "lft as l, rgt as r",
  302. $tbl,
  303. "name='$root' and type = '$type'"
  304. );
  305. if (!$rs) return array();
  306. extract($rs);
  307. $out = array();
  308. $right = array();
  309. $rs = safe_rows_start(
  310. "id, name, lft, rgt, parent, title",
  311. $tbl,
  312. "lft between $l and $r and type = '$type' and name != 'root' and $where order by lft asc"
  313. );
  314. while ($rs and $row = nextRow($rs)) {
  315. extract($row);
  316. while (count($right) > 0 && $right[count($right)-1] < $rgt) {
  317. array_pop($right);
  318. }
  319. $out[] =
  320. array(
  321. 'id' => $id,
  322. 'name' => $name,
  323. 'title' => $title,
  324. 'level' => count($right),
  325. 'children' => ($rgt - $lft - 1) / 2,
  326. 'parent' => $parent
  327. );
  328. $right[] = $rgt;
  329. }
  330. return($out);
  331. }
  332. // -------------------------------------------------------------
  333. function getTreePath($target, $type, $tbl='txp_category')
  334. {
  335. $rs = safe_row(
  336. "lft as l, rgt as r",
  337. $tbl,
  338. "name='".doSlash($target)."' and type = '".doSlash($type)."'"
  339. );
  340. if (!$rs) return array();
  341. extract($rs);
  342. $rs = safe_rows_start(
  343. "*",
  344. $tbl,
  345. "lft <= $l and rgt >= $r and type = '".doSlash($type)."' order by lft asc"
  346. );
  347. $out = array();
  348. $right = array();
  349. while ($rs and $row = nextRow($rs)) {
  350. extract($row);
  351. while (count($right) > 0 && $right[count($right)-1] < $rgt) {
  352. array_pop($right);
  353. }
  354. $out[] =
  355. array(
  356. 'id' => $id,
  357. 'name' => $name,
  358. 'title' => $title,
  359. 'level' => count($right),
  360. 'children' => ($rgt - $lft - 1) / 2
  361. );
  362. $right[] = $rgt;
  363. }
  364. return $out;
  365. }
  366. // -------------------------------------------------------------
  367. function rebuild_tree($parent, $left, $type, $tbl='txp_category')
  368. {
  369. $left = assert_int($left);
  370. $right = $left+1;
  371. $parent = doSlash($parent);
  372. $type = doSlash($type);
  373. $result = safe_column("name", $tbl,
  374. "parent='$parent' and type='$type' order by name");
  375. foreach($result as $row) {
  376. $right = rebuild_tree($row, $right, $type, $tbl);
  377. }
  378. safe_update(
  379. $tbl,
  380. "lft=$left, rgt=$right",
  381. "name='$parent' and type='$type'"
  382. );
  383. return $right+1;
  384. }
  385. //-------------------------------------------------------------
  386. function rebuild_tree_full($type, $tbl='txp_category')
  387. {
  388. # fix circular references, otherwise rebuild_tree() could get stuck in a loop
  389. safe_update($tbl, "parent=''", "type='".doSlash($type)."' and name='root'");
  390. safe_update($tbl, "parent='root'", "type='".doSlash($type)."' and parent=name");
  391. rebuild_tree('root', 1, $type, $tbl);
  392. }
  393. //-------------------------------------------------------------
  394. function get_prefs()
  395. {
  396. global $txp_user;
  397. $out = array();
  398. // get current user's private prefs
  399. if ($txp_user) {
  400. $r = safe_rows_start('name, val', 'txp_prefs', 'prefs_id=1 AND user_name=\''.doSlash($txp_user).'\'');
  401. if ($r) {
  402. while ($a = nextRow($r)) {
  403. $out[$a['name']] = $a['val'];
  404. }
  405. }
  406. }
  407. // get global prefs, eventually override equally named user prefs.
  408. $r = safe_rows_start('name, val', 'txp_prefs', 'prefs_id=1 AND user_name=\'\'');
  409. if ($r) {
  410. while ($a = nextRow($r)) {
  411. $out[$a['name']] = $a['val'];
  412. }
  413. }
  414. return $out;
  415. }
  416. // -------------------------------------------------------------
  417. function db_down()
  418. {
  419. // 503 status might discourage search engines from indexing or caching the error message
  420. txp_status_header('503 Service Unavailable');
  421. $error = mysql_error();
  422. return <<<eod
  423. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  424. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  425. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  426. <head>
  427. <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  428. <title>Untitled</title>
  429. </head>
  430. <body>
  431. <p align="center" style="margin-top:4em">Database unavailable.</p>
  432. <!-- $error -->
  433. </body>
  434. </html>
  435. eod;
  436. }
  437. ?>