You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bootstrap.php 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. <?php
  2. /**
  3. +-----------------------------------------------------------------------+
  4. | This file is part of the Roundcube PHP suite |
  5. | Copyright (C) 2005-2017, The Roundcube Dev Team |
  6. | |
  7. | Licensed under the GNU General Public License version 3 or |
  8. | any later version with exceptions for skins & plugins. |
  9. | See the README file for a full license statement. |
  10. | |
  11. | CONTENTS: |
  12. | Roundcube Framework Initialization |
  13. +-----------------------------------------------------------------------+
  14. | Author: Thomas Bruederli <roundcube@gmail.com> |
  15. | Author: Aleksander Machniak <alec@alec.pl> |
  16. +-----------------------------------------------------------------------+
  17. */
  18. /**
  19. * Roundcube Framework Initialization
  20. *
  21. * @package Framework
  22. * @subpackage Core
  23. */
  24. $config = array(
  25. 'error_reporting' => E_ALL & ~E_NOTICE & ~E_STRICT,
  26. // Some users are not using Installer, so we'll check some
  27. // critical PHP settings here. Only these, which doesn't provide
  28. // an error/warning in the logs later. See (#1486307).
  29. 'mbstring.func_overload' => 0,
  30. );
  31. // check these additional ini settings if not called via CLI
  32. if (php_sapi_name() != 'cli') {
  33. $config += array(
  34. 'suhosin.session.encrypt' => false,
  35. 'file_uploads' => true,
  36. );
  37. }
  38. foreach ($config as $optname => $optval) {
  39. $ini_optval = filter_var(ini_get($optname), is_bool($optval) ? FILTER_VALIDATE_BOOLEAN : FILTER_VALIDATE_INT);
  40. if ($optval != $ini_optval && @ini_set($optname, $optval) === false) {
  41. $optval = !is_bool($optval) ? $optval : ($optval ? 'On' : 'Off');
  42. $error = "ERROR: Wrong '$optname' option value and it wasn't possible to set it to required value ($optval).\n"
  43. . "Check your PHP configuration (including php_admin_flag).";
  44. if (defined('STDERR')) fwrite(STDERR, $error); else echo $error;
  45. exit(1);
  46. }
  47. }
  48. // framework constants
  49. define('RCUBE_VERSION', '1.3.6');
  50. define('RCUBE_CHARSET', 'UTF-8');
  51. if (!defined('RCUBE_LIB_DIR')) {
  52. define('RCUBE_LIB_DIR', __DIR__ . '/');
  53. }
  54. if (!defined('RCUBE_INSTALL_PATH')) {
  55. define('RCUBE_INSTALL_PATH', RCUBE_LIB_DIR);
  56. }
  57. if (!defined('RCUBE_CONFIG_DIR')) {
  58. define('RCUBE_CONFIG_DIR', RCUBE_INSTALL_PATH . 'config/');
  59. }
  60. if (!defined('RCUBE_PLUGINS_DIR')) {
  61. define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'plugins/');
  62. }
  63. if (!defined('RCUBE_LOCALIZATION_DIR')) {
  64. define('RCUBE_LOCALIZATION_DIR', RCUBE_INSTALL_PATH . 'localization/');
  65. }
  66. // set internal encoding for mbstring extension
  67. if (function_exists('mb_internal_encoding')) {
  68. mb_internal_encoding(RCUBE_CHARSET);
  69. }
  70. if (function_exists('mb_regex_encoding')) {
  71. mb_regex_encoding(RCUBE_CHARSET);
  72. }
  73. // make sure the Roundcube lib directory is in the include_path
  74. $rcube_path = realpath(RCUBE_LIB_DIR . '..');
  75. $sep = PATH_SEPARATOR;
  76. $regexp = "!(^|$sep)" . preg_quote($rcube_path, '!') . "($sep|\$)!";
  77. $path = ini_get('include_path');
  78. if (!preg_match($regexp, $path)) {
  79. set_include_path($path . PATH_SEPARATOR . $rcube_path);
  80. }
  81. // Register autoloader
  82. spl_autoload_register('rcube_autoload');
  83. // set PEAR error handling (will also load the PEAR main class)
  84. PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
  85. /**
  86. * Similar function as in_array() but case-insensitive with multibyte support.
  87. *
  88. * @param string $needle Needle value
  89. * @param array $heystack Array to search in
  90. *
  91. * @return boolean True if found, False if not
  92. */
  93. function in_array_nocase($needle, $haystack)
  94. {
  95. // use much faster method for ascii
  96. if (is_ascii($needle)) {
  97. foreach ((array) $haystack as $value) {
  98. if (strcasecmp($value, $needle) === 0) {
  99. return true;
  100. }
  101. }
  102. }
  103. else {
  104. $needle = mb_strtolower($needle);
  105. foreach ((array) $haystack as $value) {
  106. if ($needle === mb_strtolower($value)) {
  107. return true;
  108. }
  109. }
  110. }
  111. return false;
  112. }
  113. /**
  114. * Parse a human readable string for a number of bytes.
  115. *
  116. * @param string $str Input string
  117. *
  118. * @return float Number of bytes
  119. */
  120. function parse_bytes($str)
  121. {
  122. if (is_numeric($str)) {
  123. return floatval($str);
  124. }
  125. if (preg_match('/([0-9\.]+)\s*([a-z]*)/i', $str, $regs)) {
  126. $bytes = floatval($regs[1]);
  127. switch (strtolower($regs[2])) {
  128. case 'g':
  129. case 'gb':
  130. $bytes *= 1073741824;
  131. break;
  132. case 'm':
  133. case 'mb':
  134. $bytes *= 1048576;
  135. break;
  136. case 'k':
  137. case 'kb':
  138. $bytes *= 1024;
  139. break;
  140. }
  141. }
  142. return floatval($bytes);
  143. }
  144. /**
  145. * Make sure the string ends with a slash
  146. */
  147. function slashify($str)
  148. {
  149. return unslashify($str).'/';
  150. }
  151. /**
  152. * Remove slashes at the end of the string
  153. */
  154. function unslashify($str)
  155. {
  156. return preg_replace('/\/+$/', '', $str);
  157. }
  158. /**
  159. * Returns number of seconds for a specified offset string.
  160. *
  161. * @param string $str String representation of the offset (e.g. 20min, 5h, 2days, 1week)
  162. *
  163. * @return int Number of seconds
  164. */
  165. function get_offset_sec($str)
  166. {
  167. if (preg_match('/^([0-9]+)\s*([smhdw])/i', $str, $regs)) {
  168. $amount = (int) $regs[1];
  169. $unit = strtolower($regs[2]);
  170. }
  171. else {
  172. $amount = (int) $str;
  173. $unit = 's';
  174. }
  175. switch ($unit) {
  176. case 'w':
  177. $amount *= 7;
  178. case 'd':
  179. $amount *= 24;
  180. case 'h':
  181. $amount *= 60;
  182. case 'm':
  183. $amount *= 60;
  184. }
  185. return $amount;
  186. }
  187. /**
  188. * Create a unix timestamp with a specified offset from now.
  189. *
  190. * @param string $offset_str String representation of the offset (e.g. 20min, 5h, 2days)
  191. * @param int $factor Factor to multiply with the offset
  192. *
  193. * @return int Unix timestamp
  194. */
  195. function get_offset_time($offset_str, $factor = 1)
  196. {
  197. return time() + get_offset_sec($offset_str) * $factor;
  198. }
  199. /**
  200. * Truncate string if it is longer than the allowed length.
  201. * Replace the middle or the ending part of a string with a placeholder.
  202. *
  203. * @param string $str Input string
  204. * @param int $maxlength Max. length
  205. * @param string $placeholder Replace removed chars with this
  206. * @param bool $ending Set to True if string should be truncated from the end
  207. *
  208. * @return string Abbreviated string
  209. */
  210. function abbreviate_string($str, $maxlength, $placeholder = '...', $ending = false)
  211. {
  212. $length = mb_strlen($str);
  213. if ($length > $maxlength) {
  214. if ($ending) {
  215. return mb_substr($str, 0, $maxlength) . $placeholder;
  216. }
  217. $placeholder_length = mb_strlen($placeholder);
  218. $first_part_length = floor(($maxlength - $placeholder_length)/2);
  219. $second_starting_location = $length - $maxlength + $first_part_length + $placeholder_length;
  220. $prefix = mb_substr($str, 0, $first_part_length);
  221. $suffix = mb_substr($str, $second_starting_location);
  222. $str = $prefix . $placeholder . $suffix;
  223. }
  224. return $str;
  225. }
  226. /**
  227. * Get all keys from array (recursive).
  228. *
  229. * @param array $array Input array
  230. *
  231. * @return array List of array keys
  232. */
  233. function array_keys_recursive($array)
  234. {
  235. $keys = array();
  236. if (!empty($array) && is_array($array)) {
  237. foreach ($array as $key => $child) {
  238. $keys[] = $key;
  239. foreach (array_keys_recursive($child) as $val) {
  240. $keys[] = $val;
  241. }
  242. }
  243. }
  244. return $keys;
  245. }
  246. /**
  247. * Remove all non-ascii and non-word chars except ., -, _
  248. */
  249. function asciiwords($str, $css_id = false, $replace_with = '')
  250. {
  251. $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : '');
  252. return preg_replace("/[^$allowed]/i", $replace_with, $str);
  253. }
  254. /**
  255. * Check if a string contains only ascii characters
  256. *
  257. * @param string $str String to check
  258. * @param bool $control_chars Includes control characters
  259. *
  260. * @return bool
  261. */
  262. function is_ascii($str, $control_chars = true)
  263. {
  264. $regexp = $control_chars ? '/[^\x00-\x7F]/' : '/[^\x20-\x7E]/';
  265. return preg_match($regexp, $str) ? false : true;
  266. }
  267. /**
  268. * Compose a valid representation of name and e-mail address
  269. *
  270. * @param string $email E-mail address
  271. * @param string $name Person name
  272. *
  273. * @return string Formatted string
  274. */
  275. function format_email_recipient($email, $name = '')
  276. {
  277. $email = trim($email);
  278. if ($name && $name != $email) {
  279. // Special chars as defined by RFC 822 need to in quoted string (or escaped).
  280. if (preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name)) {
  281. $name = '"'.addcslashes($name, '"').'"';
  282. }
  283. return "$name <$email>";
  284. }
  285. return $email;
  286. }
  287. /**
  288. * Format e-mail address
  289. *
  290. * @param string $email E-mail address
  291. *
  292. * @return string Formatted e-mail address
  293. */
  294. function format_email($email)
  295. {
  296. $email = trim($email);
  297. $parts = explode('@', $email);
  298. $count = count($parts);
  299. if ($count > 1) {
  300. $parts[$count-1] = mb_strtolower($parts[$count-1]);
  301. $email = implode('@', $parts);
  302. }
  303. return $email;
  304. }
  305. /**
  306. * Fix version number so it can be used correctly in version_compare()
  307. *
  308. * @param string $version Version number string
  309. *
  310. * @param return Version number string
  311. */
  312. function version_parse($version)
  313. {
  314. return str_replace(
  315. array('-stable', '-git'),
  316. array('.0', '.99'),
  317. $version
  318. );
  319. }
  320. /**
  321. * intl replacement functions
  322. */
  323. if (!function_exists('idn_to_utf8'))
  324. {
  325. function idn_to_utf8($domain)
  326. {
  327. static $idn, $loaded;
  328. if (!$loaded) {
  329. $idn = new Net_IDNA2();
  330. $loaded = true;
  331. }
  332. if ($idn && $domain && preg_match('/(^|\.)xn--/i', $domain)) {
  333. try {
  334. $domain = $idn->decode($domain);
  335. }
  336. catch (Exception $e) {
  337. }
  338. }
  339. return $domain;
  340. }
  341. }
  342. if (!function_exists('idn_to_ascii'))
  343. {
  344. function idn_to_ascii($domain)
  345. {
  346. static $idn, $loaded;
  347. if (!$loaded) {
  348. $idn = new Net_IDNA2();
  349. $loaded = true;
  350. }
  351. if ($idn && $domain && preg_match('/[^\x20-\x7E]/', $domain)) {
  352. try {
  353. $domain = $idn->encode($domain);
  354. }
  355. catch (Exception $e) {
  356. }
  357. }
  358. return $domain;
  359. }
  360. }
  361. /**
  362. * Use PHP5 autoload for dynamic class loading
  363. *
  364. * @todo Make Zend, PEAR etc play with this
  365. * @todo Make our classes conform to a more straight forward CS.
  366. */
  367. function rcube_autoload($classname)
  368. {
  369. if (strpos($classname, 'rcube') === 0) {
  370. $classname = 'Roundcube/' . $classname;
  371. }
  372. else if (strpos($classname, 'html_') === 0 || $classname === 'html') {
  373. $classname = 'Roundcube/html';
  374. }
  375. else if (strpos($classname, 'Mail_') === 0) {
  376. $classname = 'Mail/' . substr($classname, 5);
  377. }
  378. else if (strpos($classname, 'Net_') === 0) {
  379. $classname = 'Net/' . substr($classname, 4);
  380. }
  381. else if (strpos($classname, 'Auth_') === 0) {
  382. $classname = 'Auth/' . substr($classname, 5);
  383. }
  384. // Translate PHP namespaces into directories,
  385. // i.e. use \Sabre\VObject; $vcf = VObject\Reader::read(...)
  386. // -> Sabre/VObject/Reader.php
  387. $classname = str_replace('\\', '/', $classname);
  388. if ($fp = @fopen("$classname.php", 'r', true)) {
  389. fclose($fp);
  390. include_once "$classname.php";
  391. return true;
  392. }
  393. return false;
  394. }
  395. /**
  396. * Local callback function for PEAR errors
  397. */
  398. function rcube_pear_error($err)
  399. {
  400. $msg = sprintf("ERROR: %s (%s)", $err->getMessage(), $err->getCode());
  401. if ($info = $err->getUserinfo()) {
  402. $msg .= ': ' . $info;
  403. }
  404. error_log($msg, 0);
  405. }