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