]> git.donarmstrong.com Git - roundcube.git/blob - program/include/rcube_shared.inc
Imported Upstream version 0.1~rc2
[roundcube.git] / program / include / rcube_shared.inc
1 <?php
2
3 /*
4  +-----------------------------------------------------------------------+
5  | rcube_shared.inc                                                      |
6  |                                                                       |
7  | This file is part of the RoundCube PHP suite                          |
8  | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
9  | Licensed under the GNU GPL                                            |
10  |                                                                       |
11  | CONTENTS:                                                             |
12  |   Shared functions and classes used in PHP projects                   |
13  |                                                                       |
14  +-----------------------------------------------------------------------+
15  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16  +-----------------------------------------------------------------------+
17
18  $Id: rcube_shared.inc 839 2007-09-29 18:15:05Z thomasb $
19
20 */
21
22
23 /**
24  * RoundCube shared functions
25  * 
26  * @package Core
27  */
28
29
30 /**
31  * Provide details about the client's browser
32  *
33  * @return array Key-value pairs of browser properties
34  */
35 function rcube_browser()
36 {
37   $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
38
39   $bw['ver'] = 0;
40   $bw['win'] = stristr($HTTP_USER_AGENT, 'win');
41   $bw['mac'] = stristr($HTTP_USER_AGENT, 'mac');
42   $bw['linux'] = stristr($HTTP_USER_AGENT, 'linux');
43   $bw['unix']  = stristr($HTTP_USER_AGENT, 'unix');
44
45   $bw['ns4'] = stristr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie');
46   $bw['ns']  = ($bw['ns4'] || stristr($HTTP_USER_AGENT, 'netscape'));
47   $bw['ie']  = stristr($HTTP_USER_AGENT, 'msie');
48   $bw['mz']  = stristr($HTTP_USER_AGENT, 'mozilla/5');
49   $bw['opera'] = stristr($HTTP_USER_AGENT, 'opera');
50   $bw['safari'] = stristr($HTTP_USER_AGENT, 'safari');
51
52   if($bw['ns'])
53   {
54     $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs);
55     $bw['ver'] = $test ? (float)$regs[1] : 0;
56   }
57   if($bw['mz'])
58   {
59     $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs);
60     $bw['ver'] = $test ? (float)$regs[1] : 0;
61   }
62   if($bw['ie'])
63   {
64     $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
65     $bw['ver'] = $test ? (float)$regs[1] : 0;
66   }
67   if($bw['opera'])
68   {
69     $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
70     $bw['ver'] = $test ? (float)$regs[1] : 0;
71   }
72
73   if(eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs))
74     $bw['lang'] =  $regs[1];
75   else
76     $bw['lang'] =  'en';
77
78   $bw['dom'] = ($bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5) || ($bw['opera'] && $bw['ver']>=7));
79   $bw['pngalpha'] = $bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5.5) ||
80                     ($bw['ie'] && $bw['ver']>=5 && $bw['mac']) || ($bw['opera'] && $bw['ver']>=7) ? TRUE : FALSE;
81
82   return $bw;
83 }
84
85
86 /**
87  * Get localized text in the desired language
88  *
89  * @param mixed Named parameters array or label name
90  * @return string Localized text
91  */
92 function rcube_label($attrib)
93 {
94   global $sess_user_lang, $INSTALL_PATH, $OUTPUT;
95   static $sa_text_data, $s_language, $utf8_decode;
96
97   // extract attributes
98   if (is_string($attrib))
99     $attrib = array('name' => $attrib);
100     
101   $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1;
102   $vars = isset($attrib['vars']) ? $attrib['vars'] : '';
103
104   $command_name = !empty($attrib['command']) ? $attrib['command'] : NULL;
105   $alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : '');
106
107
108   // load localized texts
109   if (!$sa_text_data || $s_language != $sess_user_lang)
110     {
111     $sa_text_data = array();
112     
113     // get english labels (these should be complete)
114     @include($INSTALL_PATH.'program/localization/en_US/labels.inc');
115     @include($INSTALL_PATH.'program/localization/en_US/messages.inc');
116
117     if (is_array($labels))
118       $sa_text_data = $labels;
119     if (is_array($messages))
120       $sa_text_data = array_merge($sa_text_data, $messages);
121     
122     // include user language files
123     if ($sess_user_lang!='en' && is_dir($INSTALL_PATH.'program/localization/'.$sess_user_lang))
124     {
125       include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/labels.inc');
126       include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/messages.inc');
127
128       if (is_array($labels))
129         $sa_text_data = array_merge($sa_text_data, $labels);
130       if (is_array($messages))
131         $sa_text_data = array_merge($sa_text_data, $messages);
132     }
133       
134     $s_language = $sess_user_lang;
135   }
136
137   // text does not exist
138   if (!($text_item = $sa_text_data[$alias]))
139   {
140     /*
141     raise_error(array(
142       'code' => 500,
143       'type' => 'php',
144       'line' => __LINE__,
145       'file' => __FILE__,
146       'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE);
147     */
148     return "[$alias]";
149   }
150
151   // make text item array 
152   $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item);
153
154   // decide which text to use
155   if ($nr==1)
156     $text = $a_text_item['single'];
157   else if ($nr>0)
158     $text = $a_text_item['multiple'];
159   else if ($nr==0)
160   {
161     if ($a_text_item['none'])
162       $text = $a_text_item['none'];
163     else if ($a_text_item['single'])
164       $text = $a_text_item['single'];
165     else if ($a_text_item['multiple'])
166       $text = $a_text_item['multiple'];
167   }
168
169   // default text is single
170   if ($text=='')
171     $text = $a_text_item['single'];
172
173   // replace vars in text
174   if (is_array($attrib['vars']))
175   {
176     foreach ($attrib['vars'] as $var_key=>$var_value)
177       $a_replace_vars[substr($var_key, 0, 1)=='$' ? substr($var_key, 1) : $var_key] = $var_value;
178   }
179
180   if ($a_replace_vars)
181     $text = preg_replace('/\${?([_a-z]{1}[_a-z0-9]*)}?/ei', '$a_replace_vars["\1"]', $text);
182
183   // remove variables in text which were not available in arg $vars and $nr
184   eval("\$text = <<<EOF
185 $text
186 EOF;
187 ");
188
189   // format output
190   if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])
191     return ucfirst($text);
192   else if ($attrib['uppercase'])
193     return strtoupper($text);
194   else if ($attrib['lowercase'])
195     return strtolower($text);
196
197   return $text;
198 }
199
200
201 /**
202  * Send HTTP headers to prevent caching this page
203  */
204 function send_nocacheing_headers()
205 {
206   if (headers_sent())
207     return;
208
209   header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
210   header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
211   header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
212   header("Pragma: no-cache");
213 }
214
215
216 /**
217  * Send header with expire date 30 days in future
218  *
219  * @param int Expiration time in seconds
220  */
221 function send_future_expire_header($offset=2600000)
222 {
223   if (headers_sent())
224     return;
225
226   header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+$offset)." GMT");
227   header("Cache-Control: max-age=$offset");
228   header("Pragma: ");
229 }
230
231
232 /**
233  * Check request for If-Modified-Since and send an according response.
234  * This will terminate the current script if headers match the given values
235  *
236  * @param int Modified date as unix timestamp
237  * @param string Etag value for caching
238  */
239 function send_modified_header($mdate, $etag=null)
240 {
241   if (headers_sent())
242     return;
243     
244   $iscached = false;
245   if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $mdate)
246     $iscached = true;
247   
248   $etag = $etag ? "\"$etag\"" : null;
249   if ($etag && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag)
250     $iscached = true;
251   
252   if ($iscached)
253     header("HTTP/1.x 304 Not Modified");
254   else
255     header("Last-Modified: ".gmdate("D, d M Y H:i:s", $mdate)." GMT");
256   
257   header("Cache-Control: max-age=0");
258   header("Expires: ");
259   header("Pragma: ");
260   
261   if ($etag)
262     header("Etag: $etag");
263   
264   if ($iscached)
265     exit;
266 }
267
268
269 /**
270  * Convert a variable into a javascript object notation
271  *
272  * @param mixed Input value
273  * @return string Serialized JSON string
274  */
275 function json_serialize($var)
276 {
277   if (is_object($var))
278     $var = get_object_vars($var);
279
280   if (is_array($var))
281   {
282     // empty array
283     if (!sizeof($var))
284       return '[]';
285     else
286     {
287       $keys_arr = array_keys($var);
288       $is_assoc = $have_numeric = 0;
289
290       for ($i=0; $i<sizeof($keys_arr); ++$i)
291       {
292         if (is_numeric($keys_arr[$i]))
293           $have_numeric = 1;
294         if (!is_numeric($keys_arr[$i]) || $keys_arr[$i] != $i)
295           $is_assoc = 1;
296         if ($is_assoc && $have_numeric)
297           break;
298       }
299       
300       $brackets = $is_assoc ? '{}' : '[]';
301       $pairs = array();
302
303       foreach ($var as $key => $value)
304       {
305         // enclose key with quotes if it is not variable-name conform
306         if (!ereg("^[_a-zA-Z]{1}[_a-zA-Z0-9]*$", $key) /* || is_js_reserved_word($key) */)
307           $key = "'$key'";
308
309         $pairs[] = sprintf("%s%s", $is_assoc ? "$key:" : '', json_serialize($value));
310       }
311
312       return $brackets{0} . implode(',', $pairs) . $brackets{1};
313     }
314   }
315   else if (is_numeric($var) && strval(intval($var)) === strval($var))
316     return $var;
317   else if (is_bool($var))
318     return $var ? '1' : '0';
319   else
320     return "'".JQ($var)."'";
321
322 }
323
324 /**
325  * Function to convert an array to a javascript array
326  * Actually an alias function for json_serialize()
327  * @deprecated
328  */
329 function array2js($arr, $type='')
330 {
331   return json_serialize($arr);
332 }
333
334
335 /**
336  * Similar function as in_array() but case-insensitive
337  *
338  * @param mixed Needle value
339  * @param array Array to search in
340  * @return boolean True if found, False if not
341  */
342 function in_array_nocase($needle, $haystack)
343 {
344   foreach ($haystack as $value)
345     if (strtolower($needle)===strtolower($value))
346       return true;
347   
348   return false;
349 }
350
351
352 /**
353  * Find out if the string content means TRUE or FALSE
354  *
355  * @param string Input value
356  * @return boolean Imagine what!
357  */
358 function get_boolean($str)
359 {
360   $str = strtolower($str);
361   if(in_array($str, array('false', '0', 'no', 'nein', ''), TRUE))
362     return FALSE;
363   else
364     return TRUE;
365 }
366
367
368 /**
369  * Parse a human readable string for a number of bytes
370  *
371  * @param string Input string
372  * @return int Number of bytes
373  */
374 function parse_bytes($str)
375 {
376   if (is_numeric($str))
377     return intval($str);
378     
379   if (preg_match('/([0-9]+)([a-z])/i', $str, $regs))
380   {
381     $bytes = floatval($regs[1]);
382     switch (strtolower($regs[2]))
383     {
384       case 'g':
385         $bytes *= 1073741824;
386         break;
387       case 'm':
388         $bytes *= 1048576;
389         break;
390       case 'k':
391         $bytes *= 1024;
392         break;
393     }
394   }
395
396   return intval($bytes);
397 }
398     
399 /**
400  * Create a human readable string for a number of bytes
401  *
402  * @param int Number of bytes
403  * @return string Byte string
404  */
405 function show_bytes($bytes)
406 {
407   if ($bytes > 1073741824)
408   {
409     $gb = $bytes/1073741824;
410     $str = sprintf($gb>=10 ? "%d GB" : "%.1f GB", $gb);
411   }
412   else if ($bytes > 1048576)
413   {
414     $mb = $bytes/1048576;
415     $str = sprintf($mb>=10 ? "%d MB" : "%.1f MB", $mb);
416   }
417   else if ($bytes > 1024)
418     $str = sprintf("%d KB",  round($bytes/1024));
419   else
420     $str = sprintf('%d B', $bytes);
421
422   return $str;
423 }
424
425
426 /**
427  * Convert paths like ../xxx to an absolute path using a base url
428  *
429  * @param string Relative path
430  * @param string Base URL
431  * @return string Absolute URL
432  */
433 function make_absolute_url($path, $base_url)
434 {
435   $host_url = $base_url;
436   $abs_path = $path;
437   
438   // check if path is an absolute URL
439   if (preg_match('/^[fhtps]+:\/\//', $path))
440     return $path;
441
442   // cut base_url to the last directory
443   if (strpos($base_url, '/')>7)
444   {
445     $host_url = substr($base_url, 0, strpos($base_url, '/'));
446     $base_url = substr($base_url, 0, strrpos($base_url, '/'));
447   }
448
449   // $path is absolute
450   if ($path{0}=='/')
451     $abs_path = $host_url.$path;
452   else
453   {
454     // strip './' because its the same as ''
455     $path = preg_replace('/^\.\//', '', $path);
456
457     if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER))
458       foreach ($matches as $a_match)
459       {
460         if (strrpos($base_url, '/'))
461           $base_url = substr($base_url, 0, strrpos($base_url, '/'));
462         
463         $path = substr($path, 3);
464       }
465
466     $abs_path = $base_url.'/'.$path;
467   }
468     
469   return $abs_path;
470 }
471
472
473 /**
474  * Wrapper function for strlen
475  */
476 function rc_strlen($str)
477 {
478   if (function_exists('mb_strlen'))
479     return mb_strlen($str);
480   else
481     return strlen($str);
482 }
483   
484 /**
485  * Wrapper function for strtolower
486  */
487 function rc_strtolower($str)
488 {
489   if (function_exists('mb_strtolower'))
490     return mb_strtolower($str);
491   else
492     return strtolower($str);
493 }
494
495 /**
496  * Wrapper function for substr
497  */
498 function rc_substr($str, $start, $len=null)
499 {
500   if (function_exists('mb_substr'))
501     return mb_substr($str, $start, $len);
502   else
503     return substr($str, $start, $len);
504 }
505
506 /**
507  * Wrapper function for strpos
508  */
509 function rc_strpos($haystack, $needle, $offset=0)
510 {
511   if (function_exists('mb_strpos'))
512     return mb_strpos($haystack, $needle, $offset);
513   else
514     return strpos($haystack, $needle, $offset);
515 }
516
517 /**
518  * Wrapper function for strrpos
519  */
520 function rc_strrpos($haystack, $needle, $offset=0)
521 {
522   if (function_exists('mb_strrpos'))
523     return mb_strrpos($haystack, $needle, $offset);
524   else
525     return strrpos($haystack, $needle, $offset);
526 }
527
528
529 /**
530  * Read a specific HTTP request header
531  *
532  * @access static
533  * @param  string $name Header name
534  * @return mixed  Header value or null if not available
535  */
536 function rc_request_header($name)
537 {
538   if (function_exists('getallheaders'))
539   {
540     $hdrs = array_change_key_case(getallheaders(), CASE_UPPER);
541     $key  = strtoupper($name);
542   }
543   else
544   {
545     $key  = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
546     $hdrs = array_change_key_case($_SERVER, CASE_UPPER);
547   }
548
549   return $hdrs[$key];
550   }
551
552
553 /**
554  * Replace the middle part of a string with ...
555  * if it is longer than the allowed length
556  *
557  * @param string Input string
558  * @param int    Max. length
559  * @param string Replace removed chars with this
560  * @return string Abbrevated string
561  */
562 function abbrevate_string($str, $maxlength, $place_holder='...')
563 {
564   $length = rc_strlen($str);
565   $first_part_length = floor($maxlength/2) - rc_strlen($place_holder);
566   
567   if ($length > $maxlength)
568   {
569     $second_starting_location = $length - $maxlength + $first_part_length + 1;
570     $str = rc_substr($str, 0, $first_part_length) . $place_holder . rc_substr($str, $second_starting_location, $length);
571   }
572
573   return $str;
574 }
575
576
577 /**
578  * Make sure the string ends with a slash
579  */
580 function slashify($str)
581 {
582   return unslashify($str).'/';
583 }
584
585
586 /**
587  * Remove slash at the end of the string
588  */
589 function unslashify($str)
590 {
591   return preg_replace('/\/$/', '', $str);
592 }
593   
594
595 /**
596  * Delete all files within a folder
597  *
598  * @param string Path to directory
599  * @return boolean True on success, False if directory was not found
600  */
601 function clear_directory($dir_path)
602 {
603   $dir = @opendir($dir_path);
604   if(!$dir) return FALSE;
605
606   while ($file = readdir($dir))
607     if (strlen($file)>2)
608       unlink("$dir_path/$file");
609
610   closedir($dir);
611   return TRUE;
612 }
613
614
615 /**
616  * Create a unix timestamp with a specified offset from now
617  *
618  * @param string String representation of the offset (e.g. 20min, 5h, 2days)
619  * @param int Factor to multiply with the offset
620  * @return int Unix timestamp
621  */
622 function get_offset_time($offset_str, $factor=1)
623   {
624   if (preg_match('/^([0-9]+)\s*([smhdw])/i', $offset_str, $regs))
625   {
626     $amount = (int)$regs[1];
627     $unit = strtolower($regs[2]);
628   }
629   else
630   {
631     $amount = (int)$offset_str;
632     $unit = 's';
633   }
634     
635   $ts = mktime();
636   switch ($unit)
637   {
638     case 'w':
639       $amount *= 7;
640     case 'd':
641       $amount *= 24;
642     case 'h':
643       $amount *= 60;
644     case 'm':
645       $amount *= 60;
646     case 's':
647       $ts += $amount * $factor;
648   }
649
650   return $ts;
651 }
652
653
654 /**
655  * Return the last occurence of a string in another string
656  *
657  * @param haystack string string in which to search
658  * @param needle string string for which to search
659  * @return index of needle within haystack, or false if not found
660  */
661 function strrstr($haystack, $needle)
662 {
663   $pver = phpversion();
664   if ($pver[0] >= 5)
665       return strrpos($haystack, $needle);
666   else
667   {
668     $index = strpos(strrev($haystack), strrev($needle));
669     if($index === false)
670         return false;
671     
672     $index = strlen($haystack) - strlen($needle) - $index;
673     return $index;
674   }
675 }
676
677
678 ?>