| | |
| | | |
| | | /* |
| | | +-----------------------------------------------------------------------+ |
| | | | program/include/rcube_utils.php | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2008-2012, The Roundcube Dev Team | |
| | | | Copyright (C) 2011-2012, Kolab Systems AG | |
| | |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-----------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | |
| | | /** |
| | | * Utility class providing common functions |
| | |
| | | { |
| | | // IPv6, but there's no build-in IPv6 support |
| | | if (strpos($ip, ':') !== false && !defined('AF_INET6')) { |
| | | $parts = explode(':', $domain_part); |
| | | $parts = explode(':', $ip); |
| | | $count = count($parts); |
| | | |
| | | if ($count > 8 || $count < 2) { |
| | |
| | | return $value; |
| | | } |
| | | |
| | | // strip single quotes if magic_quotes_sybase is enabled |
| | | if (ini_get('magic_quotes_sybase')) { |
| | | $value = str_replace("''", "'", $value); |
| | | } |
| | | // strip slashes if magic_quotes enabled |
| | | else if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) { |
| | | if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) { |
| | | $value = stripslashes($value); |
| | | } |
| | | |
| | |
| | | * Convert array of request parameters (prefixed with _) |
| | | * to a regular array with non-prefixed keys. |
| | | * |
| | | * @param int $mode Source to get value from (GPC) |
| | | * @param string $ignore PCRE expression to skip parameters by name |
| | | * @param int $mode Source to get value from (GPC) |
| | | * @param string $ignore PCRE expression to skip parameters by name |
| | | * @param boolean $allow_html Allow HTML tags in field value |
| | | * |
| | | * @return array Hash array with all request parameters |
| | | */ |
| | | public static function request2param($mode = null, $ignore = 'task|action') |
| | | public static function request2param($mode = null, $ignore = 'task|action', $allow_html = false) |
| | | { |
| | | $out = array(); |
| | | $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST); |
| | | |
| | | foreach ($src as $key => $value) { |
| | | foreach (array_keys($src) as $key) { |
| | | $fname = $key[0] == '_' ? substr($key, 1) : $key; |
| | | if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) { |
| | | $out[$fname] = self::get_input_value($key, $mode); |
| | | $out[$fname] = self::get_input_value($key, $mode, $allow_html); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Create an edit field for inclusion on a form |
| | | * |
| | | * @param string col field name |
| | | * @param string value field value |
| | | * @param array attrib HTML element attributes for field |
| | | * @param string type HTML element type (default 'text') |
| | | * |
| | | * @return string HTML field definition |
| | | */ |
| | | public static function get_edit_field($col, $value, $attrib, $type = 'text') |
| | | { |
| | | static $colcounts = array(); |
| | | |
| | | $fname = '_'.$col; |
| | | $attrib['name'] = $fname . ($attrib['array'] ? '[]' : ''); |
| | | $attrib['class'] = trim($attrib['class'] . ' ff_' . $col); |
| | | |
| | | if ($type == 'checkbox') { |
| | | $attrib['value'] = '1'; |
| | | $input = new html_checkbox($attrib); |
| | | } |
| | | else if ($type == 'textarea') { |
| | | $attrib['cols'] = $attrib['size']; |
| | | $input = new html_textarea($attrib); |
| | | } |
| | | else if ($type == 'select') { |
| | | $input = new html_select($attrib); |
| | | $input->add('---', ''); |
| | | $input->add(array_values($attrib['options']), array_keys($attrib['options'])); |
| | | } |
| | | else if ($attrib['type'] == 'password') { |
| | | $input = new html_passwordfield($attrib); |
| | | } |
| | | else { |
| | | if ($attrib['type'] != 'text' && $attrib['type'] != 'hidden') { |
| | | $attrib['type'] = 'text'; |
| | | } |
| | | $input = new html_inputfield($attrib); |
| | | } |
| | | |
| | | // use value from post |
| | | if (isset($_POST[$fname])) { |
| | | $postvalue = self::get_input_value($fname, self::INPUT_POST, true); |
| | | $value = $attrib['array'] ? $postvalue[intval($colcounts[$col]++)] : $postvalue; |
| | | } |
| | | |
| | | $out = $input->show($value); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Replace all css definitions with #container [def] |
| | | * and remove css-inlined scripting |
| | | * |
| | |
| | | $source = self::xss_entity_decode($source); |
| | | $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); |
| | | $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); |
| | | |
| | | if (preg_match("/$evilexpr/i", $stripped)) { |
| | | return '/* evil! */'; |
| | | } |
| | | |
| | | $strict_url_regexp = '!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims'; |
| | | |
| | | // cut out all contents between { and } |
| | | while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { |
| | | $styles = substr($source, $pos+1, $pos2-($pos+1)); |
| | | $length = $pos2 - $pos - 1; |
| | | $styles = substr($source, $pos+1, $length); |
| | | |
| | | // check every line of a style block... |
| | | if ($allow_remote) { |
| | | $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); |
| | | |
| | | foreach ($a_styles as $line) { |
| | | $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); |
| | | // ... and only allow strict url() values |
| | | $regexp = '!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims'; |
| | | if (stripos($stripped, 'url(') && !preg_match($regexp, $line)) { |
| | | if (stripos($stripped, 'url(') && !preg_match($strict_url_regexp, $line)) { |
| | | $a_styles = array('/* evil! */'); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | $styles = join(";\n", $a_styles); |
| | | } |
| | | |
| | | $key = $replacements->add($styles); |
| | | $source = substr($source, 0, $pos+1) |
| | | . $replacements->get_replacement($key) |
| | | . substr($source, $pos2, strlen($source)-$pos2); |
| | | $last_pos = $pos+2; |
| | | $key = $replacements->add($styles); |
| | | $repl = $replacements->get_replacement($key); |
| | | $source = substr_replace($source, $repl, $pos+1, $length); |
| | | $last_pos = $pos2 - ($length - strlen($repl)); |
| | | } |
| | | |
| | | // remove html comments and add #container to each tag selector. |
| | | // also replace body definition because we also stripped off the <body> tag |
| | | $styles = preg_replace( |
| | | $source = preg_replace( |
| | | array( |
| | | '/(^\s*<!--)|(-->\s*$)/', |
| | | '/(^\s*<\!--)|(-->\s*$)/m', |
| | | '/(^\s*|,\s*|\}\s*)([a-z0-9\._#\*][a-z0-9\.\-_]*)/im', |
| | | '/'.preg_quote($container_id, '/').'\s+body/i', |
| | | ), |
| | |
| | | $source); |
| | | |
| | | // put block contents back in |
| | | $styles = $replacements->resolve($styles); |
| | | $source = $replacements->resolve($source); |
| | | |
| | | return $styles; |
| | | return $source; |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | public static function file2class($mimetype, $filename) |
| | | { |
| | | $mimetype = strtolower($mimetype); |
| | | $filename = strtolower($filename); |
| | | |
| | | list($primary, $secondary) = explode('/', $mimetype); |
| | | |
| | | $classes = array($primary ? $primary : 'unknown'); |
| | | |
| | | if ($secondary) { |
| | | $classes[] = $secondary; |
| | | } |
| | | if (preg_match('/\.([a-z0-9]+)$/i', $filename, $m)) { |
| | | $classes[] = $m[1]; |
| | | |
| | | if (preg_match('/\.([a-z0-9]+)$/', $filename, $m)) { |
| | | if (!in_array($m[1], $classes)) { |
| | | $classes[] = $m[1]; |
| | | } |
| | | } |
| | | |
| | | return strtolower(join(" ", $classes)); |
| | | return join(" ", $classes); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the real remote IP address |
| | | * |
| | | * @return string Remote IP address |
| | | */ |
| | | public static function remote_addr() |
| | | { |
| | | foreach (array('HTTP_X_FORWARDED_FOR','HTTP_X_REAL_IP','REMOTE_ADDR') as $prop) { |
| | | if (!empty($_SERVER[$prop])) |
| | | return $_SERVER[$prop]; |
| | | } |
| | | |
| | | return ''; |
| | | } |
| | | |
| | | /** |
| | | * Read a specific HTTP request header. |
| | | * |
| | | * @param string $name Header name |
| | |
| | | */ |
| | | public static function strtotime($date) |
| | | { |
| | | $date = trim($date); |
| | | |
| | | // check for MS Outlook vCard date format YYYYMMDD |
| | | if (preg_match('/^([12][90]\d\d)([01]\d)(\d\d)$/', trim($date), $matches)) { |
| | | return mktime(0,0,0, intval($matches[2]), intval($matches[3]), intval($matches[1])); |
| | | } |
| | | else if (is_numeric($date)) { |
| | | return $date; |
| | | if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) { |
| | | return mktime(0,0,0, intval($m[2]), intval($m[3]), intval($m[1])); |
| | | } |
| | | |
| | | // support non-standard "GMTXXXX" literal |
| | | $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); |
| | | // common little-endian formats, e.g. dd/mm/yyyy (not all are supported by strtotime) |
| | | if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m) |
| | | && $m[1] > 0 && $m[1] <= 31 && $m[2] > 0 && $m[2] <= 12 && $m[3] >= 1970 |
| | | ) { |
| | | return mktime(0,0,0, intval($m[2]), intval($m[1]), intval($m[3])); |
| | | } |
| | | |
| | | // unix timestamp |
| | | if (is_numeric($date)) { |
| | | return (int) $date; |
| | | } |
| | | |
| | | // Clean malformed data |
| | | $date = preg_replace( |
| | | array( |
| | | '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal |
| | | '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters |
| | | '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names |
| | | ), |
| | | array( |
| | | '\\1', |
| | | '', |
| | | '', |
| | | ), $date); |
| | | |
| | | $date = trim($date); |
| | | |
| | | // if date parsing fails, we have a date in non-rfc format. |
| | | // remove token from the end and try again |
| | |
| | | $date = implode(' ', $d); |
| | | } |
| | | |
| | | return $ts; |
| | | return (int) $ts; |
| | | } |
| | | |
| | | /** |
| | | * Date parsing function that turns the given value into a DateTime object |
| | | * |
| | | * @param string $date Date string |
| | | * |
| | | * @return object DateTime instance or false on failure |
| | | */ |
| | | public static function anytodatetime($date) |
| | | { |
| | | if (is_object($date) && is_a($date, 'DateTime')) { |
| | | return $date; |
| | | } |
| | | |
| | | $dt = false; |
| | | $date = trim($date); |
| | | |
| | | // try to parse string with DateTime first |
| | | if (!empty($date)) { |
| | | try { |
| | | $dt = new DateTime($date); |
| | | } |
| | | catch (Exception $e) { |
| | | // ignore |
| | | } |
| | | } |
| | | |
| | | // try our advanced strtotime() method |
| | | if (!$dt && ($timestamp = self::strtotime($date))) { |
| | | try { |
| | | $dt = new DateTime("@".$timestamp); |
| | | } |
| | | catch (Exception $e) { |
| | | // ignore |
| | | } |
| | | } |
| | | |
| | | return $dt; |
| | | } |
| | | |
| | | /* |
| | | * Idn_to_ascii wrapper. |