Source for file db_prefs.php
Documentation is available at db_prefs.php
* This contains functions for manipulating user preferences
* stored in a database, accessed though the Pear DB layer
* or PDO, the latter taking precedence if available.
* The preferences table should have three columns:
* CREATE TABLE userprefs (user CHAR(128) NOT NULL DEFAULT '',
* prefkey CHAR(64) NOT NULL DEFAULT '',
* prefval BLOB NOT NULL DEFAULT '',
* primary key (user,prefkey));
* Configuration of databasename, username and password is done
* by using conf.pl or the administrator plugin
* Three settings that control PDO behavior can be specified in
* config/config_local.php if needed:
* boolean $disable_pdo SquirrelMail uses PDO by default to access the
* user preferences and address book databases, but
* setting this to TRUE will cause SquirrelMail to
* fall back to using Pear DB instead.
* boolean $pdo_show_sql_errors When database errors are encountered,
* setting this to TRUE causes the actual
* database error to be displayed, otherwise
* generic errors are displayed, preventing
* internal database information from being
* exposed. This should be enabled only for
* string $pdo_identifier_quote_char By default, SquirrelMail will quote
* table and field names in database
* queries with what it thinks is the
* appropriate quote character for the
* database type being used (backtick
* for MySQL (and thus MariaDB), double
* quotes for all others), but you can
* override the character used by
* putting it here, or tell SquirrelMail
* NOT to quote identifiers by setting
* @copyright 1999-2020 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id: db_prefs.php 14840 2020-01-07 07:42:38Z pdontthink $
global $disable_pdo, $use_pdo;
if (!$use_pdo &&
!include_once('DB.php')) {
// same error also in abook_database.php
require_once(SM_PATH .
'functions/display_messages.php');
$error =
_("Could not find or include PHP PDO or PEAR database functions required for the database backend.") .
"<br />\n";
if (!empty($disable_pdo))
$error .=
_("You have set \$disable_pdo - please try removing that.") .
"<br />\n";
$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?"), '<tt>DB.php</tt>') .
"<br />\n";
$error .=
_("Please contact your system administrator and report this error.");
global $prefs_are_cached, $prefs_cache;
global $prefs_are_cached, $prefs_cache;
printf( _("Preference database error (%s). Exiting abnormally"),
$db->fillPrefsCache($username);
printf( _("Preference database error (%s). Exiting abnormally"),
$prefs_are_cached =
true;
* Completely undocumented class - someone document it!
var $default =
Array('theme_default' =>
0,
'include_self_reply_all' =>
0,
'do_not_reply_to_self' =>
1,
'show_html_default' =>
'0');
* Constructor (PHP5 style, required in some future version of PHP)
* initialize the default preferences array.
// Try and read the default preferences file.
$default_pref =
SM_PATH .
'data/default_pref';
if ($file =
@fopen($default_pref, 'r')) {
$pref =
fgets($file, 1024);
* Constructor (PHP4 style, kept for compatibility reasons)
* initialize the default preferences array.
global $prefs_dsn, $prefs_table, $use_pdo, $pdo_identifier_quote_char;
global $prefs_user_field, $prefs_key_field, $prefs_val_field;
if (strpos($prefs_dsn, 'mysql') ===
0) {
} else if (strpos($prefs_dsn, 'pgsql') ===
0) {
// figure out identifier quoting (only used for PDO, though we could change that)
if (empty($pdo_identifier_quote_char)) {
} else if ($pdo_identifier_quote_char ===
'none')
if (!empty($prefs_table)) {
$this->table =
$prefs_table;
if (!empty($prefs_user_field)) {
// the default user field is "user", which in PostgreSQL
// is an identifier and causes errors if not escaped
if (!empty($prefs_key_field)) {
if (!empty($prefs_val_field)) {
// connect, create database connection object
// parse and convert DSN to PDO style
// Pear's full DSN syntax is one of the following:
// phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value
// phptype(syntax)://user:pass@protocol(proto_opts)/database
// $matches will contain:
// 4: hostname (and possible port number) OR protocol (and possible protocol options)
// 5: database name (and possible options)
// 6: port number (moved from match number 4)
// 7: options (moved from match number 5)
// 8: protocol (instead of hostname)
// 9: protocol options (moved from match number 4/8)
//TODO: do we care about supporting cases where no password is given? (this is a legal DSN, but causes an error below)
if (!preg_match('|^(.+)://(.+):(.+)@(.+)/(.+)$|i', $prefs_dsn, $matches)) {
$this->error =
_("Could not parse prefs DSN");
if (preg_match('|^(.+):(\d+)$|', $matches[4], $host_port_matches)) {
$matches[4] =
$host_port_matches[1];
$matches[6] =
$host_port_matches[2];
if (preg_match('|^(.+?)\((.+)\)$|', $matches[4], $protocol_matches)) {
$matches[8] =
$protocol_matches[1];
$matches[9] =
$protocol_matches[2];
//TODO: currently we just ignore options specified on the end of the DSN
if (preg_match('|^(.+?)\?(.+)$|', $matches[5], $database_name_options_matches)) {
$matches[5] =
$database_name_options_matches[1];
$matches[7] =
$database_name_options_matches[2];
if ($matches[8] ===
'unix' &&
!empty($matches[9]))
$pdo_prefs_dsn =
$matches[1] .
':unix_socket=' .
$matches[9] .
';dbname=' .
$matches[5];
$pdo_prefs_dsn =
$matches[1] .
':host=' .
$matches[4] .
(!empty($matches[6]) ?
';port=' .
$matches[6] :
'') .
';dbname=' .
$matches[5];
$dbh =
new PDO($pdo_prefs_dsn, $matches[2], $matches[3]);
$this->error =
$e->getMessage();
$dbh =
DB::connect($prefs_dsn, true);
$this->error =
DB::errorMessage($dbh);
printf(_("Preference database error (%s). Exiting abnormally"),
printf(_("Preference database error (%s). Exiting abnormally"),
($use_pdo ?
implode(' - ', $res->errorInfo()) :
DB::errorMessage($res)));
function getKey($user, $key, $default =
'') {
// FIXME: ideally, we'd have a better way to determine if the return value from the hook above should be respected, even if it is NULL, but this is as good as it gets for now... previously the test was more weak: if (!$result)
if (isset
($prefs_cache[$key])) {
$result =
$prefs_cache[$key];
//FIXME: is there justification for having these TWO hooks so close together? who uses these?
//FIXME: testing below for !$result means that a plugin cannot fetch its own pref value of 0, '0', '', FALSE, or anything else that evaluates to boolean FALSE.
global $prefs_cache, $use_pdo, $pdo_show_sql_errors;
if ($pdo_show_sql_errors)
$this->error =
_("Could not prepare query");
if (!($res =
$sth->execute(array($user, $key)))) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
$query =
sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
$this->dbh->quoteString($user),
$this->dbh->quoteString($key));
$res =
$this->dbh->simpleQuery($query);
unset
($prefs_cache[$key]);
function setKey($user, $key, $value) {
global $use_pdo, $pdo_show_sql_errors;
if ($pdo_show_sql_errors)
$this->error =
_("Could not prepare query");
if (!($res =
$sth->execute(array($user, $key, $value)))) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
$query =
sprintf("REPLACE INTO %s (%s, %s, %s) ".
"VALUES('%s','%s','%s')",
$this->dbh->quoteString($user),
$this->dbh->quoteString($key),
$this->dbh->quoteString($value));
$res =
$this->dbh->simpleQuery($query);
if ($this->dbh->exec('BEGIN TRANSACTION') ===
FALSE) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
if ($pdo_show_sql_errors)
$this->error =
_("Could not prepare query");
if (!($res =
$sth->execute(array($user, $key)))) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
$this->dbh->exec('ROLLBACK TRANSACTION');
if ($pdo_show_sql_errors)
$this->error =
_("Could not prepare query");
if (!($res =
$sth->execute(array($user, $key, $value)))) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
$this->dbh->exec('ROLLBACK TRANSACTION');
if ($this->dbh->exec('COMMIT TRANSACTION') ===
FALSE) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
$this->dbh->simpleQuery("BEGIN TRANSACTION");
$query =
sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
$this->dbh->quoteString($user),
$this->dbh->quoteString($key));
$res =
$this->dbh->simpleQuery($query);
$this->dbh->simpleQuery("ROLLBACK TRANSACTION");
$query =
sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
$this->dbh->quoteString($user),
$this->dbh->quoteString($key),
$this->dbh->quoteString($value));
$res =
$this->dbh->simpleQuery($query);
$this->dbh->simpleQuery("ROLLBACK TRANSACTION");
$this->dbh->simpleQuery("COMMIT TRANSACTION");
if ($pdo_show_sql_errors)
$this->error =
_("Could not prepare query");
if (!($res =
$sth->execute(array($user, $key)))) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
if ($pdo_show_sql_errors)
$this->error =
_("Could not prepare query");
if (!($res =
$sth->execute(array($user, $key, $value)))) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
$query =
sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
$this->dbh->quoteString($user),
$this->dbh->quoteString($key));
$res =
$this->dbh->simpleQuery($query);
$query =
sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
$this->dbh->quoteString($user),
$this->dbh->quoteString($key),
$this->dbh->quoteString($value));
$res =
$this->dbh->simpleQuery($query);
global $prefs_cache, $use_pdo, $pdo_show_sql_errors;
if ($pdo_show_sql_errors)
$this->error =
_("Could not prepare query");
if (!($res =
$sth->execute(array($user)))) {
if ($pdo_show_sql_errors)
$this->error =
_("Could not execute query");
while ($row =
$sth->fetch(PDO::FETCH_ASSOC)) {
$prefs_cache[$row['prefkey']] =
$row['prefval'];
$query =
sprintf("SELECT %s as prefkey, %s as prefval FROM %s ".
$this->dbh->quoteString($user));
$res =
$this->dbh->query($query);
while ($row =
$res->fetchRow(DB_FETCHMODE_ASSOC)) {
$prefs_cache[$row['prefkey']] =
$row['prefval'];
} /* end class dbPrefs */
* returns the value for the pref $string
function getPref($data_dir, $username, $string, $default =
'') {
printf( _("Preference database error (%s). Exiting abnormally"),
return $db->getKey($username, $string, $default);
* Remove the pref $string
function removePref($data_dir, $username, $string) {
if (isset
($prefs_cache[$string])) {
unset
($prefs_cache[$string]);
* sets the pref, $string, to $set_to
function setPref($data_dir, $username, $string, $set_to) {
if (isset
($prefs_cache[$string]) &&
($prefs_cache[$string] ==
$set_to)) {
$db->setKey($username, $string, $set_to);
$prefs_cache[$string] =
$set_to;
assert ('$set_to == $prefs_cache[$string]');
* This checks if the prefs are available
function setSig($data_dir, $username, $number, $string) {
$key =
'___signature___';
$key =
sprintf('___sig%s___', $number);
setPref($data_dir, $username, $key, $string);
function getSig($data_dir, $username, $number) {
$key =
'___signature___';
$key =
sprintf('___sig%d___', $number);
return getPref($data_dir, $username, $key);
Documentation generated on Mon, 13 Jan 2020 04:24:28 +0100 by phpDocumentor 1.4.3