db_prefs.php 36 KB

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