db_prefs.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. <?php
  2. /**
  3. * db_prefs.php
  4. *
  5. * This contains functions for manipulating user preferences
  6. * stored in a database, accessed though the Pear DB layer.
  7. *
  8. * Database:
  9. *
  10. * The preferences table should have three columns:
  11. * user char \ primary
  12. * prefkey char / key
  13. * prefval blob
  14. *
  15. * CREATE TABLE userprefs (user CHAR(128) NOT NULL DEFAULT '',
  16. * prefkey CHAR(64) NOT NULL DEFAULT '',
  17. * prefval BLOB NOT NULL DEFAULT '',
  18. * primary key (user,prefkey));
  19. *
  20. * Configuration of databasename, username and password is done
  21. * by using conf.pl or the administrator plugin
  22. *
  23. * @copyright &copy; 1999-2007 The SquirrelMail Project Team
  24. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  25. * @version $Id$
  26. * @package squirrelmail
  27. * @subpackage prefs
  28. * @since 1.1.3
  29. */
  30. /** @ignore */
  31. if (!defined('SM_PATH')) define('SM_PATH','../');
  32. /** Unknown database */
  33. define('SMDB_UNKNOWN', 0);
  34. /** MySQL */
  35. define('SMDB_MYSQL', 1);
  36. /** PostgreSQL */
  37. define('SMDB_PGSQL', 2);
  38. /**
  39. * don't display errors (no code execution in functions/*.php).
  40. * will handle error in dbPrefs class.
  41. */
  42. @include_once('DB.php');
  43. global $prefs_are_cached, $prefs_cache;
  44. /**
  45. * @ignore
  46. */
  47. function cachePrefValues($username) {
  48. global $prefs_are_cached, $prefs_cache;
  49. sqgetGlobalVar('prefs_are_cached', $prefs_are_cached, SQ_SESSION );
  50. if ($prefs_are_cached) {
  51. sqgetGlobalVar('prefs_cache', $prefs_cache, SQ_SESSION );
  52. return;
  53. }
  54. sqsession_unregister('prefs_cache');
  55. sqsession_unregister('prefs_are_cached');
  56. $db = new dbPrefs;
  57. if(isset($db->error)) {
  58. printf( _("Preference database error (%s). Exiting abnormally"),
  59. $db->error);
  60. exit;
  61. }
  62. $db->fillPrefsCache($username);
  63. if (isset($db->error)) {
  64. printf( _("Preference database error (%s). Exiting abnormally"),
  65. $db->error);
  66. exit;
  67. }
  68. $prefs_are_cached = true;
  69. sqsession_register($prefs_cache, 'prefs_cache');
  70. sqsession_register($prefs_are_cached, 'prefs_are_cached');
  71. }
  72. /**
  73. * Class used to handle connections to prefs database and operations with preferences
  74. *
  75. * @package squirrelmail
  76. * @subpackage prefs
  77. * @since 1.1.3
  78. *
  79. */
  80. class dbPrefs {
  81. /**
  82. * Table used to store preferences
  83. * @var string
  84. */
  85. var $table = 'userprefs';
  86. /**
  87. * Field used to store owner of preference
  88. * @var string
  89. */
  90. var $user_field = 'user';
  91. /**
  92. * Field used to store preference name
  93. * @var string
  94. */
  95. var $key_field = 'prefkey';
  96. /**
  97. * Field used to store preference value
  98. * @var string
  99. */
  100. var $val_field = 'prefval';
  101. /**
  102. * Database connection object
  103. * @var object
  104. */
  105. var $dbh = NULL;
  106. /**
  107. * Error messages
  108. * @var string
  109. */
  110. var $error = NULL;
  111. /**
  112. * Database type (SMDB_* constants)
  113. * Is used in setKey().
  114. * @var integer
  115. */
  116. var $db_type = SMDB_UNKNOWN;
  117. /**
  118. * Default preferences
  119. * @var array
  120. */
  121. var $default = Array('theme_default' => 0,
  122. 'show_html_default' => '0');
  123. /**
  124. * Preference owner field size
  125. * @var integer
  126. * @since 1.5.1
  127. */
  128. var $user_size = 128;
  129. /**
  130. * Preference key field size
  131. * @var integer
  132. * @since 1.5.1
  133. */
  134. var $key_size = 64;
  135. /**
  136. * Preference value field size
  137. * @var integer
  138. * @since 1.5.1
  139. */
  140. var $val_size = 65536;
  141. /**
  142. * initialize DB connection object
  143. *
  144. * @return boolean true, if object is initialized
  145. *
  146. */
  147. function open() {
  148. global $prefs_dsn, $prefs_table;
  149. global $prefs_user_field, $prefs_key_field, $prefs_val_field;
  150. global $prefs_user_size, $prefs_key_size, $prefs_val_size;
  151. /* test if Pear DB class is available and freak out if it is not */
  152. if (! class_exists('DB')) {
  153. // same error also in abook_database.php
  154. $this->error = _("Could not include PEAR database functions required for the database backend.") . "\n";
  155. $this->error .= sprintf(_("Is PEAR installed, and is the include path set correctly to find %s?"),
  156. 'DB.php') . "\n";
  157. $this->error .= _("Please contact your system administrator and report this error.");
  158. return false;
  159. }
  160. if(isset($this->dbh)) {
  161. return true;
  162. }
  163. if (preg_match('/^mysql/', $prefs_dsn)) {
  164. $this->db_type = SMDB_MYSQL;
  165. } elseif (preg_match('/^pgsql/', $prefs_dsn)) {
  166. $this->db_type = SMDB_PGSQL;
  167. }
  168. if (!empty($prefs_table)) {
  169. $this->table = $prefs_table;
  170. }
  171. if (!empty($prefs_user_field)) {
  172. $this->user_field = $prefs_user_field;
  173. }
  174. if (!empty($prefs_key_field)) {
  175. $this->key_field = $prefs_key_field;
  176. }
  177. if (!empty($prefs_val_field)) {
  178. $this->val_field = $prefs_val_field;
  179. }
  180. if (!empty($prefs_user_size)) {
  181. $this->user_size = (int) $prefs_user_size;
  182. }
  183. if (!empty($prefs_key_size)) {
  184. $this->key_size = (int) $prefs_key_size;
  185. }
  186. if (!empty($prefs_val_size)) {
  187. $this->val_size = (int) $prefs_val_size;
  188. }
  189. $dbh = DB::connect($prefs_dsn, true);
  190. if(DB::isError($dbh)) {
  191. $this->error = DB::errorMessage($dbh);
  192. return false;
  193. }
  194. $this->dbh = $dbh;
  195. return true;
  196. }
  197. /**
  198. * Function used to handle database connection errors
  199. *
  200. * @param object PEAR Error object
  201. *
  202. */
  203. function failQuery($res = NULL) {
  204. if($res == NULL) {
  205. printf(_("Preference database error (%s). Exiting abnormally"),
  206. $this->error);
  207. } else {
  208. printf(_("Preference database error (%s). Exiting abnormally"),
  209. DB::errorMessage($res));
  210. }
  211. exit;
  212. }
  213. /**
  214. * Get user's prefs setting
  215. *
  216. * @param string $user user name
  217. * @param string $key preference name
  218. * @param mixed $default (since 1.2.5) default value
  219. *
  220. * @return mixed preference value
  221. *
  222. */
  223. function getKey($user, $key, $default = '') {
  224. global $prefs_cache;
  225. cachePrefValues($user);
  226. if (isset($prefs_cache[$key])) {
  227. return $prefs_cache[$key];
  228. } else {
  229. if (isset($this->default[$key])) {
  230. return $this->default[$key];
  231. } else {
  232. return $default;
  233. }
  234. }
  235. }
  236. /**
  237. * Delete user's prefs setting
  238. *
  239. * @param string $user user name
  240. * @param string $key preference name
  241. *
  242. * @return boolean
  243. *
  244. */
  245. function deleteKey($user, $key) {
  246. global $prefs_cache;
  247. if (!$this->open()) {
  248. return false;
  249. }
  250. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  251. $this->table,
  252. $this->user_field,
  253. $this->dbh->quoteString($user),
  254. $this->key_field,
  255. $this->dbh->quoteString($key));
  256. $res = $this->dbh->simpleQuery($query);
  257. if(DB::isError($res)) {
  258. $this->failQuery($res);
  259. }
  260. unset($prefs_cache[$key]);
  261. return true;
  262. }
  263. /**
  264. * Set user's preference
  265. *
  266. * @param string $user user name
  267. * @param string $key preference name
  268. * @param mixed $value preference value
  269. *
  270. * @return boolean
  271. *
  272. */
  273. function setKey($user, $key, $value) {
  274. if (!$this->open()) {
  275. return false;
  276. }
  277. /**
  278. * Check if username fits into db field
  279. */
  280. if (strlen($user) > $this->user_size) {
  281. $this->error = "Oversized username value."
  282. ." Your preferences can't be saved."
  283. ." See the administrator's manual or contact your system administrator.";
  284. /**
  285. * Debugging function. Can be used to log all issues that trigger
  286. * oversized field errors. Function should be enabled in all three
  287. * strlen checks. See http://www.php.net/error-log
  288. */
  289. // error_log($user.'|'.$key.'|'.$value."\n",3,'/tmp/oversized_log');
  290. // error is fatal
  291. $this->failQuery(null);
  292. }
  293. /**
  294. * Check if preference key fits into db field
  295. */
  296. if (strlen($key) > $this->key_size) {
  297. $err_msg = "Oversized user's preference key."
  298. ." Some preferences were not saved."
  299. ." See the administrator's manual or contact your system administrator.";
  300. // error is not fatal. Only some preference is not saved.
  301. trigger_error($err_msg,E_USER_WARNING);
  302. return false;
  303. }
  304. /**
  305. * Check if preference value fits into db field
  306. */
  307. if (strlen($value) > $this->val_size) {
  308. $err_msg = "Oversized user's preference value."
  309. ." Some preferences were not saved."
  310. ." See the administrator's manual or contact your system administrator.";
  311. // error is not fatal. Only some preference is not saved.
  312. trigger_error($err_msg,E_USER_WARNING);
  313. return false;
  314. }
  315. if ($this->db_type == SMDB_MYSQL) {
  316. $query = sprintf("REPLACE INTO %s (%s, %s, %s) ".
  317. "VALUES('%s','%s','%s')",
  318. $this->table,
  319. $this->user_field,
  320. $this->key_field,
  321. $this->val_field,
  322. $this->dbh->quoteString($user),
  323. $this->dbh->quoteString($key),
  324. $this->dbh->quoteString($value));
  325. $res = $this->dbh->simpleQuery($query);
  326. if(DB::isError($res)) {
  327. $this->failQuery($res);
  328. }
  329. } elseif ($this->db_type == SMDB_PGSQL) {
  330. $this->dbh->simpleQuery("BEGIN TRANSACTION");
  331. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  332. $this->table,
  333. $this->user_field,
  334. $this->dbh->quoteString($user),
  335. $this->key_field,
  336. $this->dbh->quoteString($key));
  337. $res = $this->dbh->simpleQuery($query);
  338. if (DB::isError($res)) {
  339. $this->dbh->simpleQuery("ROLLBACK TRANSACTION");
  340. $this->failQuery($res);
  341. }
  342. $query = sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
  343. $this->table,
  344. $this->user_field,
  345. $this->key_field,
  346. $this->val_field,
  347. $this->dbh->quoteString($user),
  348. $this->dbh->quoteString($key),
  349. $this->dbh->quoteString($value));
  350. $res = $this->dbh->simpleQuery($query);
  351. if (DB::isError($res)) {
  352. $this->dbh->simpleQuery("ROLLBACK TRANSACTION");
  353. $this->failQuery($res);
  354. }
  355. $this->dbh->simpleQuery("COMMIT TRANSACTION");
  356. } else {
  357. $query = sprintf("DELETE FROM %s WHERE %s='%s' AND %s='%s'",
  358. $this->table,
  359. $this->user_field,
  360. $this->dbh->quoteString($user),
  361. $this->key_field,
  362. $this->dbh->quoteString($key));
  363. $res = $this->dbh->simpleQuery($query);
  364. if (DB::isError($res)) {
  365. $this->failQuery($res);
  366. }
  367. $query = sprintf("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')",
  368. $this->table,
  369. $this->user_field,
  370. $this->key_field,
  371. $this->val_field,
  372. $this->dbh->quoteString($user),
  373. $this->dbh->quoteString($key),
  374. $this->dbh->quoteString($value));
  375. $res = $this->dbh->simpleQuery($query);
  376. if (DB::isError($res)) {
  377. $this->failQuery($res);
  378. }
  379. }
  380. return true;
  381. }
  382. /**
  383. * Fill preference cache array
  384. *
  385. * @param string $user user name
  386. *
  387. * @since 1.2.3
  388. *
  389. */
  390. function fillPrefsCache($user) {
  391. global $prefs_cache;
  392. if (!$this->open()) {
  393. return;
  394. }
  395. $prefs_cache = array();
  396. $query = sprintf("SELECT %s as prefkey, %s as prefval FROM %s ".
  397. "WHERE %s = '%s'",
  398. $this->key_field,
  399. $this->val_field,
  400. $this->table,
  401. $this->user_field,
  402. $this->dbh->quoteString($user));
  403. $res = $this->dbh->query($query);
  404. if (DB::isError($res)) {
  405. $this->failQuery($res);
  406. }
  407. while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
  408. $prefs_cache[$row['prefkey']] = $row['prefval'];
  409. }
  410. }
  411. } /* end class dbPrefs */
  412. /**
  413. * Returns the value for the requested preference
  414. * @ignore
  415. */
  416. function getPref($data_dir, $username, $pref_name, $default = '') {
  417. $db = new dbPrefs;
  418. if(isset($db->error)) {
  419. printf( _("Preference database error (%s). Exiting abnormally"),
  420. $db->error);
  421. exit;
  422. }
  423. return $db->getKey($username, $pref_name, $default);
  424. }
  425. /**
  426. * Remove the desired preference setting ($pref_name)
  427. * @ignore
  428. */
  429. function removePref($data_dir, $username, $pref_name) {
  430. global $prefs_cache;
  431. $db = new dbPrefs;
  432. if(isset($db->error)) {
  433. $db->failQuery();
  434. }
  435. $db->deleteKey($username, $pref_name);
  436. if (isset($prefs_cache[$pref_name])) {
  437. unset($prefs_cache[$pref_name]);
  438. }
  439. sqsession_register($prefs_cache , 'prefs_cache');
  440. return;
  441. }
  442. /**
  443. * Sets the desired preference setting ($pref_name) to whatever is in $value
  444. * @ignore
  445. */
  446. function setPref($data_dir, $username, $pref_name, $value) {
  447. global $prefs_cache;
  448. if (isset($prefs_cache[$pref_name]) && ($prefs_cache[$pref_name] == $value)) {
  449. return;
  450. }
  451. if ($value === '') {
  452. removePref($data_dir, $username, $pref_name);
  453. return;
  454. }
  455. $db = new dbPrefs;
  456. if(isset($db->error)) {
  457. $db->failQuery();
  458. }
  459. $db->setKey($username, $pref_name, $value);
  460. $prefs_cache[$pref_name] = $value;
  461. assert_options(ASSERT_ACTIVE, 1);
  462. assert_options(ASSERT_BAIL, 1);
  463. assert ('$value == $prefs_cache[$pref_name]');
  464. sqsession_register($prefs_cache , 'prefs_cache');
  465. return;
  466. }
  467. /**
  468. * This checks if the prefs are available
  469. * @ignore
  470. */
  471. function checkForPrefs($data_dir, $username) {
  472. $db = new dbPrefs;
  473. if(isset($db->error)) {
  474. $db->failQuery();
  475. }
  476. }
  477. /**
  478. * Writes the Signature
  479. * @ignore
  480. */
  481. function setSig($data_dir, $username, $number, $value) {
  482. if ($number == "g") {
  483. $key = '___signature___';
  484. } else {
  485. $key = sprintf('___sig%s___', $number);
  486. }
  487. setPref($data_dir, $username, $key, $value);
  488. return;
  489. }
  490. /**
  491. * Gets the signature
  492. * @ignore
  493. */
  494. function getSig($data_dir, $username, $number) {
  495. if ($number == "g") {
  496. $key = '___signature___';
  497. } else {
  498. $key = sprintf('___sig%d___', $number);
  499. }
  500. return getPref($data_dir, $username, $key);
  501. }