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