PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/program/include/rcube_config.php

https://github.com/netconstructor/roundcubemail
PHP | 441 lines | 237 code | 70 blank | 134 comment | 77 complexity | ac6d40ffd8070e54fa3c21fe2a9193b9 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. <?php
  2. /*
  3. +-----------------------------------------------------------------------+
  4. | program/include/rcube_config.php |
  5. | |
  6. | This file is part of the Roundcube Webmail client |
  7. | Copyright (C) 2008-2012, The Roundcube Dev Team |
  8. | |
  9. | Licensed under the GNU General Public License version 3 or |
  10. | any later version with exceptions for skins & plugins. |
  11. | See the README file for a full license statement. |
  12. | |
  13. | PURPOSE: |
  14. | Class to read configuration settings |
  15. | |
  16. +-----------------------------------------------------------------------+
  17. | Author: Thomas Bruederli <roundcube@gmail.com> |
  18. +-----------------------------------------------------------------------+
  19. */
  20. /**
  21. * Configuration class for Roundcube
  22. *
  23. * @package Framework
  24. * @subpackage Core
  25. */
  26. class rcube_config
  27. {
  28. const DEFAULT_SKIN = 'larry';
  29. private $prop = array();
  30. private $errors = array();
  31. private $userprefs = array();
  32. /**
  33. * Renamed options
  34. *
  35. * @var array
  36. */
  37. private $legacy_props = array(
  38. // new name => old name
  39. 'default_folders' => 'default_imap_folders',
  40. 'mail_pagesize' => 'pagesize',
  41. 'addressbook_pagesize' => 'pagesize',
  42. 'reply_mode' => 'top_posting',
  43. 'refresh_interval' => 'keep_alive',
  44. 'min_refresh_interval' => 'min_keep_alive',
  45. );
  46. /**
  47. * Object constructor
  48. */
  49. public function __construct()
  50. {
  51. $this->load();
  52. // Defaults, that we do not require you to configure,
  53. // but contain information that is used in various
  54. // locations in the code:
  55. $this->set('contactlist_fields', array('name', 'firstname', 'surname', 'email'));
  56. }
  57. /**
  58. * Load config from local config file
  59. *
  60. * @todo Remove global $CONFIG
  61. */
  62. private function load()
  63. {
  64. // load main config file
  65. if (!$this->load_from_file(RCMAIL_CONFIG_DIR . '/main.inc.php'))
  66. $this->errors[] = 'main.inc.php was not found.';
  67. // load database config
  68. if (!$this->load_from_file(RCMAIL_CONFIG_DIR . '/db.inc.php'))
  69. $this->errors[] = 'db.inc.php was not found.';
  70. // load host-specific configuration
  71. $this->load_host_config();
  72. // set skin (with fallback to old 'skin_path' property)
  73. if (empty($this->prop['skin'])) {
  74. if (!empty($this->prop['skin_path'])) {
  75. $this->prop['skin'] = str_replace('skins/', '', unslashify($this->prop['skin_path']));
  76. }
  77. else {
  78. $this->prop['skin'] = self::DEFAULT_SKIN;
  79. }
  80. }
  81. // larry is the new default skin :-)
  82. if ($this->prop['skin'] == 'default')
  83. $this->prop['skin'] = self::DEFAULT_SKIN;
  84. // fix paths
  85. $this->prop['log_dir'] = $this->prop['log_dir'] ? realpath(unslashify($this->prop['log_dir'])) : INSTALL_PATH . 'logs';
  86. $this->prop['temp_dir'] = $this->prop['temp_dir'] ? realpath(unslashify($this->prop['temp_dir'])) : INSTALL_PATH . 'temp';
  87. // fix default imap folders encoding
  88. foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder)
  89. $this->prop[$folder] = rcube_charset::convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF7-IMAP');
  90. if (!empty($this->prop['default_folders']))
  91. foreach ($this->prop['default_folders'] as $n => $folder)
  92. $this->prop['default_folders'][$n] = rcube_charset::convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');
  93. // set PHP error logging according to config
  94. if ($this->prop['debug_level'] & 1) {
  95. ini_set('log_errors', 1);
  96. if ($this->prop['log_driver'] == 'syslog') {
  97. ini_set('error_log', 'syslog');
  98. }
  99. else {
  100. ini_set('error_log', $this->prop['log_dir'].'/errors');
  101. }
  102. }
  103. // enable display_errors in 'show' level, but not for ajax requests
  104. ini_set('display_errors', intval(empty($_REQUEST['_remote']) && ($this->prop['debug_level'] & 4)));
  105. // set timezone auto settings values
  106. if ($this->prop['timezone'] == 'auto') {
  107. $this->prop['_timezone_value'] = $this->client_timezone();
  108. }
  109. else if (is_numeric($this->prop['timezone']) && ($tz = timezone_name_from_abbr("", $this->prop['timezone'] * 3600, 0))) {
  110. $this->prop['timezone'] = $tz;
  111. }
  112. else if (empty($this->prop['timezone'])) {
  113. $this->prop['timezone'] = 'UTC';
  114. }
  115. // remove deprecated properties
  116. unset($this->prop['dst_active']);
  117. // export config data
  118. $GLOBALS['CONFIG'] = &$this->prop;
  119. }
  120. /**
  121. * Load a host-specific config file if configured
  122. * This will merge the host specific configuration with the given one
  123. */
  124. private function load_host_config()
  125. {
  126. $fname = null;
  127. if (is_array($this->prop['include_host_config'])) {
  128. $fname = $this->prop['include_host_config'][$_SERVER['HTTP_HOST']];
  129. }
  130. else if (!empty($this->prop['include_host_config'])) {
  131. $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $_SERVER['HTTP_HOST']) . '.inc.php';
  132. }
  133. if ($fname) {
  134. $this->load_from_file(RCMAIL_CONFIG_DIR . '/' . $fname);
  135. }
  136. }
  137. /**
  138. * Read configuration from a file
  139. * and merge with the already stored config values
  140. *
  141. * @param string $fpath Full path to the config file to be loaded
  142. * @return booelan True on success, false on failure
  143. */
  144. public function load_from_file($fpath)
  145. {
  146. if (is_file($fpath) && is_readable($fpath)) {
  147. // use output buffering, we don't need any output here
  148. ob_start();
  149. include($fpath);
  150. ob_end_clean();
  151. if (is_array($rcmail_config)) {
  152. $this->prop = array_merge($this->prop, $rcmail_config, $this->userprefs);
  153. return true;
  154. }
  155. }
  156. return false;
  157. }
  158. /**
  159. * Getter for a specific config parameter
  160. *
  161. * @param string $name Parameter name
  162. * @param mixed $def Default value if not set
  163. * @return mixed The requested config value
  164. */
  165. public function get($name, $def = null)
  166. {
  167. if (isset($this->prop[$name])) {
  168. $result = $this->prop[$name];
  169. }
  170. else if (isset($this->legacy_props[$name])) {
  171. return $this->get($this->legacy_props[$name], $def);
  172. }
  173. else {
  174. $result = $def;
  175. }
  176. $rcube = rcube::get_instance();
  177. if ($name == 'timezone' && isset($this->prop['_timezone_value'])) {
  178. $result = $this->prop['_timezone_value'];
  179. }
  180. else if ($name == 'client_mimetypes') {
  181. if ($result == null && $def == null)
  182. $result = 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,image/bmp,image/tiff,application/x-javascript,application/pdf,application/x-shockwave-flash';
  183. if ($result && is_string($result))
  184. $result = explode(',', $result);
  185. }
  186. $plugin = $rcube->plugins->exec_hook('config_get', array(
  187. 'name' => $name, 'default' => $def, 'result' => $result));
  188. return $plugin['result'];
  189. }
  190. /**
  191. * Setter for a config parameter
  192. *
  193. * @param string $name Parameter name
  194. * @param mixed $value Parameter value
  195. */
  196. public function set($name, $value)
  197. {
  198. $this->prop[$name] = $value;
  199. }
  200. /**
  201. * Override config options with the given values (eg. user prefs)
  202. *
  203. * @param array $prefs Hash array with config props to merge over
  204. */
  205. public function merge($prefs)
  206. {
  207. $this->prop = array_merge($this->prop, $prefs, $this->userprefs);
  208. }
  209. /**
  210. * Merge the given prefs over the current config
  211. * and make sure that they survive further merging.
  212. *
  213. * @param array $prefs Hash array with user prefs
  214. */
  215. public function set_user_prefs($prefs)
  216. {
  217. // Honor the dont_override setting for any existing user preferences
  218. $dont_override = $this->get('dont_override');
  219. if (is_array($dont_override) && !empty($dont_override)) {
  220. foreach ($dont_override as $key) {
  221. unset($prefs[$key]);
  222. }
  223. }
  224. // convert user's timezone into the new format
  225. if (is_numeric($prefs['timezone']) && ($tz = timezone_name_from_abbr('', $prefs['timezone'] * 3600, 0))) {
  226. $prefs['timezone'] = $tz;
  227. }
  228. // larry is the new default skin :-)
  229. if ($prefs['skin'] == 'default') {
  230. $prefs['skin'] = self::DEFAULT_SKIN;
  231. }
  232. $this->userprefs = $prefs;
  233. $this->prop = array_merge($this->prop, $prefs);
  234. // override timezone settings with client values
  235. if ($this->prop['timezone'] == 'auto') {
  236. $this->prop['_timezone_value'] = isset($_SESSION['timezone']) ? $this->client_timezone() : $this->prop['_timezone_value'];
  237. }
  238. else if (isset($this->prop['_timezone_value']))
  239. unset($this->prop['_timezone_value']);
  240. }
  241. /**
  242. * Getter for all config options
  243. *
  244. * @return array Hash array containg all config properties
  245. */
  246. public function all()
  247. {
  248. return $this->prop;
  249. }
  250. /**
  251. * Special getter for user's timezone offset including DST
  252. *
  253. * @return float Timezone offset (in hours)
  254. * @deprecated
  255. */
  256. public function get_timezone()
  257. {
  258. if ($tz = $this->get('timezone')) {
  259. try {
  260. $tz = new DateTimeZone($tz);
  261. return $tz->getOffset(new DateTime('now')) / 3600;
  262. }
  263. catch (Exception $e) {
  264. }
  265. }
  266. return 0;
  267. }
  268. /**
  269. * Return requested DES crypto key.
  270. *
  271. * @param string $key Crypto key name
  272. * @return string Crypto key
  273. */
  274. public function get_crypto_key($key)
  275. {
  276. // Bomb out if the requested key does not exist
  277. if (!array_key_exists($key, $this->prop)) {
  278. rcube::raise_error(array(
  279. 'code' => 500, 'type' => 'php',
  280. 'file' => __FILE__, 'line' => __LINE__,
  281. 'message' => "Request for unconfigured crypto key \"$key\""
  282. ), true, true);
  283. }
  284. $key = $this->prop[$key];
  285. // Bomb out if the configured key is not exactly 24 bytes long
  286. if (strlen($key) != 24) {
  287. rcube::raise_error(array(
  288. 'code' => 500, 'type' => 'php',
  289. 'file' => __FILE__, 'line' => __LINE__,
  290. 'message' => "Configured crypto key '$key' is not exactly 24 bytes long"
  291. ), true, true);
  292. }
  293. return $key;
  294. }
  295. /**
  296. * Try to autodetect operating system and find the correct line endings
  297. *
  298. * @return string The appropriate mail header delimiter
  299. */
  300. public function header_delimiter()
  301. {
  302. // use the configured delimiter for headers
  303. if (!empty($this->prop['mail_header_delimiter'])) {
  304. $delim = $this->prop['mail_header_delimiter'];
  305. if ($delim == "\n" || $delim == "\r\n")
  306. return $delim;
  307. else
  308. rcube::raise_error(array(
  309. 'code' => 500, 'type' => 'php',
  310. 'file' => __FILE__, 'line' => __LINE__,
  311. 'message' => "Invalid mail_header_delimiter setting"
  312. ), true, false);
  313. }
  314. $php_os = strtolower(substr(PHP_OS, 0, 3));
  315. if ($php_os == 'win')
  316. return "\r\n";
  317. if ($php_os == 'mac')
  318. return "\r\n";
  319. return "\n";
  320. }
  321. /**
  322. * Return the mail domain configured for the given host
  323. *
  324. * @param string $host IMAP host
  325. * @param boolean $encode If true, domain name will be converted to IDN ASCII
  326. * @return string Resolved SMTP host
  327. */
  328. public function mail_domain($host, $encode=true)
  329. {
  330. $domain = $host;
  331. if (is_array($this->prop['mail_domain'])) {
  332. if (isset($this->prop['mail_domain'][$host]))
  333. $domain = $this->prop['mail_domain'][$host];
  334. }
  335. else if (!empty($this->prop['mail_domain'])) {
  336. $domain = rcube_utils::parse_host($this->prop['mail_domain']);
  337. }
  338. if ($encode) {
  339. $domain = rcube_utils::idn_to_ascii($domain);
  340. }
  341. return $domain;
  342. }
  343. /**
  344. * Getter for error state
  345. *
  346. * @return mixed Error message on error, False if no errors
  347. */
  348. public function get_error()
  349. {
  350. return empty($this->errors) ? false : join("\n", $this->errors);
  351. }
  352. /**
  353. * Internal getter for client's (browser) timezone identifier
  354. */
  355. private function client_timezone()
  356. {
  357. if (isset($_SESSION['timezone']) && is_numeric($_SESSION['timezone'])
  358. && ($ctz = timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0))) {
  359. return $ctz;
  360. }
  361. else if (!empty($_SESSION['timezone'])) {
  362. try {
  363. $tz = timezone_open($_SESSION['timezone']);
  364. return $tz->getName();
  365. }
  366. catch (Exception $e) { /* gracefully ignore */ }
  367. }
  368. // fallback to server's timezone
  369. return date_default_timezone_get();
  370. }
  371. }