db_prefs.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. <?php
  2. /**
  3. * db_prefs.php
  4. *
  5. * This contains functions for manipulating user preferences
  6. * stored in a database, accessed through the Pear DB layer
  7. * or PDO, the latter taking precedence if available.
  8. *
  9. * Database:
  10. *
  11. * The preferences table should have three columns:
  12. * user char \ primary
  13. * prefkey char / key
  14. * prefval blob
  15. *
  16. * CREATE TABLE userprefs (user CHAR(128) NOT NULL DEFAULT '',
  17. * prefkey CHAR(64) NOT NULL DEFAULT '',
  18. * prefval BLOB NOT NULL DEFAULT '',
  19. * primary key (user,prefkey));
  20. *
  21. * Configuration of databasename, username and password is done
  22. * by using conf.pl or the administrator plugin
  23. *
  24. * Three settings that control PDO behavior can be specified in
  25. * config/config_local.php if needed:
  26. * boolean $disable_pdo SquirrelMail uses PDO by default to access the
  27. * user preferences and address book databases, but
  28. * setting this to TRUE will cause SquirrelMail to
  29. * fall back to using Pear DB instead.
  30. * boolean $pdo_show_sql_errors When database errors are encountered,
  31. * setting this to TRUE causes the actual
  32. * database error to be displayed, otherwise
  33. * generic errors are displayed, preventing
  34. * internal database information from being
  35. * exposed. This should be enabled only for
  36. * debugging purposes.
  37. * string $pdo_identifier_quote_char By default, SquirrelMail will quote
  38. * table and field names in database
  39. * queries with what it thinks is the
  40. * appropriate quote character for the
  41. * database type being used (backtick
  42. * for MySQL (and thus MariaDB), double
  43. * quotes for all others), but you can
  44. * override the character used by
  45. * putting it here, or tell SquirrelMail
  46. * NOT to quote identifiers by setting
  47. * this to "none"
  48. *
  49. * @copyright 1999-2015 The SquirrelMail Project Team
  50. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  51. * @version $Id$
  52. * @package squirrelmail
  53. * @subpackage prefs
  54. * @since 1.1.3
  55. */
  56. /** @ignore */
  57. if (!defined('SM_PATH')) define('SM_PATH','../');
  58. /** Unknown database */
  59. define('SMDB_UNKNOWN', 0);
  60. /** MySQL */
  61. define('SMDB_MYSQL', 1);
  62. /** PostgreSQL */
  63. define('SMDB_PGSQL', 2);
  64. /**
  65. * Needs either PDO or the DB functions
  66. * Don't display errors here. (no code execution in functions/*.php).
  67. * will handle error in dbPrefs class.
  68. */
  69. global $use_pdo, $disable_pdo;
  70. if (empty($disable_pdo) && class_exists('PDO'))
  71. $use_pdo = TRUE;
  72. else
  73. $use_pdo = FALSE;
  74. if (!$use_pdo)
  75. @include_once('DB.php');
  76. global $prefs_are_cached, $prefs_cache;
  77. /**
  78. * @ignore
  79. */
  80. function cachePrefValues($username) {
  81. global $prefs_are_cached, $prefs_cache;
  82. sqgetGlobalVar('prefs_are_cached', $prefs_are_cached, SQ_SESSION );
  83. if ($prefs_are_cached) {
  84. sqgetGlobalVar('prefs_cache', $prefs_cache, SQ_SESSION );
  85. return;
  86. }
  87. sqsession_unregister('prefs_cache');
  88. sqsession_unregister('prefs_are_cached');
  89. $db = new dbPrefs;
  90. if(isset($db->error)) {
  91. printf( _("Preference database error (%s). Exiting abnormally"),
  92. $db->error);
  93. exit;
  94. }
  95. $db->fillPrefsCache($username);
  96. if (isset($db->error)) {
  97. printf( _("Preference database error (%s). Exiting abnormally"),
  98. $db->error);
  99. exit;
  100. }
  101. $prefs_are_cached = true;
  102. sqsession_register($prefs_cache, 'prefs_cache');
  103. sqsession_register($prefs_are_cached, 'prefs_are_cached');
  104. }
  105. /**
  106. * Class used to handle connections to prefs database and operations with preferences
  107. *
  108. * @package squirrelmail
  109. * @subpackage prefs
  110. * @since 1.1.3
  111. *
  112. */
  113. class dbPrefs {
  114. /**
  115. * Table used to store preferences
  116. * @var string
  117. */
  118. var $table = 'userprefs';
  119. /**
  120. * Field used to store owner of preference
  121. * @var string
  122. */
  123. var $user_field = 'user';
  124. /**
  125. * Field used to store preference name
  126. * @var string
  127. */
  128. var $key_field = 'prefkey';
  129. /**
  130. * Field used to store preference value
  131. * @var string
  132. */
  133. var $val_field = 'prefval';
  134. /**
  135. * Database connection object
  136. * @var object
  137. */
  138. var $dbh = NULL;
  139. /**
  140. * Error messages
  141. * @var string
  142. */
  143. var $error = NULL;
  144. /**
  145. * Database type (SMDB_* constants)
  146. * Is used in setKey().
  147. * @var integer
  148. */
  149. var $db_type = SMDB_UNKNOWN;
  150. /**
  151. * Character used to quote database table
  152. * and field names
  153. * @var string
  154. */
  155. var $identifier_quote_char = '';
  156. /**
  157. * Default preferences
  158. * @var array
  159. */
  160. var $default = Array('theme_default' => 0,
  161. 'include_self_reply_all' => '0',
  162. 'do_not_reply_to_self' => '1',
  163. 'show_html_default' => '0');
  164. /**
  165. * Preference owner field size
  166. * @var integer
  167. * @since 1.5.1
  168. */
  169. var $user_size = 128;
  170. /**
  171. * Preference key field size
  172. * @var integer
  173. * @since 1.5.1
  174. */
  175. var $key_size = 64;
  176. /**
  177. * Preference value field size
  178. * @var integer
  179. * @since 1.5.1
  180. */
  181. var $val_size = 65536;
  182. /**
  183. * initialize the default preferences array.
  184. *
  185. */
  186. function dbPrefs() {
  187. // Try and read the default preferences file.
  188. $default_pref = SM_PATH . 'config/default_pref';
  189. if (@file_exists($default_pref)) {
  190. if ($file = @fopen($default_pref, 'r')) {
  191. while (!feof($file)) {
  192. $pref = fgets($file, 1024);
  193. $i = strpos($pref, '=');
  194. if ($i > 0) {
  195. $this->default[trim(substr($pref, 0, $i))] = trim(substr($pref, $i + 1));
  196. }
  197. }
  198. fclose($file);
  199. }
  200. }
  201. }
  202. /**
  203. * initialize DB connection object
  204. *
  205. * @return boolean true, if object is initialized
  206. *
  207. */
  208. function open() {
  209. global $prefs_dsn, $prefs_table, $use_pdo, $pdo_identifier_quote_char;
  210. global $prefs_user_field, $prefs_key_field, $prefs_val_field;
  211. global $prefs_user_size, $prefs_key_size, $prefs_val_size;
  212. /* test if PDO or Pear DB classes are available and freak out if necessary */
  213. if (!$use_pdo && !class_exists('DB')) {
  214. // same error also in abook_database.php
  215. $error = _("Could not find or include PHP PDO or PEAR database functions required for the database backend.") . "\n";
  216. $error .= sprintf(_("PDO should come preinstalled with PHP version 5.1 or higher. Otherwise, is PEAR installed, and is the include path set correctly to find %s?"), 'DB.php') . "\n";
  217. $error .= _("Please contact your system administrator and report this error.");
  218. return false;
  219. }
  220. if(isset($this->dbh)) {
  221. return true;
  222. }
  223. if (strpos($prefs_dsn, 'mysql') === 0) {
  224. $this->db_type = SMDB_MYSQL;
  225. } else if (strpos($prefs_dsn, 'pgsql') === 0) {
  226. $this->db_type = SMDB_PGSQL;
  227. }
  228. // figure out identifier quoting (only used for PDO, though we could change that)
  229. if (empty($pdo_identifier_quote_char)) {
  230. if ($this->db_type == SMDB_MYSQL)
  231. $this->identifier_quote_char = '`';
  232. else
  233. $this->identifier_quote_char = '"';
  234. } else if ($pdo_identifier_quote_char === 'none')
  235. $this->identifier_quote_char = '';
  236. else
  237. $this->identifier_quote_char = $pdo_identifier_quote_char;
  238. if (!empty($prefs_table)) {
  239. $this->table = $prefs_table;
  240. }
  241. if (!empty($prefs_user_field)) {
  242. $this->user_field = $prefs_user_field;
  243. }
  244. // the default user field is "user", which in PostgreSQL
  245. // is an identifier and causes errors if not escaped
  246. //
  247. if ($this->db_type == SMDB_PGSQL) {
  248. $this->user_field = '"' . $this->user_field . '"';
  249. }
  250. if (!empty($prefs_key_field)) {
  251. $this->key_field = $prefs_key_field;
  252. }
  253. if (!empty($prefs_val_field)) {
  254. $this->val_field = $prefs_val_field;
  255. }
  256. if (!empty($prefs_user_size)) {
  257. $this->user_size = (int) $prefs_user_size;
  258. }
  259. if (!empty($prefs_key_size)) {
  260. $this->key_size = (int) $prefs_key_size;
  261. }
  262. if (!empty($prefs_val_size)) {
  263. $this->val_size = (int) $prefs_val_size;
  264. }
  265. // connect, create database connection object
  266. //
  267. if ($use_pdo) {
  268. // parse and convert DSN to PDO style
  269. // Pear's full DSN syntax is one of the following:
  270. // phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value
  271. // phptype(syntax)://user:pass@protocol(proto_opts)/database
  272. //
  273. // $matches will contain:
  274. // 1: database type
  275. // 2: username
  276. // 3: password
  277. // 4: hostname (and possible port number) OR protocol (and possible protocol options)
  278. // 5: database name (and possible options)
  279. // 6: port number (moved from match number 4)
  280. // 7: options (moved from match number 5)
  281. // 8: protocol (instead of hostname)
  282. // 9: protocol options (moved from match number 4/8)
  283. //TODO: do we care about supporting cases where no password is given? (this is a legal DSN, but causes an error below)
  284. if (!preg_match('|^(.+)://(.+):(.+)@(.+)/(.+)$|i', $prefs_dsn, $matches)) {
  285. $this->error = _("Could not parse prefs DSN");
  286. return false;
  287. }
  288. $matches[6] = NULL;
  289. $matches[7] = NULL;
  290. $matches[8] = NULL;
  291. $matches[9] = NULL;
  292. if (preg_match('|^(.+):(\d+)$|', $matches[4], $host_port_matches)) {
  293. $matches[4] = $host_port_matches[1];
  294. $matches[6] = $host_port_matches[2];
  295. }
  296. if (preg_match('|^(.+?)\((.+)\)$|', $matches[4], $protocol_matches)) {
  297. $matches[8] = $protocol_matches[1];
  298. $matches[9] = $protocol_matches[2];
  299. $matches[4] = NULL;
  300. $matches[6] = NULL;
  301. }
  302. //TODO: currently we just ignore options specified on the end of the DSN
  303. if (preg_match('|^(.+?)\?(.+)$|', $matches[5], $database_name_options_matches)) {
  304. $matches[5] = $database_name_options_matches[1];
  305. $matches[7] = $database_name_options_matches[2];
  306. }
  307. if ($matches[8] === 'unix' && !empty($matches[9]))
  308. $pdo_prefs_dsn = $matches[1] . ':unix_socket=' . $matches[9] . ';dbname=' . $matches[5];
  309. else
  310. $pdo_prefs_dsn = $matches[1] . ':host=' . $matches[4] . (!empty($matches[6]) ? ';port=' . $matches[6] : '') . ';dbname=' . $matches[5];
  311. try {
  312. $dbh = new PDO($pdo_prefs_dsn, $matches[2], $matches[3]);
  313. } catch (Exception $e) {
  314. $this->error = $e->getMessage();
  315. return false;
  316. }
  317. } else {
  318. $dbh = DB::connect($prefs_dsn, true);
  319. if(DB::isError($dbh)) {
  320. $this->error = DB::errorMessage($dbh);
  321. return false;
  322. }
  323. }
  324. $this->dbh = $dbh;
  325. return true;
  326. }
  327. /**
  328. * Function used to handle database connection errors
  329. *
  330. * @param object PEAR Error object
  331. *
  332. */
  333. function failQuery($res = NULL) {
  334. global $use_pdo;
  335. if($res == NULL) {
  336. printf(_("Preference database error (%s). Exiting abnormally"),
  337. $this->error);
  338. } else {
  339. printf(_("Preference database error (%s). Exiting abnormally"),
  340. ($use_pdo ? implode(' - ', $res->errorInfo()) : DB::errorMessage($res)));
  341. }
  342. exit;
  343. }
  344. /**
  345. * Get user's prefs setting
  346. *
  347. * @param string $user user name
  348. * @param string $key preference name
  349. * @param mixed $default (since 1.2.5) default value
  350. *
  351. * @return mixed preference value
  352. *
  353. */
  354. function getKey($user, $key, $default = '') {
  355. global $prefs_cache;
  356. $temp = array(&$user, &$key);
  357. $result = do_hook('get_pref_override', $temp);
  358. if (is_null($result)) {
  359. cachePrefValues($user);
  360. if (isset($prefs_cache[$key])) {
  361. $result = $prefs_cache[$key];
  362. } else {
  363. //FIXME: is there a justification for having two prefs hooks so close? who uses them?
  364. $temp = array(&$user, &$key);
  365. $result = do_hook('get_pref', $temp);
  366. if (is_null($result)) {
  367. if (isset($this->default[$key])) {
  368. $result = $this->default[$key];
  369. } else {
  370. $result = $default;
  371. }
  372. }
  373. }
  374. }
  375. return $result;
  376. }
  377. /**
  378. * Delete user's prefs setting
  379. *
  380. * @param string $user user name
  381. * @param string $key preference name
  382. *
  383. * @return boolean
  384. *
  385. */
  386. function deleteKey($user, $key) {
  387. global $prefs_cache, $use_pdo, $pdo_show_sql_errors;
  388. if (!$this->open()) {
  389. return false;
  390. }
  391. if ($use_pdo) {
  392. if (!($sth = $this->dbh->prepare('DELETE FROM ' . $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' . $this->identifier_quote_char . $this->user_field . $this->identifier_quote_char . ' = ? AND ' . $this->identifier_quote_char . $this->key_field . $this->identifier_quote_char . ' = ?'))) {
  393. if ($pdo_show_sql_errors)
  394. $this->error = implode(' - ', $this->dbh->errorInfo());
  395. else
  396. $this->error = _("Could not prepare query");
  397. $this->failQuery();
  398. }
  399. if (!($res = $sth->execute(array($user, $key)))) {
  400. if ($pdo_show_sql_errors)
  401. $this->error = implode(' - ', $sth->errorInfo());
  402. else
  403. $this->error = _("Could not execute query");
  404. $this->failQuery();
  405. }
  406. } else {
  407. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  408. $this->table,
  409. $this->user_field,
  410. $this->dbh->quoteString($user),
  411. $this->key_field,
  412. $this->dbh->quoteString($key));
  413. $res = $this->dbh->simpleQuery($query);
  414. if(DB::isError($res)) {
  415. $this->failQuery($res);
  416. }
  417. }
  418. unset($prefs_cache[$key]);
  419. return true;
  420. }
  421. /**
  422. * Set user's preference
  423. *
  424. * @param string $user user name
  425. * @param string $key preference name
  426. * @param mixed $value preference value
  427. *
  428. * @return boolean
  429. *
  430. */
  431. function setKey($user, $key, $value) {
  432. global $use_pdo, $pdo_show_sql_errors;
  433. if (!$this->open()) {
  434. return false;
  435. }
  436. /**
  437. * Check if username fits into db field
  438. */
  439. if (strlen($user) > $this->user_size) {
  440. $this->error = "Oversized username value."
  441. ." Your preferences can't be saved."
  442. ." See the administrator's manual or contact your system administrator.";
  443. /**
  444. * Debugging function. Can be used to log all issues that trigger
  445. * oversized field errors. Function should be enabled in all three
  446. * strlen checks. See http://www.php.net/error-log
  447. */
  448. // error_log($user.'|'.$key.'|'.$value."\n",3,'/tmp/oversized_log');
  449. // error is fatal
  450. $this->failQuery(null);
  451. }
  452. /**
  453. * Check if preference key fits into db field
  454. */
  455. if (strlen($key) > $this->key_size) {
  456. $err_msg = "Oversized user's preference key."
  457. ." Some preferences were not saved."
  458. ." See the administrator's manual or contact your system administrator.";
  459. // error is not fatal. Only some preference is not saved.
  460. trigger_error($err_msg,E_USER_WARNING);
  461. return false;
  462. }
  463. /**
  464. * Check if preference value fits into db field
  465. */
  466. if (strlen($value) > $this->val_size) {
  467. $err_msg = "Oversized user's preference value."
  468. ." Some preferences were not saved."
  469. ." See the administrator's manual or contact your system administrator.";
  470. // error is not fatal. Only some preference is not saved.
  471. trigger_error($err_msg,E_USER_WARNING);
  472. return false;
  473. }
  474. if ($this->db_type == SMDB_MYSQL) {
  475. if ($use_pdo) {
  476. if (!($sth = $this->dbh->prepare('REPLACE INTO ' . $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' (' . $this->identifier_quote_char . $this->user_field . $this->identifier_quote_char . ', ' . $this->identifier_quote_char . $this->key_field . $this->identifier_quote_char . ', ' . $this->identifier_quote_char . $this->val_field . $this->identifier_quote_char . ') VALUES (?, ?, ?)'))) {
  477. if ($pdo_show_sql_errors)
  478. $this->error = implode(' - ', $this->dbh->errorInfo());
  479. else
  480. $this->error = _("Could not prepare query");
  481. $this->failQuery();
  482. }
  483. if (!($res = $sth->execute(array($user, $key, $value)))) {
  484. if ($pdo_show_sql_errors)
  485. $this->error = implode(' - ', $sth->errorInfo());
  486. else
  487. $this->error = _("Could not execute query");
  488. $this->failQuery();
  489. }
  490. } else {
  491. $query = sprintf("REPLACE INTO %s (%s, %s, %s) ".
  492. "VALUES('%s','%s','%s')",
  493. $this->table,
  494. $this->user_field,
  495. $this->key_field,
  496. $this->val_field,
  497. $this->dbh->quoteString($user),
  498. $this->dbh->quoteString($key),
  499. $this->dbh->quoteString($value));
  500. $res = $this->dbh->simpleQuery($query);
  501. if(DB::isError($res)) {
  502. $this->failQuery($res);
  503. }
  504. }
  505. } elseif ($this->db_type == SMDB_PGSQL) {
  506. if ($use_pdo) {
  507. if ($this->dbh->exec('BEGIN TRANSACTION') === FALSE) {
  508. if ($pdo_show_sql_errors)
  509. $this->error = implode(' - ', $this->dbh->errorInfo());
  510. else
  511. $this->error = _("Could not execute query");
  512. $this->failQuery();
  513. }
  514. if (!($sth = $this->dbh->prepare('DELETE FROM ' . $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' . $this->identifier_quote_char . $this->user_field . $this->identifier_quote_char . ' = ? AND ' . $this->identifier_quote_char . $this->key_field . $this->identifier_quote_char . ' = ?'))) {
  515. if ($pdo_show_sql_errors)
  516. $this->error = implode(' - ', $this->dbh->errorInfo());
  517. else
  518. $this->error = _("Could not prepare query");
  519. $this->failQuery();
  520. }
  521. if (!($res = $sth->execute(array($user, $key)))) {
  522. if ($pdo_show_sql_errors)
  523. $this->error = implode(' - ', $sth->errorInfo());
  524. else
  525. $this->error = _("Could not execute query");
  526. $this->dbh->exec('ROLLBACK TRANSACTION');
  527. $this->failQuery();
  528. }
  529. if (!($sth = $this->dbh->prepare('INSERT INTO ' . $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' (' . $this->identifier_quote_char . $this->user_field . $this->identifier_quote_char . ', ' . $this->identifier_quote_char . $this->key_field . $this->identifier_quote_char . ', ' . $this->identifier_quote_char . $this->val_field . $this->identifier_quote_char . ') VALUES (?, ?, ?)'))) {
  530. if ($pdo_show_sql_errors)
  531. $this->error = implode(' - ', $this->dbh->errorInfo());
  532. else
  533. $this->error = _("Could not prepare query");
  534. $this->failQuery();
  535. }
  536. if (!($res = $sth->execute(array($user, $key, $value)))) {
  537. if ($pdo_show_sql_errors)
  538. $this->error = implode(' - ', $sth->errorInfo());
  539. else
  540. $this->error = _("Could not execute query");
  541. $this->dbh->exec('ROLLBACK TRANSACTION');
  542. $this->failQuery();
  543. }
  544. if ($this->dbh->exec('COMMIT TRANSACTION') === FALSE) {
  545. if ($pdo_show_sql_errors)
  546. $this->error = implode(' - ', $this->dbh->errorInfo());
  547. else
  548. $this->error = _("Could not execute query");
  549. $this->failQuery();
  550. }
  551. } else {
  552. $this->dbh->simpleQuery("BEGIN TRANSACTION");
  553. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  554. $this->table,
  555. $this->user_field,
  556. $this->dbh->quoteString($user),
  557. $this->key_field,
  558. $this->dbh->quoteString($key));
  559. $res = $this->dbh->simpleQuery($query);
  560. if (DB::isError($res)) {
  561. $this->dbh->simpleQuery("ROLLBACK TRANSACTION");
  562. $this->failQuery($res);
  563. }
  564. $query = sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
  565. $this->table,
  566. $this->user_field,
  567. $this->key_field,
  568. $this->val_field,
  569. $this->dbh->quoteString($user),
  570. $this->dbh->quoteString($key),
  571. $this->dbh->quoteString($value));
  572. $res = $this->dbh->simpleQuery($query);
  573. if (DB::isError($res)) {
  574. $this->dbh->simpleQuery("ROLLBACK TRANSACTION");
  575. $this->failQuery($res);
  576. }
  577. $this->dbh->simpleQuery("COMMIT TRANSACTION");
  578. }
  579. } else {
  580. if ($use_pdo) {
  581. if (!($sth = $this->dbh->prepare('DELETE FROM ' . $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' . $this->identifier_quote_char . $this->user_field . $this->identifier_quote_char . ' = ? AND ' . $this->identifier_quote_char . $this->key_field . $this->identifier_quote_char . ' = ?'))) {
  582. if ($pdo_show_sql_errors)
  583. $this->error = implode(' - ', $this->dbh->errorInfo());
  584. else
  585. $this->error = _("Could not prepare query");
  586. $this->failQuery();
  587. }
  588. if (!($res = $sth->execute(array($user, $key)))) {
  589. if ($pdo_show_sql_errors)
  590. $this->error = implode(' - ', $sth->errorInfo());
  591. else
  592. $this->error = _("Could not execute query");
  593. $this->failQuery();
  594. }
  595. if (!($sth = $this->dbh->prepare('INSERT INTO ' . $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' (' . $this->identifier_quote_char . $this->user_field . $this->identifier_quote_char . ', ' . $this->identifier_quote_char . $this->key_field . $this->identifier_quote_char . ', ' . $this->identifier_quote_char . $this->val_field . $this->identifier_quote_char . ') VALUES (?, ?, ?)'))) {
  596. if ($pdo_show_sql_errors)
  597. $this->error = implode(' - ', $this->dbh->errorInfo());
  598. else
  599. $this->error = _("Could not prepare query");
  600. $this->failQuery();
  601. }
  602. if (!($res = $sth->execute(array($user, $key, $value)))) {
  603. if ($pdo_show_sql_errors)
  604. $this->error = implode(' - ', $sth->errorInfo());
  605. else
  606. $this->error = _("Could not execute query");
  607. $this->failQuery();
  608. }
  609. } else {
  610. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  611. $this->table,
  612. $this->user_field,
  613. $this->dbh->quoteString($user),
  614. $this->key_field,
  615. $this->dbh->quoteString($key));
  616. $res = $this->dbh->simpleQuery($query);
  617. if (DB::isError($res)) {
  618. $this->failQuery($res);
  619. }
  620. $query = sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
  621. $this->table,
  622. $this->user_field,
  623. $this->key_field,
  624. $this->val_field,
  625. $this->dbh->quoteString($user),
  626. $this->dbh->quoteString($key),
  627. $this->dbh->quoteString($value));
  628. $res = $this->dbh->simpleQuery($query);
  629. if (DB::isError($res)) {
  630. $this->failQuery($res);
  631. }
  632. }
  633. }
  634. return true;
  635. }
  636. /**
  637. * Fill preference cache array
  638. *
  639. * @param string $user user name
  640. *
  641. * @since 1.2.3
  642. *
  643. */
  644. function fillPrefsCache($user) {
  645. global $prefs_cache, $use_pdo, $pdo_show_sql_errors;
  646. if (!$this->open()) {
  647. return;
  648. }
  649. $prefs_cache = array();
  650. if ($use_pdo) {
  651. if (!($sth = $this->dbh->prepare('SELECT ' . $this->identifier_quote_char . $this->key_field . $this->identifier_quote_char . ' AS prefkey, ' . $this->identifier_quote_char . $this->val_field . $this->identifier_quote_char . ' AS prefval FROM ' . $this->identifier_quote_char . $this->table . $this->identifier_quote_char . ' WHERE ' . $this->identifier_quote_char . $this->user_field . $this->identifier_quote_char . ' = ?'))) {
  652. if ($pdo_show_sql_errors)
  653. $this->error = implode(' - ', $this->dbh->errorInfo());
  654. else
  655. $this->error = _("Could not prepare query");
  656. $this->failQuery();
  657. }
  658. if (!($res = $sth->execute(array($user)))) {
  659. if ($pdo_show_sql_errors)
  660. $this->error = implode(' - ', $sth->errorInfo());
  661. else
  662. $this->error = _("Could not execute query");
  663. $this->failQuery();
  664. }
  665. while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
  666. $prefs_cache[$row['prefkey']] = $row['prefval'];
  667. }
  668. } else {
  669. $query = sprintf("SELECT %s as prefkey, %s as prefval FROM %s ".
  670. "WHERE %s = '%s'",
  671. $this->key_field,
  672. $this->val_field,
  673. $this->table,
  674. $this->user_field,
  675. $this->dbh->quoteString($user));
  676. $res = $this->dbh->query($query);
  677. if (DB::isError($res)) {
  678. $this->failQuery($res);
  679. }
  680. while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  681. $prefs_cache[$row['prefkey']] = $row['prefval'];
  682. }
  683. }
  684. }
  685. } /* end class dbPrefs */
  686. /**
  687. * Returns the value for the requested preference
  688. * @ignore
  689. */
  690. function getPref($data_dir, $username, $pref_name, $default = '') {
  691. $db = new dbPrefs;
  692. if(isset($db->error)) {
  693. printf( _("Preference database error (%s). Exiting abnormally"),
  694. $db->error);
  695. exit;
  696. }
  697. return $db->getKey($username, $pref_name, $default);
  698. }
  699. /**
  700. * Remove the desired preference setting ($pref_name)
  701. * @ignore
  702. */
  703. function removePref($data_dir, $username, $pref_name) {
  704. global $prefs_cache;
  705. $db = new dbPrefs;
  706. if(isset($db->error)) {
  707. $db->failQuery();
  708. }
  709. $db->deleteKey($username, $pref_name);
  710. if (isset($prefs_cache[$pref_name])) {
  711. unset($prefs_cache[$pref_name]);
  712. }
  713. sqsession_register($prefs_cache , 'prefs_cache');
  714. return;
  715. }
  716. /**
  717. * Sets the desired preference setting ($pref_name) to whatever is in $value
  718. * @ignore
  719. */
  720. function setPref($data_dir, $username, $pref_name, $value) {
  721. global $prefs_cache;
  722. if (isset($prefs_cache[$pref_name]) && ($prefs_cache[$pref_name] == $value)) {
  723. return;
  724. }
  725. if ($value === '') {
  726. removePref($data_dir, $username, $pref_name);
  727. return;
  728. }
  729. $db = new dbPrefs;
  730. if(isset($db->error)) {
  731. $db->failQuery();
  732. }
  733. $db->setKey($username, $pref_name, $value);
  734. $prefs_cache[$pref_name] = $value;
  735. assert_options(ASSERT_ACTIVE, 1);
  736. assert_options(ASSERT_BAIL, 1);
  737. assert ('$value == $prefs_cache[$pref_name]');
  738. sqsession_register($prefs_cache , 'prefs_cache');
  739. return;
  740. }
  741. /**
  742. * This checks if the prefs are available
  743. * @ignore
  744. */
  745. function checkForPrefs($data_dir, $username) {
  746. $db = new dbPrefs;
  747. if(isset($db->error)) {
  748. $db->failQuery();
  749. }
  750. }
  751. /**
  752. * Writes the Signature
  753. * @ignore
  754. */
  755. function setSig($data_dir, $username, $number, $value) {
  756. if ($number == "g") {
  757. $key = '___signature___';
  758. } else {
  759. $key = sprintf('___sig%s___', $number);
  760. }
  761. setPref($data_dir, $username, $key, $value);
  762. return;
  763. }
  764. /**
  765. * Gets the signature
  766. * @ignore
  767. */
  768. function getSig($data_dir, $username, $number) {
  769. if ($number == "g") {
  770. $key = '___signature___';
  771. } else {
  772. $key = sprintf('___sig%d___', $number);
  773. }
  774. return getPref($data_dir, $username, $key);
  775. }