| | |
| | | } |
| | | |
| | | foreach ($domain_array as $part) { |
| | | if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) { |
| | | if (!preg_match('/^((xn--)?([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // last domain part |
| | | if (preg_match('/[^a-zA-Z]/', array_pop($domain_array))) { |
| | | $last_part = array_pop($domain_array); |
| | | if (strpos($last_part, 'xn--') !== 0 && preg_match('/[^a-zA-Z]/', $last_part)) { |
| | | return false; |
| | | } |
| | | |
| | |
| | | |
| | | if (!$dns_check || !$rcube->config->get('email_dns_check')) { |
| | | return true; |
| | | } |
| | | |
| | | if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { |
| | | $lookup = array(); |
| | | @exec("nslookup -type=MX " . escapeshellarg($domain_part) . " 2>&1", $lookup); |
| | | foreach ($lookup as $line) { |
| | | if (strpos($line, 'MX preference')) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // find MX record(s) |
| | |
| | | */ |
| | | public static function https_check($port=null, $use_https=true) |
| | | { |
| | | global $RCMAIL; |
| | | |
| | | if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') { |
| | | return true; |
| | | } |
| | | if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') { |
| | | if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) |
| | | && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' |
| | | && in_array($_SERVER['REMOTE_ADDR'], rcube::get_instance()->config->get('proxy_whitelist', array()))) { |
| | | return true; |
| | | } |
| | | if ($port && $_SERVER['SERVER_PORT'] == $port) { |
| | | return true; |
| | | } |
| | | if ($use_https && isset($RCMAIL) && $RCMAIL->config->get('use_https')) { |
| | | if ($use_https && rcube::get_instance()->config->get('use_https')) { |
| | | return true; |
| | | } |
| | | |
| | |
| | | */ |
| | | public static function remote_addr() |
| | | { |
| | | if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { |
| | | $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); |
| | | return $hosts[0]; |
| | | } |
| | | // Check if any of the headers are set first to improve performance |
| | | if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_X_REAL_IP'])) { |
| | | $proxy_whitelist = rcube::get_instance()->config->get('proxy_whitelist', array()); |
| | | if (in_array($_SERVER['REMOTE_ADDR'], $proxy_whitelist)) { |
| | | if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { |
| | | foreach(array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $forwarded_ip) { |
| | | if (!in_array($forwarded_ip, $proxy_whitelist)) { |
| | | return $forwarded_ip; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!empty($_SERVER['HTTP_X_REAL_IP'])) { |
| | | return $_SERVER['HTTP_X_REAL_IP']; |
| | | if (!empty($_SERVER['HTTP_X_REAL_IP'])) { |
| | | return $_SERVER['HTTP_X_REAL_IP']; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!empty($_SERVER['REMOTE_ADDR'])) { |
| | |
| | | * Improved equivalent to strtotime() |
| | | * |
| | | * @param string $date Date string |
| | | * @param object DateTimeZone to use for DateTime object |
| | | * |
| | | * @return int Unix timestamp |
| | | */ |
| | | public static function strtotime($date) |
| | | public static function strtotime($date, $timezone = null) |
| | | { |
| | | $date = self::clean_datestr($date); |
| | | $tzname = $timezone ? ' ' . $timezone->getName() : ''; |
| | | |
| | | // unix timestamp |
| | | if (is_numeric($date)) { |
| | |
| | | |
| | | // if date parsing fails, we have a date in non-rfc format. |
| | | // remove token from the end and try again |
| | | while ((($ts = @strtotime($date)) === false) || ($ts < 0)) { |
| | | while ((($ts = @strtotime($date . $tzname)) === false) || ($ts < 0)) { |
| | | $d = explode(' ', $date); |
| | | array_pop($d); |
| | | if (!$d) { |
| | |
| | | * Date parsing function that turns the given value into a DateTime object |
| | | * |
| | | * @param string $date Date string |
| | | * @param object DateTimeZone to use for DateTime object |
| | | * |
| | | * @return object DateTime instance or false on failure |
| | | */ |
| | | public static function anytodatetime($date) |
| | | public static function anytodatetime($date, $timezone = null) |
| | | { |
| | | if (is_object($date) && is_a($date, 'DateTime')) { |
| | | return $date; |
| | |
| | | // try to parse string with DateTime first |
| | | if (!empty($date)) { |
| | | try { |
| | | $dt = new DateTime($date); |
| | | $dt = $timezone ? new DateTime($date, $timezone) : new DateTime($date); |
| | | } |
| | | catch (Exception $e) { |
| | | // ignore |
| | |
| | | } |
| | | |
| | | // try our advanced strtotime() method |
| | | if (!$dt && ($timestamp = self::strtotime($date))) { |
| | | if (!$dt && ($timestamp = self::strtotime($date, $timezone))) { |
| | | try { |
| | | $dt = new DateTime("@".$timestamp); |
| | | if ($timezone) { |
| | | $dt->setTimezone($timezone); |
| | | } |
| | | } |
| | | catch (Exception $e) { |
| | | // ignore |
| | |
| | | * Split the given string into word tokens |
| | | * |
| | | * @param string Input to tokenize |
| | | * @param integer Minimum length of a single token |
| | | * @return array List of tokens |
| | | */ |
| | | public static function tokenize_string($str) |
| | | public static function tokenize_string($str, $minlen = 2) |
| | | { |
| | | return explode(" ", preg_replace( |
| | | array('/[\s;\/+-]+/i', '/(\d)[-.\s]+(\d)/', '/\s\w{1,3}\s/u'), |
| | | array(' ', '\\1\\2', ' '), |
| | | $str)); |
| | | $expr = array('/[\s;\/+-]+/ui', '/(\d)[-.\s]+(\d)/u'); |
| | | $repl = array(' ', '\\1\\2'); |
| | | |
| | | if ($minlen > 1) { |
| | | $minlen--; |
| | | $expr[] = "/(^|\s+)\w{1,$minlen}(\s+|$)/u"; |
| | | $repl[] = ' '; |
| | | } |
| | | |
| | | return array_filter(explode(" ", preg_replace($expr, $repl, $str))); |
| | | } |
| | | |
| | | /** |
| | | * Normalize the given string for fulltext search. |
| | | * Currently only optimized for Latin-1 characters; to be extended |
| | | * Currently only optimized for ISO-8859-1 and ISO-8859-2 characters; to be extended |
| | | * |
| | | * @param string Input string (UTF-8) |
| | | * @param boolean True to return list of words as array |
| | | * @param integer Minimum length of tokens |
| | | * |
| | | * @return mixed Normalized string or a list of normalized tokens |
| | | */ |
| | | public static function normalize_string($str, $as_array = false) |
| | | public static function normalize_string($str, $as_array = false, $minlen = 2) |
| | | { |
| | | // replace 4-byte unicode characters with '?' character, |
| | | // these are not supported in default utf-8 charset on mysql, |
| | |
| | | . ')/', '?', $str); |
| | | |
| | | // split by words |
| | | $arr = self::tokenize_string($str); |
| | | $arr = self::tokenize_string($str, $minlen); |
| | | |
| | | // detect character set |
| | | if (utf8_encode(utf8_decode($str)) == $str) { |
| | | // ISO-8859-1 (or ASCII) |
| | | preg_match_all('/./u', 'äâàåáãæçéêëèïîìíñöôòøõóüûùúýÿ', $keys); |
| | | preg_match_all('/./', 'aaaaaaaceeeeiiiinoooooouuuuyy', $values); |
| | | |
| | | $mapping = array_combine($keys[0], $values[0]); |
| | | $mapping = array_merge($mapping, array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u')); |
| | | } |
| | | else if (rcube_charset::convert(rcube_charset::convert($str, 'UTF-8', 'ISO-8859-2'), 'ISO-8859-2', 'UTF-8') == $str) { |
| | | // ISO-8859-2 |
| | | preg_match_all('/./u', 'ąáâäćçčéęëěíîłľĺńňóôöŕřśšşťţůúűüźžżý', $keys); |
| | | preg_match_all('/./', 'aaaaccceeeeiilllnnooorrsssttuuuuzzzy', $values); |
| | | |
| | | $mapping = array_combine($keys[0], $values[0]); |
| | | $mapping = array_merge($mapping, array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u')); |
| | | } |
| | | |
| | | foreach ($arr as $i => $part) { |
| | | if (utf8_encode(utf8_decode($part)) == $part) { // is latin-1 ? |
| | | $arr[$i] = utf8_encode(strtr(strtolower(strtr(utf8_decode($part), |
| | | 'ÇçäâàåéêëèïîìÅÉöôòüûùÿøØáíóúñÑÁÂÀãÃÊËÈÍÎÏÓÔõÕÚÛÙýÝ', |
| | | 'ccaaaaeeeeiiiaeooouuuyooaiounnaaaaaeeeiiioooouuuyy')), |
| | | array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u'))); |
| | | $part = mb_strtolower($part); |
| | | |
| | | if (!empty($mapping)) { |
| | | $part = strtr($part, $mapping); |
| | | } |
| | | else |
| | | $arr[$i] = mb_strtolower($part); |
| | | |
| | | $arr[$i] = $part; |
| | | } |
| | | |
| | | return $as_array ? $arr : join(" ", $arr); |
| | | } |
| | | |
| | | /** |
| | | * Compare two strings for matching words (order not relevant) |
| | | * |
| | | * @param string Haystack |
| | | * @param string Needle |
| | | * @return boolen True if match, False otherwise |
| | | */ |
| | | public static function words_match($haystack, $needle) |
| | | { |
| | | $a_needle = self::tokenize_string($needle, 1); |
| | | $_haystack = join(" ", self::tokenize_string($haystack, 1)); |
| | | $valid = strlen($_haystack) > 0; |
| | | $hits = 0; |
| | | |
| | | foreach ($a_needle as $w) { |
| | | if ($valid) { |
| | | if (stripos($_haystack, $w) !== false) { |
| | | $hits++; |
| | | } |
| | | } |
| | | else if (stripos($haystack, $w) !== false) { |
| | | $hits++; |
| | | } |
| | | } |
| | | |
| | | return $hits >= count($a_needle); |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Find out if the string content means true or false |
| | | * |
| | |
| | | return (bool) preg_match('!^[a-z]:[\\\\/]!i', $path); |
| | | } |
| | | else { |
| | | return $path[0] == DIRECTORY_SEPARATOR; |
| | | return $path[0] == '/'; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Resolve relative URL |
| | | * |
| | | * @param string $url Relative URL |
| | | * |
| | | * @return string Absolute URL |
| | | */ |
| | | public static function resolve_url($url) |
| | | { |
| | | // prepend protocol://hostname:port |
| | | if (!preg_match('|^https?://|', $url)) { |
| | | $schema = 'http'; |
| | | $default_port = 80; |
| | | |
| | | if (self::https_check()) { |
| | | $schema = 'https'; |
| | | $default_port = 443; |
| | | } |
| | | |
| | | $prefix = $schema . '://' . preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST']); |
| | | if ($_SERVER['SERVER_PORT'] != $default_port) { |
| | | $prefix .= ':' . $_SERVER['SERVER_PORT']; |
| | | } |
| | | |
| | | $url = $prefix . ($url[0] == '/' ? '' : '/') . $url; |
| | | } |
| | | |
| | | return $url; |
| | | } |
| | | |
| | | /** |
| | | * Generate a ramdom string |
| | | * |
| | | * @param int String length |
| | | * |
| | | * @return string The generated random string |
| | | */ |
| | | public static function random_bytes($length) |
| | | { |
| | | if (function_exists('openssl_random_pseudo_bytes')) { |
| | | $random = openssl_random_pseudo_bytes(ceil($length / 2)); |
| | | $random = bin2hex($random); |
| | | |
| | | // if the length wasn't even... |
| | | if ($length < strlen($random)) { |
| | | $random = substr($random, 0, $length); |
| | | } |
| | | } |
| | | else { |
| | | $alpha = 'ABCDEFGHIJKLMNOPQERSTUVXYZabcdefghijklmnopqrtsuvwxyz0123456789+*%&?!$-_='; |
| | | $random = ''; |
| | | |
| | | for ($i = 0; $i < $length; $i++) { |
| | | $random .= $alpha[rand(0, strlen($alpha)-1)]; |
| | | } |
| | | } |
| | | |
| | | return $random; |
| | | } |
| | | } |