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