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