db_prefs.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  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-2017 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. * Constructor (PHP5 style, required in some future version of PHP)
  184. * initialize the default preferences array.
  185. *
  186. */
  187. function __construct() {
  188. // Try and read the default preferences file.
  189. $default_pref = SM_PATH . 'config/default_pref';
  190. if (@file_exists($default_pref)) {
  191. if ($file = @fopen($default_pref, 'r')) {
  192. while (!feof($file)) {
  193. $pref = fgets($file, 1024);
  194. $i = strpos($pref, '=');
  195. if ($i > 0) {
  196. $this->default[trim(substr($pref, 0, $i))] = trim(substr($pref, $i + 1));
  197. }
  198. }
  199. fclose($file);
  200. }
  201. }
  202. }
  203. /**
  204. * Constructor (PHP4 style, kept for compatibility reasons)
  205. * initialize the default preferences array.
  206. *
  207. */
  208. function dbPrefs() {
  209. self::__construct();
  210. }
  211. /**
  212. * initialize DB connection object
  213. *
  214. * @return boolean true, if object is initialized
  215. *
  216. */
  217. function open() {
  218. global $prefs_dsn, $prefs_table, $use_pdo, $pdo_identifier_quote_char;
  219. global $prefs_user_field, $prefs_key_field, $prefs_val_field;
  220. global $prefs_user_size, $prefs_key_size, $prefs_val_size;
  221. /* test if PDO or Pear DB classes are available and freak out if necessary */
  222. if (!$use_pdo && !class_exists('DB')) {
  223. // same error also in abook_database.php
  224. $error = _("Could not find or include PHP PDO or PEAR database functions required for the database backend.") . "\n";
  225. $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";
  226. $error .= _("Please contact your system administrator and report this error.");
  227. return false;
  228. }
  229. if(isset($this->dbh)) {
  230. return true;
  231. }
  232. if (strpos($prefs_dsn, 'mysql') === 0) {
  233. $this->db_type = SMDB_MYSQL;
  234. } else if (strpos($prefs_dsn, 'pgsql') === 0) {
  235. $this->db_type = SMDB_PGSQL;
  236. }
  237. // figure out identifier quoting (only used for PDO, though we could change that)
  238. if (empty($pdo_identifier_quote_char)) {
  239. if ($this->db_type == SMDB_MYSQL)
  240. $this->identifier_quote_char = '`';
  241. else
  242. $this->identifier_quote_char = '"';
  243. } else if ($pdo_identifier_quote_char === 'none')
  244. $this->identifier_quote_char = '';
  245. else
  246. $this->identifier_quote_char = $pdo_identifier_quote_char;
  247. if (!empty($prefs_table)) {
  248. $this->table = $prefs_table;
  249. }
  250. if (!empty($prefs_user_field)) {
  251. $this->user_field = $prefs_user_field;
  252. }
  253. // the default user field is "user", which in PostgreSQL
  254. // is an identifier and causes errors if not escaped
  255. //
  256. if ($this->db_type == SMDB_PGSQL) {
  257. $this->user_field = '"' . $this->user_field . '"';
  258. }
  259. if (!empty($prefs_key_field)) {
  260. $this->key_field = $prefs_key_field;
  261. }
  262. if (!empty($prefs_val_field)) {
  263. $this->val_field = $prefs_val_field;
  264. }
  265. if (!empty($prefs_user_size)) {
  266. $this->user_size = (int) $prefs_user_size;
  267. }
  268. if (!empty($prefs_key_size)) {
  269. $this->key_size = (int) $prefs_key_size;
  270. }
  271. if (!empty($prefs_val_size)) {
  272. $this->val_size = (int) $prefs_val_size;
  273. }
  274. // connect, create database connection object
  275. //
  276. if ($use_pdo) {
  277. // parse and convert DSN to PDO style
  278. // Pear's full DSN syntax is one of the following:
  279. // phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value
  280. // phptype(syntax)://user:pass@protocol(proto_opts)/database
  281. //
  282. // $matches will contain:
  283. // 1: database type
  284. // 2: username
  285. // 3: password
  286. // 4: hostname (and possible port number) OR protocol (and possible protocol options)
  287. // 5: database name (and possible options)
  288. // 6: port number (moved from match number 4)
  289. // 7: options (moved from match number 5)
  290. // 8: protocol (instead of hostname)
  291. // 9: protocol options (moved from match number 4/8)
  292. //TODO: do we care about supporting cases where no password is given? (this is a legal DSN, but causes an error below)
  293. if (!preg_match('|^(.+)://(.+):(.+)@(.+)/(.+)$|i', $prefs_dsn, $matches)) {
  294. $this->error = _("Could not parse prefs DSN");
  295. return false;
  296. }
  297. $matches[6] = NULL;
  298. $matches[7] = NULL;
  299. $matches[8] = NULL;
  300. $matches[9] = NULL;
  301. if (preg_match('|^(.+):(\d+)$|', $matches[4], $host_port_matches)) {
  302. $matches[4] = $host_port_matches[1];
  303. $matches[6] = $host_port_matches[2];
  304. }
  305. if (preg_match('|^(.+?)\((.+)\)$|', $matches[4], $protocol_matches)) {
  306. $matches[8] = $protocol_matches[1];
  307. $matches[9] = $protocol_matches[2];
  308. $matches[4] = NULL;
  309. $matches[6] = NULL;
  310. }
  311. //TODO: currently we just ignore options specified on the end of the DSN
  312. if (preg_match('|^(.+?)\?(.+)$|', $matches[5], $database_name_options_matches)) {
  313. $matches[5] = $database_name_options_matches[1];
  314. $matches[7] = $database_name_options_matches[2];
  315. }
  316. if ($matches[8] === 'unix' && !empty($matches[9]))
  317. $pdo_prefs_dsn = $matches[1] . ':unix_socket=' . $matches[9] . ';dbname=' . $matches[5];
  318. else
  319. $pdo_prefs_dsn = $matches[1] . ':host=' . $matches[4] . (!empty($matches[6]) ? ';port=' . $matches[6] : '') . ';dbname=' . $matches[5];
  320. try {
  321. $dbh = new PDO($pdo_prefs_dsn, $matches[2], $matches[3]);
  322. } catch (Exception $e) {
  323. $this->error = $e->getMessage();
  324. return false;
  325. }
  326. } else {
  327. $dbh = DB::connect($prefs_dsn, true);
  328. if(DB::isError($dbh)) {
  329. $this->error = DB::errorMessage($dbh);
  330. return false;
  331. }
  332. }
  333. $this->dbh = $dbh;
  334. return true;
  335. }
  336. /**
  337. * Function used to handle database connection errors
  338. *
  339. * @param object PEAR Error object
  340. *
  341. */
  342. function failQuery($res = NULL) {
  343. global $use_pdo;
  344. if($res == NULL) {
  345. printf(_("Preference database error (%s). Exiting abnormally"),
  346. $this->error);
  347. } else {
  348. printf(_("Preference database error (%s). Exiting abnormally"),
  349. ($use_pdo ? implode(' - ', $res->errorInfo()) : DB::errorMessage($res)));
  350. }
  351. exit;
  352. }
  353. /**
  354. * Get user's prefs setting
  355. *
  356. * @param string $user user name
  357. * @param string $key preference name
  358. * @param mixed $default (since 1.2.5) default value
  359. *
  360. * @return mixed preference value
  361. *
  362. */
  363. function getKey($user, $key, $default = '') {
  364. global $prefs_cache;
  365. $temp = array(&$user, &$key);
  366. $result = do_hook('get_pref_override', $temp);
  367. if (is_null($result)) {
  368. cachePrefValues($user);
  369. if (isset($prefs_cache[$key])) {
  370. $result = $prefs_cache[$key];
  371. } else {
  372. //FIXME: is there a justification for having two prefs hooks so close? who uses them?
  373. $temp = array(&$user, &$key);
  374. $result = do_hook('get_pref', $temp);
  375. if (is_null($result)) {
  376. if (isset($this->default[$key])) {
  377. $result = $this->default[$key];
  378. } else {
  379. $result = $default;
  380. }
  381. }
  382. }
  383. }
  384. return $result;
  385. }
  386. /**
  387. * Delete user's prefs setting
  388. *
  389. * @param string $user user name
  390. * @param string $key preference name
  391. *
  392. * @return boolean
  393. *
  394. */
  395. function deleteKey($user, $key) {
  396. global $prefs_cache, $use_pdo, $pdo_show_sql_errors;
  397. if (!$this->open()) {
  398. return false;
  399. }
  400. if ($use_pdo) {
  401. 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 . ' = ?'))) {
  402. if ($pdo_show_sql_errors)
  403. $this->error = implode(' - ', $this->dbh->errorInfo());
  404. else
  405. $this->error = _("Could not prepare query");
  406. $this->failQuery();
  407. }
  408. if (!($res = $sth->execute(array($user, $key)))) {
  409. if ($pdo_show_sql_errors)
  410. $this->error = implode(' - ', $sth->errorInfo());
  411. else
  412. $this->error = _("Could not execute query");
  413. $this->failQuery();
  414. }
  415. } else {
  416. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  417. $this->table,
  418. $this->user_field,
  419. $this->dbh->quoteString($user),
  420. $this->key_field,
  421. $this->dbh->quoteString($key));
  422. $res = $this->dbh->simpleQuery($query);
  423. if(DB::isError($res)) {
  424. $this->failQuery($res);
  425. }
  426. }
  427. unset($prefs_cache[$key]);
  428. return true;
  429. }
  430. /**
  431. * Set user's preference
  432. *
  433. * @param string $user user name
  434. * @param string $key preference name
  435. * @param mixed $value preference value
  436. *
  437. * @return boolean
  438. *
  439. */
  440. function setKey($user, $key, $value) {
  441. global $use_pdo, $pdo_show_sql_errors;
  442. if (!$this->open()) {
  443. return false;
  444. }
  445. /**
  446. * Check if username fits into db field
  447. */
  448. if (strlen($user) > $this->user_size) {
  449. $this->error = "Oversized username value."
  450. ." Your preferences can't be saved."
  451. ." See the administrator's manual or contact your system administrator.";
  452. /**
  453. * Debugging function. Can be used to log all issues that trigger
  454. * oversized field errors. Function should be enabled in all three
  455. * strlen checks. See http://www.php.net/error-log
  456. */
  457. // error_log($user.'|'.$key.'|'.$value."\n",3,'/tmp/oversized_log');
  458. // error is fatal
  459. $this->failQuery(null);
  460. }
  461. /**
  462. * Check if preference key fits into db field
  463. */
  464. if (strlen($key) > $this->key_size) {
  465. $err_msg = "Oversized user's preference key."
  466. ." Some preferences were not saved."
  467. ." See the administrator's manual or contact your system administrator.";
  468. // error is not fatal. Only some preference is not saved.
  469. trigger_error($err_msg,E_USER_WARNING);
  470. return false;
  471. }
  472. /**
  473. * Check if preference value fits into db field
  474. */
  475. if (strlen($value) > $this->val_size) {
  476. $err_msg = "Oversized user's preference value."
  477. ." Some preferences were not saved."
  478. ." See the administrator's manual or contact your system administrator.";
  479. // error is not fatal. Only some preference is not saved.
  480. trigger_error($err_msg,E_USER_WARNING);
  481. return false;
  482. }
  483. if ($this->db_type == SMDB_MYSQL) {
  484. if ($use_pdo) {
  485. 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 (?, ?, ?)'))) {
  486. if ($pdo_show_sql_errors)
  487. $this->error = implode(' - ', $this->dbh->errorInfo());
  488. else
  489. $this->error = _("Could not prepare query");
  490. $this->failQuery();
  491. }
  492. if (!($res = $sth->execute(array($user, $key, $value)))) {
  493. if ($pdo_show_sql_errors)
  494. $this->error = implode(' - ', $sth->errorInfo());
  495. else
  496. $this->error = _("Could not execute query");
  497. $this->failQuery();
  498. }
  499. } else {
  500. $query = sprintf("REPLACE INTO %s (%s, %s, %s) ".
  501. "VALUES('%s','%s','%s')",
  502. $this->table,
  503. $this->user_field,
  504. $this->key_field,
  505. $this->val_field,
  506. $this->dbh->quoteString($user),
  507. $this->dbh->quoteString($key),
  508. $this->dbh->quoteString($value));
  509. $res = $this->dbh->simpleQuery($query);
  510. if(DB::isError($res)) {
  511. $this->failQuery($res);
  512. }
  513. }
  514. } elseif ($this->db_type == SMDB_PGSQL) {
  515. if ($use_pdo) {
  516. if ($this->dbh->exec('BEGIN TRANSACTION') === FALSE) {
  517. if ($pdo_show_sql_errors)
  518. $this->error = implode(' - ', $this->dbh->errorInfo());
  519. else
  520. $this->error = _("Could not execute query");
  521. $this->failQuery();
  522. }
  523. 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 . ' = ?'))) {
  524. if ($pdo_show_sql_errors)
  525. $this->error = implode(' - ', $this->dbh->errorInfo());
  526. else
  527. $this->error = _("Could not prepare query");
  528. $this->failQuery();
  529. }
  530. if (!($res = $sth->execute(array($user, $key)))) {
  531. if ($pdo_show_sql_errors)
  532. $this->error = implode(' - ', $sth->errorInfo());
  533. else
  534. $this->error = _("Could not execute query");
  535. $this->dbh->exec('ROLLBACK TRANSACTION');
  536. $this->failQuery();
  537. }
  538. 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 (?, ?, ?)'))) {
  539. if ($pdo_show_sql_errors)
  540. $this->error = implode(' - ', $this->dbh->errorInfo());
  541. else
  542. $this->error = _("Could not prepare query");
  543. $this->failQuery();
  544. }
  545. if (!($res = $sth->execute(array($user, $key, $value)))) {
  546. if ($pdo_show_sql_errors)
  547. $this->error = implode(' - ', $sth->errorInfo());
  548. else
  549. $this->error = _("Could not execute query");
  550. $this->dbh->exec('ROLLBACK TRANSACTION');
  551. $this->failQuery();
  552. }
  553. if ($this->dbh->exec('COMMIT TRANSACTION') === FALSE) {
  554. if ($pdo_show_sql_errors)
  555. $this->error = implode(' - ', $this->dbh->errorInfo());
  556. else
  557. $this->error = _("Could not execute query");
  558. $this->failQuery();
  559. }
  560. } else {
  561. $this->dbh->simpleQuery("BEGIN TRANSACTION");
  562. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  563. $this->table,
  564. $this->user_field,
  565. $this->dbh->quoteString($user),
  566. $this->key_field,
  567. $this->dbh->quoteString($key));
  568. $res = $this->dbh->simpleQuery($query);
  569. if (DB::isError($res)) {
  570. $this->dbh->simpleQuery("ROLLBACK TRANSACTION");
  571. $this->failQuery($res);
  572. }
  573. $query = sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
  574. $this->table,
  575. $this->user_field,
  576. $this->key_field,
  577. $this->val_field,
  578. $this->dbh->quoteString($user),
  579. $this->dbh->quoteString($key),
  580. $this->dbh->quoteString($value));
  581. $res = $this->dbh->simpleQuery($query);
  582. if (DB::isError($res)) {
  583. $this->dbh->simpleQuery("ROLLBACK TRANSACTION");
  584. $this->failQuery($res);
  585. }
  586. $this->dbh->simpleQuery("COMMIT TRANSACTION");
  587. }
  588. } else {
  589. if ($use_pdo) {
  590. 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 . ' = ?'))) {
  591. if ($pdo_show_sql_errors)
  592. $this->error = implode(' - ', $this->dbh->errorInfo());
  593. else
  594. $this->error = _("Could not prepare query");
  595. $this->failQuery();
  596. }
  597. if (!($res = $sth->execute(array($user, $key)))) {
  598. if ($pdo_show_sql_errors)
  599. $this->error = implode(' - ', $sth->errorInfo());
  600. else
  601. $this->error = _("Could not execute query");
  602. $this->failQuery();
  603. }
  604. 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 (?, ?, ?)'))) {
  605. if ($pdo_show_sql_errors)
  606. $this->error = implode(' - ', $this->dbh->errorInfo());
  607. else
  608. $this->error = _("Could not prepare query");
  609. $this->failQuery();
  610. }
  611. if (!($res = $sth->execute(array($user, $key, $value)))) {
  612. if ($pdo_show_sql_errors)
  613. $this->error = implode(' - ', $sth->errorInfo());
  614. else
  615. $this->error = _("Could not execute query");
  616. $this->failQuery();
  617. }
  618. } else {
  619. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  620. $this->table,
  621. $this->user_field,
  622. $this->dbh->quoteString($user),
  623. $this->key_field,
  624. $this->dbh->quoteString($key));
  625. $res = $this->dbh->simpleQuery($query);
  626. if (DB::isError($res)) {
  627. $this->failQuery($res);
  628. }
  629. $query = sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
  630. $this->table,
  631. $this->user_field,
  632. $this->key_field,
  633. $this->val_field,
  634. $this->dbh->quoteString($user),
  635. $this->dbh->quoteString($key),
  636. $this->dbh->quoteString($value));
  637. $res = $this->dbh->simpleQuery($query);
  638. if (DB::isError($res)) {
  639. $this->failQuery($res);
  640. }
  641. }
  642. }
  643. return true;
  644. }
  645. /**
  646. * Fill preference cache array
  647. *
  648. * @param string $user user name
  649. *
  650. * @since 1.2.3
  651. *
  652. */
  653. function fillPrefsCache($user) {
  654. global $prefs_cache, $use_pdo, $pdo_show_sql_errors;
  655. if (!$this->open()) {
  656. return;
  657. }
  658. $prefs_cache = array();
  659. if ($use_pdo) {
  660. 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 . ' = ?'))) {
  661. if ($pdo_show_sql_errors)
  662. $this->error = implode(' - ', $this->dbh->errorInfo());
  663. else
  664. $this->error = _("Could not prepare query");
  665. $this->failQuery();
  666. }
  667. if (!($res = $sth->execute(array($user)))) {
  668. if ($pdo_show_sql_errors)
  669. $this->error = implode(' - ', $sth->errorInfo());
  670. else
  671. $this->error = _("Could not execute query");
  672. $this->failQuery();
  673. }
  674. while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
  675. $prefs_cache[$row['prefkey']] = $row['prefval'];
  676. }
  677. } else {
  678. $query = sprintf("SELECT %s as prefkey, %s as prefval FROM %s ".
  679. "WHERE %s = '%s'",
  680. $this->key_field,
  681. $this->val_field,
  682. $this->table,
  683. $this->user_field,
  684. $this->dbh->quoteString($user));
  685. $res = $this->dbh->query($query);
  686. if (DB::isError($res)) {
  687. $this->failQuery($res);
  688. }
  689. while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  690. $prefs_cache[$row['prefkey']] = $row['prefval'];
  691. }
  692. }
  693. }
  694. } /* end class dbPrefs */
  695. /**
  696. * Returns the value for the requested preference
  697. * @ignore
  698. */
  699. function getPref($data_dir, $username, $pref_name, $default = '') {
  700. $db = new dbPrefs;
  701. if(isset($db->error)) {
  702. printf( _("Preference database error (%s). Exiting abnormally"),
  703. $db->error);
  704. exit;
  705. }
  706. return $db->getKey($username, $pref_name, $default);
  707. }
  708. /**
  709. * Remove the desired preference setting ($pref_name)
  710. * @ignore
  711. */
  712. function removePref($data_dir, $username, $pref_name) {
  713. global $prefs_cache;
  714. $db = new dbPrefs;
  715. if(isset($db->error)) {
  716. $db->failQuery();
  717. }
  718. $db->deleteKey($username, $pref_name);
  719. if (isset($prefs_cache[$pref_name])) {
  720. unset($prefs_cache[$pref_name]);
  721. }
  722. sqsession_register($prefs_cache , 'prefs_cache');
  723. return;
  724. }
  725. /**
  726. * Sets the desired preference setting ($pref_name) to whatever is in $value
  727. * @ignore
  728. */
  729. function setPref($data_dir, $username, $pref_name, $value) {
  730. global $prefs_cache;
  731. if (isset($prefs_cache[$pref_name]) && ($prefs_cache[$pref_name] == $value)) {
  732. return;
  733. }
  734. if ($value === '') {
  735. removePref($data_dir, $username, $pref_name);
  736. return;
  737. }
  738. $db = new dbPrefs;
  739. if(isset($db->error)) {
  740. $db->failQuery();
  741. }
  742. $db->setKey($username, $pref_name, $value);
  743. $prefs_cache[$pref_name] = $value;
  744. assert_options(ASSERT_ACTIVE, 1);
  745. assert_options(ASSERT_BAIL, 1);
  746. assert ('$value == $prefs_cache[$pref_name]');
  747. sqsession_register($prefs_cache , 'prefs_cache');
  748. return;
  749. }
  750. /**
  751. * This checks if the prefs are available
  752. * @ignore
  753. */
  754. function checkForPrefs($data_dir, $username) {
  755. $db = new dbPrefs;
  756. if(isset($db->error)) {
  757. $db->failQuery();
  758. }
  759. }
  760. /**
  761. * Writes the Signature
  762. * @ignore
  763. */
  764. function setSig($data_dir, $username, $number, $value) {
  765. if ($number == "g") {
  766. $key = '___signature___';
  767. } else {
  768. $key = sprintf('___sig%s___', $number);
  769. }
  770. setPref($data_dir, $username, $key, $value);
  771. return;
  772. }
  773. /**
  774. * Gets the signature
  775. * @ignore
  776. */
  777. function getSig($data_dir, $username, $number) {
  778. if ($number == "g") {
  779. $key = '___signature___';
  780. } else {
  781. $key = sprintf('___sig%d___', $number);
  782. }
  783. return getPref($data_dir, $username, $key);
  784. }