PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.1.4
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.1.4
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / vendor / javanile / php-imap2 / src / Roundcube / Utils.php

Utils.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 10.1.4, at vendor/javanile/php-imap2/src/Roundcube/Utils.php

1,029 lines 31.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 namespace Javanile\Imap2\Roundcube;
5
6 use Javanile\Imap2\DateTime;
7 use Javanile\Imap2\DateTimeZone;
8 use Javanile\Imap2\Exception;
9 use Javanile\Imap2\rcube;
10 use Javanile\Imap2\rcube_charset;
11 use Javanile\Imap2\rcube_string_replacer;
12
13 class Utils
14 {
15 const INPUT_GET = 1;
16 const INPUT_POST = 2;
17 const INPUT_COOKIE = 4;
18 const INPUT_GP = 3; // GET + POST
19 const INPUT_GPC = 7; // GET + POST + COOKIE
20
21
22 public static function setcookie($name, $value, $exp = 0, $http_only = true)
23 {
24 if (headers_sent()) {
25 return;
26 }
27
28 $cookie = session_get_cookie_params();
29 $secure = $cookie['secure'] || self::https_check();
30
31 setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'], $secure, $http_only);
32 }
33
34 public static function check_email($email, $dns_check=true)
35 {
36 if (preg_match('/\p{Cc}/u', $email)) {
37 return false;
38 }
39
40 if (strlen($email) > 254) {
41 return false;
42 }
43
44 $pos = strrpos($email, '@');
45 if (!$pos) {
46 return false;
47 }
48
49 $domain_part = substr($email, $pos + 1);
50 $local_part = substr($email, 0, $pos);
51
52 if (substr($local_part,0,1) == '"') {
53 $local_quoted = preg_replace('/\\\\(\\\\|\")/','', substr($local_part, 1, -1));
54 if (preg_match('/\\\\|"/', $local_quoted)) {
55 return false;
56 }
57 }
58 else if (preg_match('/(^\.|\.\.|\.$)/', $local_part)
59 || preg_match('/[\\ ",:;<>@]/', $local_part)
60 ) {
61 return false;
62 }
63
64 if (preg_match('/^\[((IPv6:[0-9a-f:.]+)|([0-9.]+))\]$/i', $domain_part, $matches)) {
65 return self::check_ip(preg_replace('/^IPv6:/i', '', $matches[1])); // valid IPv4 or IPv6 address
66 }
67 else {
68 $domain_array = explode('.', $domain_part);
69 if (count($domain_array) < 2) {
70 return false;
71 }
72
73 foreach ($domain_array as $part) {
74 if (!preg_match('/^((xn--)?([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) {
75 return false;
76 }
77 }
78
79 $last_part = array_pop($domain_array);
80 if (strpos($last_part, 'xn--') !== 0 && preg_match('/[^a-zA-Z]/', $last_part)) {
81 return false;
82 }
83
84 $rcube = rcube::get_instance();
85
86 if (!$dns_check || !function_exists('checkdnsrr') || !$rcube->config->get('email_dns_check')) {
87 return true;
88 }
89
90 foreach (array('A', 'MX', 'CNAME', 'AAAA') as $type) {
91 if (checkdnsrr($domain_part, $type)) {
92 return true;
93 }
94 }
95 }
96
97 return false;
98 }
99
100 public static function check_ip($ip)
101 {
102 return filter_var($ip, FILTER_VALIDATE_IP) !== false;
103 }
104
105 public static function rep_specialchars_output($str, $enctype = '', $mode = '', $newlines = true)
106 {
107 static $html_encode_arr = false;
108 static $js_rep_table = false;
109 static $xml_rep_table = false;
110
111 if (!is_string($str)) {
112 $str = strval($str);
113 }
114
115 if ($enctype == 'html') {
116 if (!$html_encode_arr) {
117 $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
118 unset($html_encode_arr['?']);
119 }
120
121 $encode_arr = $html_encode_arr;
122
123 if ($mode == 'remove') {
124 $str = strip_tags($str);
125 }
126 else if ($mode != 'strict') {
127 $ltpos = strpos($str, '<');
128 if ($ltpos !== false && strpos($str, '>', $ltpos) !== false) {
129 unset($encode_arr['"']);
130 unset($encode_arr['<']);
131 unset($encode_arr['>']);
132 unset($encode_arr['&']);
133 }
134 }
135
136 $out = strtr($str, $encode_arr);
137
138 return $newlines ? nl2br($out) : $out;
139 }
140
141 if ($js_rep_table === false) {
142 $js_rep_table = $xml_rep_table = array();
143 $xml_rep_table['&'] = '&amp;';
144
145 for ($c=160; $c<256; $c++) {
146 $xml_rep_table[chr($c)] = "&#$c;";
147 }
148
149 $xml_rep_table['"'] = '&quot;';
150 $js_rep_table['"'] = '\\"';
151 $js_rep_table["'"] = "\\'";
152 $js_rep_table["\\"] = "\\\\";
153 $js_rep_table[chr(hexdec('E2')).chr(hexdec('80')).chr(hexdec('A8'))] = '&#8232;';
154 $js_rep_table[chr(hexdec('E2')).chr(hexdec('80')).chr(hexdec('A9'))] = '&#8233;';
155 }
156
157 if ($enctype == 'js') {
158 return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table));
159 }
160
161 if ($enctype == 'text') {
162 return str_replace("\r\n", "\n", $mode == 'remove' ? strip_tags($str) : $str);
163 }
164
165 if ($enctype == 'url') {
166 return rawurlencode($str);
167 }
168
169 if ($enctype == 'xml') {
170 return strtr($str, $xml_rep_table);
171 }
172
173 return $str;
174 }
175
176 public static function get_input_value($fname, $source, $allow_html = false, $charset = null)
177 {
178 $value = null;
179
180 if (($source & self::INPUT_GET) && isset($_GET[$fname])) {
181 $value = $_GET[$fname];
182 }
183
184 if (($source & self::INPUT_POST) && isset($_POST[$fname])) {
185 $value = $_POST[$fname];
186 }
187
188 if (($source & self::INPUT_COOKIE) && isset($_COOKIE[$fname])) {
189 $value = $_COOKIE[$fname];
190 }
191
192 return self::parse_input_value($value, $allow_html, $charset);
193 }
194
195 public static function parse_input_value($value, $allow_html = false, $charset = null)
196 {
197 global $OUTPUT;
198
199 if (empty($value)) {
200 return $value;
201 }
202
203 if (is_array($value)) {
204 foreach ($value as $idx => $val) {
205 $value[$idx] = self::parse_input_value($val, $allow_html, $charset);
206 }
207 return $value;
208 }
209
210 if (!$allow_html) {
211 $value = strip_tags($value);
212 }
213
214 $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null;
215
216 if ($output_charset == 'UTF-8') {
217 $value = rcube_charset::clean($value);
218 }
219
220 if ($charset && $output_charset) {
221 $value = rcube_charset::convert($value, $output_charset, $charset);
222 }
223
224 return $value;
225 }
226
227 public static function request2param($mode = null, $ignore = 'task|action', $allow_html = false)
228 {
229 $out = array();
230 $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST);
231
232 foreach (array_keys($src) as $key) {
233 $fname = $key[0] == '_' ? substr($key, 1) : $key;
234 if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) {
235 $out[$fname] = self::get_input_value($key, $mode, $allow_html);
236 }
237 }
238
239 return $out;
240 }
241
242 public static function html_identifier($str, $encode = false)
243 {
244 if ($encode) {
245 return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
246 }
247
248 return asciiwords($str, true, '_');
249 }
250
251 public static function mod_css_styles($source, $container_id, $allow_remote = false, $prefix = '')
252 {
253 $last_pos = 0;
254 $replacements = new rcube_string_replacer;
255
256 $source = self::xss_entity_decode($source);
257 $stripped = preg_replace('/[^a-z\(:;]/i', '', $source);
258 $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\((?!data:image)' : '');
259
260 if (preg_match("/$evilexpr/i", $stripped)) {
261 return '/* evil! */';
262 }
263
264 $strict_url_regexp = '!url\s*\(\s*["\']?(https?:)//[a-z0-9/._+-]+["\']?\s*\)!Uims';
265
266 while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) {
267 $nested = strpos($source, '{', $pos+1);
268 if ($nested && $nested < $pos2) // when dealing with nested blocks (e.g. @media), take the inner one
269 $pos = $nested;
270 $length = $pos2 - $pos - 1;
271 $styles = substr($source, $pos+1, $length);
272
273 $styles = preg_replace('/position[^a-z]*:[\s\r\n]*fixed/i', 'position: absolute', $styles);
274
275 if ($allow_remote) {
276 $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY);
277
278 for ($i=0, $len=count($a_styles); $i < $len; $i++) {
279 $line = $a_styles[$i];
280 $stripped = preg_replace('/[^a-z\(:;]/i', '', $line);
281
282 if (stripos($stripped, 'url(data:image')) {
283 $a_styles[$i] .= ';' . $a_styles[$i+1];
284 unset($a_styles[$i+1]);
285 }
286 else if (stripos($stripped, 'url(') && !preg_match($strict_url_regexp, $line)) {
287 $a_styles = array('/* evil! */');
288 break;
289 }
290 }
291
292 $styles = implode(";\n", $a_styles);
293 }
294
295 $key = $replacements->add($styles);
296 $repl = $replacements->get_replacement($key);
297 $source = substr_replace($source, $repl, $pos+1, $length);
298 $last_pos = $pos2 - ($length - strlen($repl));
299 }
300
301 $source = preg_replace('/(^\s*<\!--)|(-->\s*$)/m', '', $source);
302
303 if ($container_id || $prefix) {
304 $regexp = '/(^\s*|,\s*|\}\s*|\{\s*)((?!##str):?[a-z0-9\._#\*\[][a-z0-9\._:\(\)#=~ \[\]"\|\>\+\$\^-]*)/im';
305 $callback = function($matches) use ($container_id, $prefix) {
306 $replace = $matches[2];
307
308 if (stripos($replace, ':root') === 0) {
309 $replace = substr($replace, 5);
310 }
311
312 if ($prefix) {
313 $replace = str_replace(array('.', '#'), array(".$prefix", "#$prefix"), $replace);
314 }
315
316 if ($container_id) {
317 $replace = "#$container_id " . $replace;
318 }
319
320 $replace = preg_replace('/\s+/', ' ', $replace);
321
322 return str_replace($matches[2], $replace, $matches[0]);
323 };
324
325 $source = preg_replace_callback($regexp, $callback, $source);
326 }
327
328 if ($container_id) {
329 $regexp = '/#' . preg_quote($container_id, '/') . '\s+body/i';
330 $source = preg_replace($regexp, "#$container_id", $source);
331 }
332
333 $source = $replacements->resolve($source);
334
335 return $source;
336 }
337
338 public static function file2class($mimetype, $filename)
339 {
340 $mimetype = strtolower($mimetype);
341 $filename = strtolower($filename);
342
343 list($primary, $secondary) = explode('/', $mimetype);
344
345 $classes = array($primary ?: 'unknown');
346
347 if ($secondary) {
348 $classes[] = $secondary;
349 }
350
351 if (preg_match('/\.([a-z0-9]+)$/', $filename, $m)) {
352 if (!in_array($m[1], $classes)) {
353 $classes[] = $m[1];
354 }
355 }
356
357 return implode(' ', $classes);
358 }
359
360 public static function xss_entity_decode($content)
361 {
362 $callback = function($matches) { return chr(hexdec($matches[1])); };
363
364 $out = html_entity_decode(html_entity_decode($content));
365 $out = trim(preg_replace('/(^<!--|-->$)/', '', trim($out)));
366 $out = preg_replace_callback('/\\\([0-9a-f]{2,6})\s*/i', $callback, $out);
367 $out = preg_replace('/\\\([^0-9a-f])/i', '\\1', $out);
368 $out = preg_replace('#/\*.*\*/#Ums', '', $out);
369 $out = strip_tags($out);
370
371 return $out;
372 }
373
374 public static function mem_check($need)
375 {
376 $mem_limit = parse_bytes(ini_get('memory_limit'));
377 $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB
378
379 return $mem_limit > 0 && $memory + $need > $mem_limit ? false : true;
380 }
381
382 public static function https_check($port = null, $use_https = true)
383 {
384 if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
385 return true;
386 }
387
388 if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])
389 && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
390 && in_array($_SERVER['REMOTE_ADDR'], rcube::get_instance()->config->get('proxy_whitelist', array()))
391 ) {
392 return true;
393 }
394
395 if ($port && $_SERVER['SERVER_PORT'] == $port) {
396 return true;
397 }
398
399 if ($use_https && rcube::get_instance()->config->get('use_https')) {
400 return true;
401 }
402
403 return false;
404 }
405
406 public static function parse_host($name, $host = '')
407 {
408 if (!is_string($name)) {
409 return $name;
410 }
411
412 $n = self::server_name();
413 $t = preg_replace('/^[^.]+\.(?![^.]+$)/', '', $n);
414 $d = preg_replace('/^[^.]+\.(?![^.]+$)/', '', self::server_name('HTTP_HOST'));
415 $h = $_SESSION['storage_host'] ?: $host;
416 $z = preg_replace('/^[^.]+\.(?![^.]+$)/', '', $h);
417 if (strpos($name, '%s') !== false) {
418 $user_email = self::idn_to_ascii(self::get_input_value('_user', self::INPUT_POST));
419 $matches = preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s);
420 if ($matches < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false) {
421 return false;
422 }
423 }
424
425 return str_replace(array('%n', '%t', '%d', '%h', '%z', '%s'), array($n, $t, $d, $h, $z, $s[2]), $name);
426 }
427
428 public static function server_name($type = null, $strip_port = true)
429 {
430 $name = $_SERVER[$type ?: 'SERVER_NAME'];
431 $rcube = rcube::get_instance();
432 $patterns = (array) $rcube->config->get('trusted_host_patterns');
433
434 if ($strip_port) {
435 $name = preg_replace('/:\d+$/', '', $name);
436 }
437
438 if (empty($patterns) || in_array_nocase($name, $patterns)) {
439 return $name;
440 }
441
442 if (!empty($name)) {
443 foreach ($patterns as $pattern) {
444 if (preg_match("/$pattern/", $name)) {
445 return $name;
446 }
447 }
448
449 $rcube->raise_error(array('file' => __FILE__, 'line' => __LINE__,
450 'message' => "Specified host is not trusted. Using 'localhost'."), true, false);
451 }
452
453 return 'localhost';
454 }
455
456 public static function remote_ip()
457 {
458 $address = $_SERVER['REMOTE_ADDR'];
459
460 if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
461 $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP'];
462 }
463
464 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
465 $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
466 }
467
468 if (!empty($remote_ip)) {
469 $address .= '(' . implode(',', $remote_ip) . ')';
470 }
471
472 return $address;
473 }
474
475 public static function remote_addr()
476 {
477 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_X_REAL_IP'])) {
478 $proxy_whitelist = rcube::get_instance()->config->get('proxy_whitelist', array());
479 if (in_array($_SERVER['REMOTE_ADDR'], $proxy_whitelist)) {
480 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
481 foreach (array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $forwarded_ip) {
482 $forwarded_ip = trim($forwarded_ip);
483 if (!in_array($forwarded_ip, $proxy_whitelist)) {
484 return $forwarded_ip;
485 }
486 }
487 }
488
489 if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
490 return $_SERVER['HTTP_X_REAL_IP'];
491 }
492 }
493 }
494
495 if (!empty($_SERVER['REMOTE_ADDR'])) {
496 return $_SERVER['REMOTE_ADDR'];
497 }
498
499 return '';
500 }
501
502 public static function request_header($name)
503 {
504 if (function_exists('apache_request_headers')) {
505 $headers = apache_request_headers();
506 $key = strtoupper($name);
507 }
508 else {
509 $headers = $_SERVER;
510 $key = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
511 }
512
513 if (!empty($headers)) {
514 $headers = array_change_key_case($headers, CASE_UPPER);
515
516 return $headers[$key];
517 }
518 }
519
520 public static function explode_quoted_string($delimiter, $string)
521 {
522 $result = array();
523 $strlen = strlen($string);
524
525 for ($q=$p=$i=0; $i < $strlen; $i++) {
526 if ($string[$i] == "\"" && $string[$i-1] != "\\") {
527 $q = $q ? false : true;
528 }
529 else if (!$q && preg_match("/$delimiter/", $string[$i])) {
530 $result[] = substr($string, $p, $i - $p);
531 $p = $i + 1;
532 }
533 }
534
535 $result[] = (string) substr($string, $p);
536
537 return $result;
538 }
539
540 public static function strtotime($date, $timezone = null)
541 {
542 $date = self::clean_datestr($date);
543 $tzname = $timezone ? ' ' . $timezone->getName() : '';
544
545 if (is_numeric($date)) {
546 return (int) $date;
547 }
548
549 if (strlen($date) > 128) {
550 $date = substr($date, 0, 128);
551 }
552
553 while (($ts = @strtotime($date . $tzname)) === false || $ts < 0) {
554 if (($pos = strrpos($date, ' ')) === false) {
555 break;
556 }
557
558 $date = rtrim(substr($date, 0, $pos));
559 }
560
561 return (int) $ts;
562 }
563
564 public static function anytodatetime($date, $timezone = null)
565 {
566 if ($date instanceof DateTime) {
567 return $date;
568 }
569
570 $dt = false;
571 $date = self::clean_datestr($date);
572
573 if (!empty($date)) {
574 try {
575 $_date = preg_match('/^[0-9]+$/', $date) ? "@$date" : $date;
576 $dt = $timezone ? new DateTime($_date, $timezone) : new DateTime($_date);
577 }
578 catch (Exception $e) {
579 }
580 }
581
582 if (!$dt && ($timestamp = self::strtotime($date, $timezone))) {
583 try {
584 $dt = new DateTime("@".$timestamp);
585 if ($timezone) {
586 $dt->setTimezone($timezone);
587 }
588 }
589 catch (Exception $e) {
590 }
591 }
592
593 return $dt;
594 }
595
596 public static function clean_datestr($date)
597 {
598 $date = trim($date);
599
600 if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) {
601 return sprintf('%04d-%02d-%02d 00:00:00', intval($m[1]), intval($m[2]), intval($m[3]));
602 }
603
604 $date = preg_replace(
605 array(
606 '/\(.*\)/', // remove RFC comments
607 '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal
608 '/[^a-z0-9\x20\x09:\/\.+-]/i', // remove any invalid characters
609 '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names
610 ),
611 array(
612 '',
613 '\\1',
614 '',
615 '',
616 ), $date);
617
618 $date = trim($date);
619
620 if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})(\s.*)?$/', $date, $m)) {
621 $mdy = $m[2] > 12 && $m[1] <= 12;
622 $day = $mdy ? $m[2] : $m[1];
623 $month = $mdy ? $m[1] : $m[2];
624 $date = sprintf('%04d-%02d-%02d%s', $m[3], $month, $day, $m[4] ?: ' 00:00:00');
625 }
626 else if (preg_match('/^(\d{4})\.(\d{1,2})\.(\d{1,2})(\s.*)?$/', $date, $m)) {
627 $date = sprintf('%04d-%02d-%02d%s', $m[1], $m[2], $m[3], $m[4] ?: ' 00:00:00');
628 }
629
630 return $date;
631 }
632
633 public static function format_datestr($date, $format)
634 {
635 $format_items = preg_split('/[.-\/\\\\]/', $format);
636 $date_items = preg_split('/[.-\/\\\\]/', $date);
637 $iso_format = '%04d-%02d-%02d';
638
639 if (count($format_items) == 3 && count($date_items) == 3) {
640 if ($format_items[0] == 'Y') {
641 $date = sprintf($iso_format, $date_items[0], $date_items[1], $date_items[2]);
642 }
643 else if (strpos('dj', $format_items[0]) !== false) {
644 $date = sprintf($iso_format, $date_items[2], $date_items[1], $date_items[0]);
645 }
646 else if (strpos('mn', $format_items[0]) !== false) {
647 $date = sprintf($iso_format, $date_items[2], $date_items[0], $date_items[1]);
648 }
649 }
650
651 return $date;
652 }
653
654 public static function idn_to_ascii($str)
655 {
656 return self::idn_convert($str, true);
657 }
658
659 public static function idn_to_utf8($str)
660 {
661 return self::idn_convert($str, false);
662 }
663
664 public static function idn_convert($input, $is_utf = false)
665 {
666 if ($at = strpos($input, '@')) {
667 $user = substr($input, 0, $at);
668 $domain = substr($input, $at + 1);
669 }
670 else {
671 $user = '';
672 $domain = $input;
673 }
674
675 $variant = defined('INTL_IDNA_VARIANT_UTS46') ? INTL_IDNA_VARIANT_UTS46 : null;
676 $options = 0;
677
678
679 if ($is_utf) {
680 if (preg_match('/[^\x20-\x7E]/', $domain)) {
681 $options = defined('IDNA_NONTRANSITIONAL_TO_ASCII') ? IDNA_NONTRANSITIONAL_TO_ASCII : 0;
682 $domain = idn_to_ascii($domain, $options, $variant);
683 }
684 }
685 else if (preg_match('/(^|\.)xn--/i', $domain)) {
686 $options = defined('IDNA_NONTRANSITIONAL_TO_UNICODE') ? IDNA_NONTRANSITIONAL_TO_UNICODE : 0;
687 $domain = idn_to_utf8($domain, $options, $variant);
688 }
689
690 if ($domain === false) {
691 return '';
692 }
693
694 return $at ? $user . '@' . $domain : $domain;
695 }
696
697 public static function tokenize_string($str, $minlen = 2)
698 {
699 $expr = array('/[\s;,"\'\/+-]+/ui', '/(\d)[-.\s]+(\d)/u');
700 $repl = array(' ', '\\1\\2');
701
702 if ($minlen > 1) {
703 $minlen--;
704 $expr[] = "/(^|\s+)\w{1,$minlen}(\s+|$)/u";
705 $repl[] = ' ';
706 }
707
708 return array_filter(explode(" ", preg_replace($expr, $repl, $str)));
709 }
710
711 public static function normalize_string($str, $as_array = false, $minlen = 2)
712 {
713 $str = preg_replace('/('
714 . '\xF0[\x90-\xBF][\x80-\xBF]{2}'
715 . '|[\xF1-\xF3][\x80-\xBF]{3}'
716 . '|\xF4[\x80-\x8F][\x80-\xBF]{2}'
717 . ')/', '?', $str);
718
719 $arr = self::tokenize_string($str, $minlen);
720
721 if (utf8_encode(utf8_decode($str)) == $str) {
722 preg_match_all('/./u', 'äâàåáãæçéêëèïîìíñöôòøõóüûùúýÿ', $keys);
723 preg_match_all('/./', 'aaaaaaaceeeeiiiinoooooouuuuyy', $values);
724
725 $mapping = array_combine($keys[0], $values[0]);
726 $mapping = array_merge($mapping, array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u'));
727 }
728 else if (rcube_charset::convert(rcube_charset::convert($str, 'UTF-8', 'ISO-8859-2'), 'ISO-8859-2', 'UTF-8') == $str) {
729 preg_match_all('/./u', '�
730 áâäćçčéęëěíîłľĺńňóôöŕřśšşťţůúűüźžżý', $keys);
731 preg_match_all('/./', 'aaaaccceeeeiilllnnooorrsssttuuuuzzzy', $values);
732
733 $mapping = array_combine($keys[0], $values[0]);
734 $mapping = array_merge($mapping, array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u'));
735 }
736
737 foreach ($arr as $i => $part) {
738 $part = mb_strtolower($part);
739
740 if (!empty($mapping)) {
741 $part = strtr($part, $mapping);
742 }
743
744 $arr[$i] = $part;
745 }
746
747 return $as_array ? $arr : implode(' ', $arr);
748 }
749
750 public static function words_match($haystack, $needle)
751 {
752 $a_needle = self::tokenize_string($needle, 1);
753 $_haystack = implode(' ', self::tokenize_string($haystack, 1));
754 $valid = strlen($_haystack) > 0;
755 $hits = 0;
756
757 foreach ($a_needle as $w) {
758 if ($valid) {
759 if (stripos($_haystack, $w) !== false) {
760 $hits++;
761 }
762 }
763 else if (stripos($haystack, $w) !== false) {
764 $hits++;
765 }
766 }
767
768 return $hits >= count($a_needle);
769 }
770
771 public static function get_opt($aliases = array())
772 {
773 $args = array();
774 $bool = array();
775
776 foreach ($aliases as $key => $alias) {
777 if ($pos = strpos($alias, ':')) {
778 $aliases[$key] = substr($alias, 0, $pos);
779 $bool[] = $key;
780 $bool[] = $aliases[$key];
781 }
782 }
783
784 for ($i=1; $i < count($_SERVER['argv']); $i++) {
785 $arg = $_SERVER['argv'][$i];
786 $value = true;
787 $key = null;
788
789 if ($arg[0] == '-') {
790 $key = preg_replace('/^-+/', '', $arg);
791 $sp = strpos($arg, '=');
792
793 if ($sp > 0) {
794 $key = substr($key, 0, $sp - 2);
795 $value = substr($arg, $sp+1);
796 }
797 else if (in_array($key, $bool)) {
798 $value = true;
799 }
800 else if (strlen($_SERVER['argv'][$i+1]) && $_SERVER['argv'][$i+1][0] != '-') {
801 $value = $_SERVER['argv'][++$i];
802 }
803
804 $args[$key] = is_string($value) ? preg_replace(array('/^["\']/', '/["\']$/'), '', $value) : $value;
805 }
806 else {
807 $args[] = $arg;
808 }
809
810 if ($alias = $aliases[$key]) {
811 $args[$alias] = $args[$key];
812 }
813 }
814
815 return $args;
816 }
817
818 public static function prompt_silent($prompt = "Password:")
819 {
820 if (preg_match('/^win/i', PHP_OS)) {
821 $vbscript = sys_get_temp_dir() . 'prompt_password.vbs';
822 $vbcontent = 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "password here"))';
823 #file_put_contents($vbscript, $vbcontent);
824
825 $command = "cscript //nologo " . escapeshellarg($vbscript);
826 $password = rtrim(shell_exec($command));
827 unlink($vbscript);
828
829 return $password;
830 }
831
832 $command = "/usr/bin/env bash -c 'echo OK'";
833
834 if (rtrim(shell_exec($command)) !== 'OK') {
835 echo $prompt;
836 $pass = trim(fgets(STDIN));
837 echo chr(8)."\r" . $prompt . str_repeat("*", strlen($pass))."\n";
838
839 return $pass;
840 }
841
842 $command = "/usr/bin/env bash -c 'read -s -p \"" . addslashes($prompt) . "\" mypassword && echo \$mypassword'";
843 $password = rtrim(shell_exec($command));
844 echo "\n";
845
846 return $password;
847 }
848
849 public static function get_boolean($str)
850 {
851 $str = strtolower($str);
852
853 return !in_array($str, array('false', '0', 'no', 'off', 'nein', ''), true);
854 }
855
856 public static function is_absolute_path($path)
857 {
858 if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
859 return (bool) preg_match('!^[a-z]:[\\\\/]!i', $path);
860 }
861
862 return $path[0] == '/';
863 }
864
865 public static function resolve_url($url)
866 {
867 if (!preg_match('|^https?://|', $url)) {
868 $schema = 'http';
869 $default_port = 80;
870
871 if (self::https_check()) {
872 $schema = 'https';
873 $default_port = 443;
874 }
875
876 $prefix = $schema . '://' . preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST']);
877 if ($_SERVER['SERVER_PORT'] != $default_port && $_SERVER['SERVER_PORT'] != 80) {
878 $prefix .= ':' . $_SERVER['SERVER_PORT'];
879 }
880
881 $url = $prefix . ($url[0] == '/' ? '' : '/') . $url;
882 }
883
884 return $url;
885 }
886
887 public static function random_bytes($length, $raw = false)
888 {
889 $hextab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
890 $tabsize = strlen($hextab);
891
892 if ($raw && function_exists('random_bytes')) {
893 return random_bytes($length);
894 }
895
896 if (!$raw && function_exists('random_int')) {
897 $result = '';
898 while ($length-- > 0) {
899 $result .= $hextab[random_int(0, $tabsize - 1)];
900 }
901
902 return $result;
903 }
904
905 $random = openssl_random_pseudo_bytes($length);
906
907 if ($random === false && $length > 0) {
908 throw new Exception("Failed to get random bytes");
909 }
910
911 if (!$raw) {
912 for ($x = 0; $x < $length; $x++) {
913 $random[$x] = $hextab[ord($random[$x]) % $tabsize];
914 }
915 }
916
917 return $random;
918 }
919
920 public static function bin2ascii($input)
921 {
922 $hextab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
923 $result = '';
924
925 for ($x = 0; $x < strlen($input); $x++) {
926 $result .= $hextab[ord($input[$x]) % 62];
927 }
928
929 return $result;
930 }
931
932 public static function date_format($format = null)
933 {
934 if (empty($format)) {
935 $format = 'd-M-Y H:i:s O';
936 }
937
938 if (strpos($format, 'u') !== false) {
939 $dt = number_format(microtime(true), 6, '.', '');
940 $dt .= '.' . date_default_timezone_get();
941
942 if ($date = date_create_from_format('U.u.e', $dt)) {
943 return $date->format($format);
944 }
945 }
946
947 return date($format);
948 }
949
950 public static function parse_socket_options(&$options, $host = null)
951 {
952 if (empty($host) || empty($options)) {
953 return;
954 }
955
956 $host_url = parse_url($host);
957 if (isset($host_url['host'])) {
958 $host = $host_url['host'];
959 }
960
961 if ($host && array_key_exists($host, $options)) {
962 $options = $options[$host];
963 }
964 }
965
966 public static function max_upload_size()
967 {
968 $max_filesize = parse_bytes(ini_get('upload_max_filesize'));
969 $max_postsize = parse_bytes(ini_get('post_max_size'));
970
971 if ($max_postsize && $max_postsize < $max_filesize) {
972 $max_filesize = $max_postsize;
973 }
974
975 return $max_filesize;
976 }
977
978 public static function preg_error($error = array(), $terminate = false)
979 {
980 if (($preg_error = preg_last_error()) != PREG_NO_ERROR) {
981 $errstr = "PCRE Error: $preg_error.";
982
983 if ($preg_error == PREG_BACKTRACK_LIMIT_ERROR) {
984 $errstr .= " Consider raising pcre.backtrack_limit!";
985 }
986 if ($preg_error == PREG_RECURSION_LIMIT_ERROR) {
987 $errstr .= " Consider raising pcre.recursion_limit!";
988 }
989
990 $error = array_merge(array('code' => 620, 'line' => __LINE__, 'file' => __FILE__), $error);
991
992 if (!empty($error['message'])) {
993 $error['message'] .= ' ' . $errstr;
994 }
995 else {
996 $error['message'] = $errstr;
997 }
998
999 rcube::raise_error($error, true, $terminate);
1000
1001 return true;
1002 }
1003
1004 return false;
1005 }
1006
1007 public static function temp_filename($file_name, $unique = true, $create = true)
1008 {
1009 $temp_dir = rcube::get_instance()->config->get('temp_dir');
1010
1011 if (!is_writable($temp_dir)) {
1012 $temp_dir = sys_get_temp_dir();
1013 }
1014
1015 $temp_file = $unique ? str_replace('.', '', uniqid($file_name, true)) : $file_name;
1016 $temp_path = unslashify($temp_dir) . '/' . RCUBE_TEMP_FILE_PREFIX . $temp_file;
1017
1018 if ($unique && file_exists($temp_path)) {
1019 return self::temp_filename($file_name, $unique, $create);
1020 }
1021
1022 if ($create) {
1023 touch($temp_path);
1024 }
1025
1026 return $temp_path;
1027 }
1028 }
1029