PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/textpattern/lib/txplib_db.php

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