Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117752567
rcube_utils.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
27 KB
Referenced Files
None
Subscribers
None
rcube_utils.php
View Options
<?php
/*
+-----------------------------------------------------------------------+
| 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 |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Utility class providing common functions |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
/**
* Utility class providing common functions
*
* @package Core
*/
class
rcube_utils
{
// define constants for input reading
const
INPUT_GET
=
0x0101
;
const
INPUT_POST
=
0x0102
;
const
INPUT_GPC
=
0x0103
;
/**
* Helper method to set a cookie with the current path and host settings
*
* @param string Cookie name
* @param string Cookie value
* @param string Expiration time
*/
public
static
function
setcookie
(
$name
,
$value
,
$exp
=
0
)
{
if
(
headers_sent
())
{
return
;
}
$cookie
=
session_get_cookie_params
();
$secure
=
$cookie
[
'secure'
]
||
self
::
https_check
();
setcookie
(
$name
,
$value
,
$exp
,
$cookie
[
'path'
],
$cookie
[
'domain'
],
$secure
,
true
);
}
/**
* E-mail address validation.
*
* @param string $email Email address
* @param boolean $dns_check True to check dns
*
* @return boolean True on success, False if address is invalid
*/
public
static
function
check_email
(
$email
,
$dns_check
=
true
)
{
// Check for invalid characters
if
(
preg_match
(
'/[
\x
00-
\x
1F
\x
7F-
\x
FF]/'
,
$email
))
{
return
false
;
}
// Check for length limit specified by RFC 5321 (#1486453)
if
(
strlen
(
$email
)
>
254
)
{
return
false
;
}
$email_array
=
explode
(
'@'
,
$email
);
// Check that there's one @ symbol
if
(
count
(
$email_array
)
<
2
)
{
return
false
;
}
$domain_part
=
array_pop
(
$email_array
);
$local_part
=
implode
(
'@'
,
$email_array
);
// from PEAR::Validate
$regexp
=
'&^(?:
("
\s
*(?:[^"
\f\n\r\t\v\b\s
]+
\s
*)+")| #1 quoted name
([-
\w
!
\#\$
%
\&\'
*+~/^`|{}=]+(?:
\.
[-
\w
!
\#\$
%
\&\'
*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322)
$&xi'
;
if
(!
preg_match
(
$regexp
,
$local_part
))
{
return
false
;
}
// Validate domain part
if
(
preg_match
(
'/^
\[
((IPv6:[0-9a-f:.]+)|([0-9.]+))
\]
$/i'
,
$domain_part
,
$matches
))
{
return
self
::
check_ip
(
preg_replace
(
'/^IPv6:/i'
,
''
,
$matches
[
1
]));
// valid IPv4 or IPv6 address
}
else
{
// If not an IP address
$domain_array
=
explode
(
'.'
,
$domain_part
);
// Not enough parts to be a valid domain
if
(
sizeof
(
$domain_array
)
<
2
)
{
return
false
;
}
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
))
{
return
false
;
}
}
// last domain part
if
(
preg_match
(
'/[^a-zA-Z]/'
,
array_pop
(
$domain_array
)))
{
return
false
;
}
$rcube
=
rcube
::
get_instance
();
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)
if
(
getmxrr
(
$domain_part
,
$mx_records
))
{
return
true
;
}
// find any DNS record
if
(
checkdnsrr
(
$domain_part
,
'ANY'
))
{
return
true
;
}
}
return
false
;
}
/**
* Validates IPv4 or IPv6 address
*
* @param string $ip IP address in v4 or v6 format
*
* @return bool True if the address is valid
*/
public
static
function
check_ip
(
$ip
)
{
// IPv6, but there's no build-in IPv6 support
if
(
strpos
(
$ip
,
':'
)
!==
false
&&
!
defined
(
'AF_INET6'
))
{
$parts
=
explode
(
':'
,
$domain_part
);
$count
=
count
(
$parts
);
if
(
$count
>
8
||
$count
<
2
)
{
return
false
;
}
foreach
(
$parts
as
$idx
=>
$part
)
{
$length
=
strlen
(
$part
);
if
(!
$length
)
{
// there can be only one ::
if
(
$found_empty
)
{
return
false
;
}
$found_empty
=
true
;
}
// last part can be an IPv4 address
else
if
(
$idx
==
$count
-
1
)
{
if
(!
preg_match
(
'/^[0-9a-f]{1,4}$/i'
,
$part
))
{
return
@
inet_pton
(
$part
)
!==
false
;
}
}
else
if
(!
preg_match
(
'/^[0-9a-f]{1,4}$/i'
,
$part
))
{
return
false
;
}
}
return
true
;
}
return
@
inet_pton
(
$ip
)
!==
false
;
}
/**
* Check whether the HTTP referer matches the current request
*
* @return boolean True if referer is the same host+path, false if not
*/
public
static
function
check_referer
()
{
$uri
=
parse_url
(
$_SERVER
[
'REQUEST_URI'
]);
$referer
=
parse_url
(
self
::
request_header
(
'Referer'
));
return
$referer
[
'host'
]
==
self
::
request_header
(
'Host'
)
&&
$referer
[
'path'
]
==
$uri
[
'path'
];
}
/**
* Replacing specials characters to a specific encoding type
*
* @param string Input string
* @param string Encoding type: text|html|xml|js|url
* @param string Replace mode for tags: show|replace|remove
* @param boolean Convert newlines
*
* @return string The quoted string
*/
public
static
function
rep_specialchars_output
(
$str
,
$enctype
=
''
,
$mode
=
''
,
$newlines
=
true
)
{
static
$html_encode_arr
=
false
;
static
$js_rep_table
=
false
;
static
$xml_rep_table
=
false
;
// encode for HTML output
if
(
$enctype
==
'html'
)
{
if
(!
$html_encode_arr
)
{
$html_encode_arr
=
get_html_translation_table
(
HTML_SPECIALCHARS
);
unset
(
$html_encode_arr
[
'?'
]);
}
$encode_arr
=
$html_encode_arr
;
// don't replace quotes and html tags
if
(
$mode
==
'show'
||
$mode
==
''
)
{
$ltpos
=
strpos
(
$str
,
'<'
);
if
(
$ltpos
!==
false
&&
strpos
(
$str
,
'>'
,
$ltpos
)
!==
false
)
{
unset
(
$encode_arr
[
'"'
]);
unset
(
$encode_arr
[
'<'
]);
unset
(
$encode_arr
[
'>'
]);
unset
(
$encode_arr
[
'&'
]);
}
}
else
if
(
$mode
==
'remove'
)
{
$str
=
strip_tags
(
$str
);
}
$out
=
strtr
(
$str
,
$encode_arr
);
// avoid douple quotation of &
$out
=
preg_replace
(
'/&([A-Za-z]{2,6}|#[0-9]{2,4});/'
,
'&
\\
1;'
,
$out
);
return
$newlines
?
nl2br
(
$out
)
:
$out
;
}
// if the replace tables for XML and JS are not yet defined
if
(
$js_rep_table
===
false
)
{
$js_rep_table
=
$xml_rep_table
=
array
();
$xml_rep_table
[
'&'
]
=
'&'
;
// can be increased to support more charsets
for
(
$c
=
160
;
$c
<
256
;
$c
++)
{
$xml_rep_table
[
chr
(
$c
)]
=
"&#$c;"
;
}
$xml_rep_table
[
'"'
]
=
'"'
;
$js_rep_table
[
'"'
]
=
'
\\
"'
;
$js_rep_table
[
"'"
]
=
"
\\
'"
;
$js_rep_table
[
"
\\
"
]
=
"
\\\\
"
;
// Unicode line and paragraph separators (#1486310)
$js_rep_table
[
chr
(
hexdec
(
E2
)).
chr
(
hexdec
(
80
)).
chr
(
hexdec
(
A8
))]
=
'
'
;
$js_rep_table
[
chr
(
hexdec
(
E2
)).
chr
(
hexdec
(
80
)).
chr
(
hexdec
(
A9
))]
=
'
'
;
}
// encode for javascript use
if
(
$enctype
==
'js'
)
{
return
preg_replace
(
array
(
"/
\r
?
\n
/"
,
"/
\r
/"
,
'/<
\\
//'
),
array
(
'
\n
'
,
'
\n
'
,
'<
\\
/'
),
strtr
(
$str
,
$js_rep_table
));
}
// encode for plaintext
if
(
$enctype
==
'text'
)
{
return
str_replace
(
"
\r\n
"
,
"
\n
"
,
$mode
==
'remove'
?
strip_tags
(
$str
)
:
$str
);
}
if
(
$enctype
==
'url'
)
{
return
rawurlencode
(
$str
);
}
// encode for XML
if
(
$enctype
==
'xml'
)
{
return
strtr
(
$str
,
$xml_rep_table
);
}
// no encoding given -> return original string
return
$str
;
}
/**
* Read input value and convert it for internal use
* Performs stripslashes() and charset conversion if necessary
*
* @param string Field name to read
* @param int Source to get value from (GPC)
* @param boolean Allow HTML tags in field value
* @param string Charset to convert into
*
* @return string Field value or NULL if not available
*/
public
static
function
get_input_value
(
$fname
,
$source
,
$allow_html
=
FALSE
,
$charset
=
NULL
)
{
$value
=
NULL
;
if
(
$source
==
self
::
INPUT_GET
)
{
if
(
isset
(
$_GET
[
$fname
]))
{
$value
=
$_GET
[
$fname
];
}
}
else
if
(
$source
==
self
::
INPUT_POST
)
{
if
(
isset
(
$_POST
[
$fname
]))
{
$value
=
$_POST
[
$fname
];
}
}
else
if
(
$source
==
self
::
INPUT_GPC
)
{
if
(
isset
(
$_POST
[
$fname
]))
{
$value
=
$_POST
[
$fname
];
}
else
if
(
isset
(
$_GET
[
$fname
]))
{
$value
=
$_GET
[
$fname
];
}
else
if
(
isset
(
$_COOKIE
[
$fname
]))
{
$value
=
$_COOKIE
[
$fname
];
}
}
return
self
::
parse_input_value
(
$value
,
$allow_html
,
$charset
);
}
/**
* Parse/validate input value. See self::get_input_value()
* Performs stripslashes() and charset conversion if necessary
*
* @param string Input value
* @param boolean Allow HTML tags in field value
* @param string Charset to convert into
*
* @return string Parsed value
*/
public
static
function
parse_input_value
(
$value
,
$allow_html
=
FALSE
,
$charset
=
NULL
)
{
global
$OUTPUT
;
if
(
empty
(
$value
))
{
return
$value
;
}
if
(
is_array
(
$value
))
{
foreach
(
$value
as
$idx
=>
$val
)
{
$value
[
$idx
]
=
self
::
parse_input_value
(
$val
,
$allow_html
,
$charset
);
}
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
())
{
$value
=
stripslashes
(
$value
);
}
// remove HTML tags if not allowed
if
(!
$allow_html
)
{
$value
=
strip_tags
(
$value
);
}
$output_charset
=
is_object
(
$OUTPUT
)
?
$OUTPUT
->
get_charset
()
:
null
;
// remove invalid characters (#1488124)
if
(
$output_charset
==
'UTF-8'
)
{
$value
=
rcube_charset
::
clean
(
$value
);
}
// convert to internal charset
if
(
$charset
&&
$output_charset
)
{
$value
=
rcube_charset
::
convert
(
$value
,
$output_charset
,
$charset
);
}
return
$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
*
* @return array Hash array with all request parameters
*/
public
static
function
request2param
(
$mode
=
null
,
$ignore
=
'task|action'
)
{
$out
=
array
();
$src
=
$mode
==
self
::
INPUT_GET
?
$_GET
:
(
$mode
==
self
::
INPUT_POST
?
$_POST
:
$_REQUEST
);
foreach
(
$src
as
$key
=>
$value
)
{
$fname
=
$key
[
0
]
==
'_'
?
substr
(
$key
,
1
)
:
$key
;
if
(
$ignore
&&
!
preg_match
(
'/^('
.
$ignore
.
')$/'
,
$fname
))
{
$out
[
$fname
]
=
self
::
get_input_value
(
$key
,
$mode
);
}
}
return
$out
;
}
/**
* Convert the given string into a valid HTML identifier
* Same functionality as done in app.js with rcube_webmail.html_identifier()
*/
public
static
function
html_identifier
(
$str
,
$encode
=
false
)
{
if
(
$encode
)
{
return
rtrim
(
strtr
(
base64_encode
(
$str
),
'+/'
,
'-_'
),
'='
);
}
else
{
return
asciiwords
(
$str
,
true
,
'_'
);
}
}
/**
* 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
*
* @param string CSS source code
* @param string Container ID to use as prefix
*
* @return string Modified CSS source
*/
public
static
function
mod_css_styles
(
$source
,
$container_id
,
$allow_remote
=
false
)
{
$last_pos
=
0
;
$replacements
=
new
rcube_string_replacer
;
// ignore the whole block if evil styles are detected
$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! */'
;
}
// cut out all contents between { and }
while
((
$pos
=
strpos
(
$source
,
'{'
,
$last_pos
))
&&
(
$pos2
=
strpos
(
$source
,
'}'
,
$pos
)))
{
$styles
=
substr
(
$source
,
$pos
+
1
,
$pos2
-(
$pos
+
1
));
// 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
))
{
$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
;
}
// 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
(
array
(
'/(^
\s
*<!--)|(-->
\s
*$)/'
,
'/(^
\s
*|,
\s
*|
\}\s
*)([a-z0-9
\.
_#
\*
][a-z0-9
\.\-
_]*)/im'
,
'/'
.
preg_quote
(
$container_id
,
'/'
).
'
\s
+body/i'
,
),
array
(
''
,
"
\\
1#$container_id
\\
2"
,
$container_id
,
),
$source
);
// put block contents back in
$styles
=
$replacements
->
resolve
(
$styles
);
return
$styles
;
}
/**
* Generate CSS classes from mimetype and filename extension
*
* @param string $mimetype Mimetype
* @param string $filename Filename
*
* @return string CSS classes separated by space
*/
public
static
function
file2class
(
$mimetype
,
$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
];
}
return
strtolower
(
join
(
" "
,
$classes
));
}
/**
* Decode escaped entities used by known XSS exploits.
* See http://downloads.securityfocus.com/vulnerabilities/exploits/26800.eml for examples
*
* @param string CSS content to decode
*
* @return string Decoded string
*/
public
static
function
xss_entity_decode
(
$content
)
{
$out
=
html_entity_decode
(
html_entity_decode
(
$content
));
$out
=
preg_replace_callback
(
'/
\\\(
[0-9a-f]{4})/i'
,
array
(
self
,
'xss_entity_decode_callback'
),
$out
);
$out
=
preg_replace
(
'#/
\*
.*
\*
/#Ums'
,
''
,
$out
);
return
$out
;
}
/**
* preg_replace_callback callback for xss_entity_decode
*
* @param array $matches Result from preg_replace_callback
*
* @return string Decoded entity
*/
public
static
function
xss_entity_decode_callback
(
$matches
)
{
return
chr
(
hexdec
(
$matches
[
1
]));
}
/**
* Check if we can process not exceeding memory_limit
*
* @param integer Required amount of memory
*
* @return boolean True if memory won't be exceeded, False otherwise
*/
public
static
function
mem_check
(
$need
)
{
$mem_limit
=
parse_bytes
(
ini_get
(
'memory_limit'
));
$memory
=
function_exists
(
'memory_get_usage'
)
?
memory_get_usage
()
:
16
*
1024
*
1024
;
// safe value: 16MB
return
$mem_limit
>
0
&&
$memory
+
$need
>
$mem_limit
?
false
:
true
;
}
/**
* Check if working in SSL mode
*
* @param integer $port HTTPS port number
* @param boolean $use_https Enables 'use_https' option checking
*
* @return boolean
*/
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'
)
{
return
true
;
}
if
(
$port
&&
$_SERVER
[
'SERVER_PORT'
]
==
$port
)
{
return
true
;
}
if
(
$use_https
&&
isset
(
$RCMAIL
)
&&
$RCMAIL
->
config
->
get
(
'use_https'
))
{
return
true
;
}
return
false
;
}
/**
* Replaces hostname variables.
*
* @param string $name Hostname
* @param string $host Optional IMAP hostname
*
* @return string Hostname
*/
public
static
function
parse_host
(
$name
,
$host
=
''
)
{
// %n - host
$n
=
preg_replace
(
'/:
\d
+$/'
,
''
,
$_SERVER
[
'SERVER_NAME'
]);
// %t - host name without first part, e.g. %n=mail.domain.tld, %t=domain.tld
$t
=
preg_replace
(
'/^[^
\.
]+
\.
/'
,
''
,
$n
);
// %d - domain name without first part
$d
=
preg_replace
(
'/^[^
\.
]+
\.
/'
,
''
,
$_SERVER
[
'HTTP_HOST'
]);
// %h - IMAP host
$h
=
$_SESSION
[
'storage_host'
]
?
$_SESSION
[
'storage_host'
]
:
$host
;
// %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld
$z
=
preg_replace
(
'/^[^
\.
]+
\.
/'
,
''
,
$h
);
// %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided
if
(
strpos
(
$name
,
'%s'
)
!==
false
)
{
$user_email
=
self
::
get_input_value
(
'_user'
,
self
::
INPUT_POST
);
$user_email
=
rcube_utils
::
idn_convert
(
$user_email
,
true
);
$matches
=
preg_match
(
'/(.*)@([a-z0-9
\.\-\[\]\:
]+)/i'
,
$user_email
,
$s
);
if
(
$matches
<
1
||
filter_var
(
$s
[
1
].
"@"
.
$s
[
2
],
FILTER_VALIDATE_EMAIL
)
===
false
)
{
return
false
;
}
}
$name
=
str_replace
(
array
(
'%n'
,
'%t'
,
'%d'
,
'%h'
,
'%z'
,
'%s'
),
array
(
$n
,
$t
,
$d
,
$h
,
$z
,
$s
[
2
]),
$name
);
return
$name
;
}
/**
* Returns remote IP address and forwarded addresses if found
*
* @return string Remote IP address(es)
*/
public
static
function
remote_ip
()
{
$address
=
$_SERVER
[
'REMOTE_ADDR'
];
// append the NGINX X-Real-IP header, if set
if
(!
empty
(
$_SERVER
[
'HTTP_X_REAL_IP'
]))
{
$remote_ip
[]
=
'X-Real-IP: '
.
$_SERVER
[
'HTTP_X_REAL_IP'
];
}
// append the X-Forwarded-For header, if set
if
(!
empty
(
$_SERVER
[
'HTTP_X_FORWARDED_FOR'
]))
{
$remote_ip
[]
=
'X-Forwarded-For: '
.
$_SERVER
[
'HTTP_X_FORWARDED_FOR'
];
}
if
(!
empty
(
$remote_ip
))
{
$address
.=
'('
.
implode
(
','
,
$remote_ip
)
.
')'
;
}
return
$address
;
}
/**
* Read a specific HTTP request header.
*
* @param string $name Header name
*
* @return mixed Header value or null if not available
*/
public
static
function
request_header
(
$name
)
{
if
(
function_exists
(
'getallheaders'
))
{
$hdrs
=
array_change_key_case
(
getallheaders
(),
CASE_UPPER
);
$key
=
strtoupper
(
$name
);
}
else
{
$key
=
'HTTP_'
.
strtoupper
(
strtr
(
$name
,
'-'
,
'_'
));
$hdrs
=
array_change_key_case
(
$_SERVER
,
CASE_UPPER
);
}
return
$hdrs
[
$key
];
}
/**
* Explode quoted string
*
* @param string Delimiter expression string for preg_match()
* @param string Input string
*
* @return array String items
*/
public
static
function
explode_quoted_string
(
$delimiter
,
$string
)
{
$result
=
array
();
$strlen
=
strlen
(
$string
);
for
(
$q
=
$p
=
$i
=
0
;
$i
<
$strlen
;
$i
++)
{
if
(
$string
[
$i
]
==
"
\"
"
&&
$string
[
$i
-
1
]
!=
"
\\
"
)
{
$q
=
$q
?
false
:
true
;
}
else
if
(!
$q
&&
preg_match
(
"/$delimiter/"
,
$string
[
$i
]))
{
$result
[]
=
substr
(
$string
,
$p
,
$i
-
$p
);
$p
=
$i
+
1
;
}
}
$result
[]
=
substr
(
$string
,
$p
);
return
$result
;
}
/**
* Improved equivalent to strtotime()
*
* @param string $date Date string
*
* @return int Unix timestamp
*/
public
static
function
strtotime
(
$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
;
}
// support non-standard "GMTXXXX" literal
$date
=
preg_replace
(
'/GMT
\s
*([+-][0-9]+)/'
,
'
\\
1'
,
$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
))
{
$d
=
explode
(
' '
,
$date
);
array_pop
(
$d
);
if
(!
$d
)
{
break
;
}
$date
=
implode
(
' '
,
$d
);
}
return
$ts
;
}
/*
* Idn_to_ascii wrapper.
* Intl/Idn modules version of this function doesn't work with e-mail address
*/
public
static
function
idn_to_ascii
(
$str
)
{
return
self
::
idn_convert
(
$str
,
true
);
}
/*
* Idn_to_ascii wrapper.
* Intl/Idn modules version of this function doesn't work with e-mail address
*/
public
static
function
idn_to_utf8
(
$str
)
{
return
self
::
idn_convert
(
$str
,
false
);
}
public
static
function
idn_convert
(
$input
,
$is_utf
=
false
)
{
if
(
$at
=
strpos
(
$input
,
'@'
))
{
$user
=
substr
(
$input
,
0
,
$at
);
$domain
=
substr
(
$input
,
$at
+
1
);
}
else
{
$domain
=
$input
;
}
$domain
=
$is_utf
?
idn_to_ascii
(
$domain
)
:
idn_to_utf8
(
$domain
);
if
(
$domain
===
false
)
{
return
''
;
}
return
$at
?
$user
.
'@'
.
$domain
:
$domain
;
}
/**
* Split the given string into word tokens
*
* @param string Input to tokenize
* @return array List of tokens
*/
public
static
function
tokenize_string
(
$str
)
{
return
explode
(
" "
,
preg_replace
(
array
(
'/[
\s
;
\/
+-]+/i'
,
'/(
\d
)[-.
\s
]+(
\d
)/'
,
'/
\s\w
{1,3}
\s
/u'
),
array
(
' '
,
'
\\
1
\\
2'
,
' '
),
$str
));
}
/**
* Normalize the given string for fulltext search.
* Currently only optimized for Latin-1 characters; to be extended
*
* @param string Input string (UTF-8)
* @param boolean True to return list of words as array
* @return mixed Normalized string or a list of normalized tokens
*/
public
static
function
normalize_string
(
$str
,
$as_array
=
false
)
{
// split by words
$arr
=
self
::
tokenize_string
(
$str
);
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'
)));
}
else
$arr
[
$i
]
=
mb_strtolower
(
$part
);
}
return
$as_array
?
$arr
:
join
(
" "
,
$arr
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, Apr 4, 4:21 AM (19 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18822559
Default Alt Text
rcube_utils.php (27 KB)
Attached To
Mode
R113 roundcubemail
Attached
Detach File
Event Timeline