source: github/program/include/rcube_shared.inc @ ea7c46b

HEADcourier-fixdev-browser-capabilitiespdorelease-0.6release-0.7release-0.8
Last change on this file since ea7c46b was ea7c46b, checked in by thomascube <thomas@…>, 7 years ago

Improved reading of POST and GET values

  • Property mode set to 100644
File size: 35.5 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | rcube_shared.inc                                                      |
6 |                                                                       |
7 | This file is part of the RoundCube PHP suite                          |
8 | Copyright (C) 2005, 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$
19
20*/
21
22
23// ********* round cube schared classes *********
24
25class rcube_html_page
26  {
27  var $css;
28 
29  var $scripts_path = '';
30  var $script_files = array();
31  var $scripts = array();
32  var $charset = 'ISO-8859-1';
33 
34  var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
35  var $script_tag      = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
36 
37  var $title = '';
38  var $header = '';
39  var $footer = '';
40  var $body = '';
41  var $body_attrib = array();
42  var $meta_tags = array();
43
44
45  // PHP 5 constructor
46  function __construct()
47    {
48    $this->css = new rcube_css();
49    }
50
51  // PHP 4 compatibility
52  function rcube_html_page()
53    {
54    $this->__construct();
55    }
56
57
58  function include_script($file, $position='head')
59    {
60    static $sa_files = array();
61   
62    if (in_array($file, $sa_files))
63      return;
64     
65    if (!is_array($this->script_files[$position]))
66      $this->script_files[$position] = array();
67     
68    $this->script_files[$position][] = $file;
69    }
70   
71 
72  function add_script($script, $position='head')
73    {
74    if (!isset($this->scripts[$position]))
75      $this->scripts[$position] = '';
76
77    $this->scripts[$position] .= "\n$script";
78    }
79
80
81  function set_title()
82    {
83   
84    }
85
86  function set_charset($charset)
87    {
88    global $MBSTRING;
89   
90    $this->charset = $charset;
91   
92    if ($MBSTRING && function_exists("mb_internal_encoding"))
93      {
94      if(!@mb_internal_encoding($charset))
95        $MBSTRING = FALSE;
96      }
97    }
98   
99  function get_charset()
100    {
101    return $this->charset;
102    }
103
104
105  function write($templ='', $base_path='')
106    {
107    $output = trim($templ);
108 
109    // set default page title
110    if (!strlen($this->title))
111      $this->title = 'RoundCube Mail';
112 
113    // replace specialchars in content
114    $__page_title = rep_specialchars_output($this->title, 'html', 'show', FALSE);
115    $__page_header = $__page_body = $__page_footer = '';
116   
117   
118    // include meta tag with charset
119    if (!empty($this->charset))
120      {
121      header('Content-Type: text/html; charset='.$this->charset);
122      $__page_header = '<meta http-equiv="content-type" content="text/html; charset='.$this->charset.'" />'."\n";
123      }
124 
125 
126    // definition of the code to be placed in the document header and footer
127    if (is_array($this->script_files['head']))
128      foreach ($this->script_files['head'] as $file)
129        $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file);
130
131    if (strlen($this->scripts['head']))
132      $__page_header .= sprintf($this->script_tag, $this->scripts['head']);
133         
134    if (is_array($this->script_files['foot']))
135      foreach ($this->script_files['foot'] as $file)
136        $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file);
137
138    if (strlen($this->scripts['foot']))
139      $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']);
140
141
142    $__page_header .= $this->css->show();
143
144 
145    // find page header
146    if($hpos = strpos(strtolower($output), '</head>'))
147      $__page_header .= "\n";
148    else
149      {
150      if (!is_numeric($hpos))
151        $hpos = strpos(strtolower($output), '<body');
152      if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html')))
153        {
154        while($output[$hpos]!='>')
155        $hpos++;
156        $hpos++;
157        }
158 
159      $__page_header = "<head>\n<title>$__page_title</title>\n$__page_header\n</head>\n";
160      }
161 
162    // add page hader
163    if($hpos)
164      $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output));
165    else
166      $output = $__page_header . $output;
167 
168 
169    // find page body
170    if($bpos = strpos(strtolower($output), '<body'))
171      {
172      while($output[$bpos]!='>') $bpos++;
173      $bpos++;
174      }
175    else
176      $bpos = strpos(strtolower($output), '</head>')+7;
177 
178    // add page body
179    if($bpos && $__page_body)
180      $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output));
181 
182 
183    // find and add page footer
184    if(($fpos = strpos(strtolower($output), '</body>')) || ($fpos = strpos(strtolower($output), '</html>')))
185      $output = substr($output,0,$fpos) . "$__page_footer\n" . substr($output,$fpos,strlen($output));
186    else
187      $output .= "\n$__page_footer";
188 
189 
190    // reset those global vars
191    $__page_header = $__page_footer = '';
192 
193 
194    // correct absolute pathes in images and other tags
195    $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output);
196 
197    print rcube_charset_convert($output, 'UTF-8', $this->charset);
198    }
199   
200   
201  function _parse($templ)
202    {
203   
204    }
205  }
206
207
208
209
210class rcube_css
211  {
212  var $css_data = array();
213
214  var $css_groups = array();
215
216  var $include_files = array();
217
218  var $grouped_output = TRUE;
219
220  var $content_type = 'text/css';
221
222  var $base_path = '';
223
224  var $indent_chars = "\t";
225
226
227  // add or overwrite a css definition
228  // either pass porperty and value as separate arguments
229  // or provide an associative array as second argument
230  function set_style($selector, $property, $value='')
231    {
232    $a_elements = $this->_parse_selectors($selector);
233    foreach ($a_elements as $element)
234      {
235      if (!is_array($property))
236        $property = array($property => $value);
237
238      foreach ($property as $name => $value)
239        $this->css_data[$element][strtolower($name)] = $value;
240      }
241
242    // clear goups array
243    $this->css_groups = array();
244    }
245
246
247  // unset a style property
248  function remove_style($selector, $property)
249    {
250    if (!is_array($property))
251      $property = array($property);
252
253    foreach ($property as $key)
254      unset($this->css_data[$selector][strtolower($key)]);
255
256    // clear goups array
257    $this->css_groups = array();
258    }
259
260
261  // define base path for external css files
262  function set_basepath($path)
263    {
264    $this->base_path = preg_replace('/\/$/', '', $path);
265    }
266
267
268  // enable/disable grouped output
269  function set_grouped_output($grouped)
270    {
271    $this->grouped_output = $grouped;
272    }
273
274
275  // add a css file as external source
276  function include_file($filename, $media='')
277    {
278    // include multiple files
279    if (is_array($filename))
280      {
281      foreach ($filename as $file)
282        $this->include_file($file, $media);
283      }
284    // add single file
285    else if (!in_array($filename, $this->include_files))
286      $this->include_files[] = array('file' => $filename,
287                                     'media' => $media);
288    }
289
290
291  // parse css code
292  function import_string($str)
293    {
294    $ret = FALSE;
295    if (strlen($str))
296      $ret = $this->_parse($str);
297
298    return $ret;
299    }
300
301
302  // open and parse a css file
303  function import_file($file)
304    {
305    $ret = FALSE;
306
307    if (!is_file($file))
308      return $ret;
309
310    // for php version >= 4.3.0
311    if (function_exists('file_get_contents'))
312      $ret = $this->_parse(file_get_contents($file));
313
314    // for order php versions
315    else if ($fp = fopen($file, 'r'))
316      {
317      $ret = $this->_parse(fread($fp, filesize($file)));
318      fclose($fp);
319      }
320
321    return $ret;
322    }
323
324
325  // copy all properties inherited from superior styles to a specific selector
326  function copy_inherited_styles($selector)
327    {
328    // get inherited props from body and tag/class selectors
329    $css_props = $this->_get_inherited_styles($selector);
330
331    // write modified props back and clear goups array
332    if (sizeof($css_props))
333      {
334      $this->css_data[$selector] = $css_props;
335      $this->css_groups = array();
336      }
337    }
338
339
340  // return css definition for embedding in HTML
341  function show()
342    {
343    $out = '';
344
345    // include external css files
346    if (sizeof($this->include_files))
347      foreach ($this->include_files as $file_arr)
348      $out .= sprintf('<link rel="stylesheet" type="%s" href="%s"%s>'."\n",
349                        $this->content_type,
350                        $this->_get_file_path($file_arr['file']),
351                        $file_arr['media'] ? ' media="'.$file_arr['media'].'"' : '');
352
353
354    // compose css string
355    if (sizeof($this->css_data))
356      $out .= sprintf("<style type=\"%s\">\n<!--\n\n%s-->\n</style>",
357                      $this->content_type,
358                      $this->to_string());
359
360
361    return $out;
362    }
363
364
365  // return valid css code of the current styles grid
366  function to_string($selector=NULL)
367    {
368    // return code for a single selector
369    if ($selector)
370      {
371      $indent_str = $this->indent_chars;
372      $this->indent_chars = '';
373
374      $prop_arr = $this->to_array($selector);
375      $out = $this->_style2string($prop_arr, TRUE);
376
377      $this->indent_chars = $indent_str;
378      }
379
380    // compose css code for complete data grid
381    else
382      {
383      $out = '';
384      $css_data = $this->to_array();
385
386      foreach ($css_data as $key => $prop_arr)
387        $out .= sprintf("%s {\n%s}\n\n",
388                        $key,
389                        $this->_style2string($prop_arr, TRUE));
390      }
391
392    return $out;
393    }
394
395
396  // return a single-line string of a css definition
397  function to_inline($selector)
398    {
399    if ($this->css_data[$selector])
400      return str_replace('"', '\\"', $this->_style2string($this->css_data[$selector], FALSE));
401    }
402
403
404  // return an associative array with selector(s) as key and styles array as value
405  function to_array($selector=NULL)
406    {
407    if (!$selector && $this->grouped_output)
408      {
409      // build groups if desired
410      if (!sizeof($this->css_groups))
411        $this->_build_groups();
412
413      // modify group array to get an array(selector => properties)
414      $out_arr = array();
415      foreach ($this->css_groups as $group_arr)
416        {
417        $key = join(', ', $group_arr['selectors']);
418        $out_arr[$key] = $group_arr['properties'];
419        }
420      }
421    else
422      $out_arr = $this->css_data;
423
424    return $selector ? $out_arr[$selector] : $out_arr;
425    }
426
427
428  // create a css file
429  function to_file($filepath)
430    {
431    if ($fp = fopen($filepath, 'w'))
432      {
433      fwrite($fp, $this->to_string());
434      fclose($fp);
435      return TRUE;
436      }
437
438    return FALSE;
439    }
440
441
442  // alias method for import_string() [DEPRECATED]
443  function add($str)
444    {
445    $this->import_string($str);
446    }
447
448  // alias method for to_string() [DEPRECATED]
449  function get()
450    {
451    return $this->to_string();
452    }
453
454
455
456  // ******** private methods ********
457
458
459  // parse a string and add styles to internal data grid
460  function _parse($str)
461    {
462    // remove comments
463    $str = preg_replace("/\/\*(.*)?\*\//Usi", '', $str);
464
465    // parse style definitions
466    if (!preg_match_all ('/([a-z0-9\.#*:_][a-z0-9\.\-_#:*,\[\]\(\)\s\"\'\+\|>~=]+)\s*\{([^\}]*)\}/ims', $str, $matches, PREG_SET_ORDER))
467      return FALSE;
468
469
470    foreach ($matches as $match_arr)
471      {
472      // split selectors into array
473      $a_keys = $this->_parse_selectors(trim($match_arr[1]));
474
475      // parse each property of an element
476      $codes = explode(";", trim($match_arr[2]));
477      foreach ($codes as $code)
478        {
479        if (strlen(trim($code))>0)
480          {
481          // find the property and the value
482          if (!($sep = strpos($code, ':')))
483            continue;
484
485          $property = strtolower(trim(substr($code, 0, $sep)));
486          $value    = trim(substr($code, $sep+1));
487
488          // add the property to the object array
489          foreach ($a_keys as $key)
490            $this->css_data[$key][$property] = $value;
491          }
492        }
493      }
494
495    // clear goups array
496    if (sizeof($matches))
497      {
498      $this->css_groups = array();
499      return TRUE;
500      }
501
502    return FALSE;
503    }
504
505
506  // split selector group
507  function _parse_selectors($selector)
508    {
509    // trim selector and remove multiple spaces
510    $selector = preg_replace('/\s+/', ' ', trim($selector));
511
512    if (strpos($selector, ','))
513      return preg_split('/[\t\s\n\r]*,[\t\s\n\r]*/mi', $selector);
514    else
515      return array($selector);
516    }
517
518
519  // compare identical styles and make groups
520  function _build_groups()
521    {
522    // clear group array
523    $this->css_groups = array();
524    $string_group_map = array();
525
526    // bulild css string for each selector and check if the same is already defines
527    foreach ($this->css_data as $selector => $prop_arr)
528      {
529      // make shure to compare props in the same order
530      ksort($prop_arr);
531      $compare_str = preg_replace('/[\s\t]+/', '', $this->_style2string($prop_arr, FALSE));
532
533      // add selector to extisting group
534      if (isset($string_group_map[$compare_str]))
535        {
536        $group_index = $string_group_map[$compare_str];
537        $this->css_groups[$group_index]['selectors'][] = $selector;
538        }
539
540      // create new group
541      else
542        {
543        $i = sizeof($this->css_groups);
544        $string_group_map[$compare_str] = $i;
545        $this->css_groups[$i] = array('selectors' => array($selector),
546                                      'properties' => $this->css_data[$selector]);
547        }
548      }
549    }
550
551
552  // convert the prop array into a valid css definition
553  function _style2string($prop_arr, $multiline=TRUE)
554    {
555    $out = '';
556    $delm   = $multiline ? "\n" : '';
557    $spacer = $multiline ? ' ' : '';
558    $indent = $multiline ? $this->indent_chars : '';
559
560    if (is_array($prop_arr))
561      foreach ($prop_arr as $prop => $value)
562        if (strlen($value))
563          $out .= sprintf('%s%s:%s%s;%s',
564                          $indent,
565                          $prop,
566                          $spacer,
567                          $value,
568                          $delm);
569
570    return $out;
571    }
572
573
574  // copy all properties inherited from superior styles to a specific selector
575  function _get_inherited_styles($selector, $loop=FALSE)
576    {
577    $css_props = $this->css_data[$selector] ? $this->css_data[$selector] : array();
578
579    // get styles from tag selector
580    if (preg_match('/(([a-z0-9]*)(\.[^\s]+)?)$/i', $selector, $regs))
581      {
582      $sel = $regs[1];
583      $tagname = $regs[2];
584      $class = $regs[3];
585
586      if ($sel && is_array($this->css_data[$sel]))
587        $css_props = $this->_merge_styles($this->css_data[$sel], $css_props);
588
589      if ($class && is_array($this->css_data[$class]))
590        $css_props = $this->_merge_styles($this->css_data[$class], $css_props);
591
592      if ($tagname && is_array($this->css_data[$tagname]))
593        $css_props = $this->_merge_styles($this->css_data[$tagname], $css_props);
594      }
595
596    // analyse inheritance
597    if (strpos($selector, ' '))
598      {
599      $a_hier = split(' ', $selector);
600      if (sizeof($a_hier)>1)
601        {
602        array_pop($a_hier);
603        $base_selector = join(' ', $a_hier);
604
605        // call this method recursively
606        $new_props = $this->_get_inherited_styles($base_selector, TRUE);
607        $css_props = $this->_merge_styles($new_props, $css_props);
608        }
609      }
610
611    // get body style
612    if (!$loop && is_array($this->css_data['body']))
613      $css_props = $this->_merge_styles($this->css_data['body'], $css_props);
614
615    return $css_props;
616    }
617
618
619  // merge two arrays with style properties together like a browser would do
620  function _merge_styles($one, $two)
621    {
622    // these properties are additive
623    foreach (array('text-decoration') as $prop)
624      if ($one[$prop] && $two[$prop])
625        {
626        // if value contains 'none' it's ignored
627        if (strstr($one[$prop], 'none'))
628          continue;
629        else if (strstr($two[$prop], 'none'))
630          unset($two[$prop]);
631
632        $a_values_one = split(' ', $one[$prop]);
633        $a_values_two = split(' ', $two[$prop]);
634        $two[$prop] = join(' ', array_unique(array_merge($a_values_one, $a_values_two)));
635        }
636
637    return array_merge($one, $two);
638    }
639
640
641  // resolve file path
642  function _get_file_path($file)
643    {
644    if (!$this->base_path && $GLOBALS['CSS_PATH'])
645      $this->set_basepath($GLOBALS['CSS_PATH']);
646
647    $base = ($file{0}=='/' || $file{0}=='.' || substr($file, 0, 7)=='http://') ? '' :
648            ($this->base_path ? $this->base_path.'/' : '');
649    return $base.$file;
650    }
651
652  }
653
654
655
656class base_form_element
657  {
658  var $uppertags = FALSE;
659  var $upperattribs = FALSE;
660  var $upperprops = FALSE;
661  var $newline = FALSE;
662 
663  var $attrib = array();
664
665
666  // create string with attributes
667  function create_attrib_string($tagname='')
668    {
669    if (!sizeof($this->attrib))
670      return '';
671
672    if ($this->name!='')
673      $this->attrib['name'] = $this->name;
674
675    $attrib_arr = array();
676    foreach ($this->attrib as $key => $value)
677      {
678      // don't output some internally used attributes
679      if (in_array($key, array('form', 'quicksearch')))
680        continue;
681
682      // skip if size if not numeric
683      if (($key=='size' && !is_numeric($value)))
684        continue;
685       
686      // skip empty eventhandlers
687      if ((strpos($key,'on')===0 && $value==''))
688        continue;
689
690      // encode textarea content
691      if ($key=='value')
692        $value = rep_specialchars_output($value, 'html', 'replace', FALSE);
693
694      // attributes with no value
695      if (in_array($key, array('checked', 'multiple', 'disabled', 'selected')))
696        {
697        if ($value)
698          $attrib_arr[] = $key;
699        }
700      // don't convert size of value attribute
701      else if ($key=='value')
702        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $value, 'value');
703       
704      // regular tag attributes
705      else
706        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case($value, 'value'));
707      }
708
709    return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
710    }
711   
712   
713  // convert tags and attributes to upper-/lowercase
714  // $type can either be "tag" or "attrib"
715  function _conv_case($str, $type='attrib')
716    {
717    if ($type == 'tag')
718      return $this->uppertags ? strtoupper($str) : strtolower($str);
719    else if ($type == 'attrib')
720      return $this->upperattribs ? strtoupper($str) : strtolower($str);
721    else if ($type == 'value')
722      return $this->upperprops ? strtoupper($str) : strtolower($str);
723    }   
724  }
725
726
727class input_field extends base_form_element
728  {
729  var $type = 'text';
730 
731  // PHP 5 constructor
732  function __construct($attrib=NULL)
733    {
734    if (is_array($attrib))
735      $this->attrib = $attrib;
736
737    if ($attrib['type'])
738      $this->type = $attrib['type'];   
739
740    if ($attrib['newline'])
741      $this->newline = TRUE;   
742    }
743
744  // PHP 4 compatibility
745  function input_field($attrib=array())
746    {
747    $this->__construct($attrib);
748    } 
749
750  // compose input tag
751  function show($value=NULL, $attrib=NULL)
752    {
753    // overwrite object attributes
754    if (is_array($attrib))
755      $this->attrib = array_merge($this->attrib, $attrib);
756
757    // set value attribute
758    if ($value!==NULL)
759      $this->attrib['value'] = $value;
760
761    $this->attrib['type'] = $this->type;
762
763    // return final tag
764    return sprintf('<%s%s />%s',
765                   $this->_conv_case('input', 'tag'),
766                   $this->create_attrib_string(),
767                   ($this->newline ? "\n" : ""));   
768    } 
769  }
770
771
772class textfield extends input_field
773  {
774  var $type = 'text';
775  }
776
777class passwordfield extends input_field
778  {
779  var $type = 'password';
780  }
781
782class radiobutton extends input_field
783  {
784  var $type = 'radio';
785  }
786
787class checkbox extends input_field
788  {
789  var $type = 'checkbox';
790
791
792  function show($value='', $attrib=NULL)
793    {
794    // overwrite object attributes
795    if (is_array($attrib))
796      $this->attrib = array_merge($this->attrib, $attrib);   
797
798    $this->attrib['type'] = $this->type;
799
800    if ($value && (string)$value==(string)$this->attrib['value'])
801      $this->attrib['checked'] = TRUE;
802    else
803      $this->attrib['checked'] = FALSE;
804
805    // return final tag
806    return sprintf('<%s%s />%s',
807                   $this->_conv_case('input', 'tag'),
808                   $this->create_attrib_string(),
809                   ($this->newline ? "\n" : ""));   
810    }
811  }
812
813
814class textarea extends base_form_element
815  {
816  // PHP 5 constructor
817  function __construct($attrib=array())
818    {
819    $this->attrib = $attrib;
820
821    if ($attrib['newline'])
822      $this->newline = TRUE;   
823    }
824
825  // PHP 4 compatibility
826  function textarea($attrib=array())
827    {
828    $this->__construct($attrib);
829    }
830   
831  function show($value='', $attrib=NULL)
832    {
833    // overwrite object attributes
834    if (is_array($attrib))
835      $this->attrib = array_merge($this->attrib, $attrib);
836   
837    // take value attribute as content
838    if ($value=='')
839      $value = $this->attrib['value'];
840   
841    // make shure we don't print the value attribute
842    if (isset($this->attrib['value']))
843      unset($this->attrib['value']);
844
845    if (strlen($value))
846      $value = rep_specialchars_output($value, 'html', 'replace', FALSE);
847   
848    // return final tag
849    return sprintf('<%s%s>%s</%s>%s',
850                   $this->_conv_case('textarea', 'tag'),
851                   $this->create_attrib_string(),
852                   $value,
853                   $this->_conv_case('textarea', 'tag'),
854                   ($this->newline ? "\n" : ""));       
855    }
856  }
857
858
859class hiddenfield extends base_form_element
860  {
861  var $fields_arr = array();
862  var $newline = TRUE;
863
864  // PHP 5 constructor
865  function __construct($attrib=NULL)
866    {
867    if (is_array($attrib))
868      $this->add($attrib);
869    }
870
871  // PHP 4 compatibility
872  function hiddenfield($attrib=NULL)
873    {
874    $this->__construct($attrib);
875    }
876
877  // add a hidden field to this instance
878  function add($attrib)
879    {
880    $this->fields_arr[] = $attrib;
881    }
882
883
884  function show()
885    {
886    $out = '';
887    foreach ($this->fields_arr as $attrib)
888      {
889      $this->attrib = $attrib;
890      $this->attrib['type'] = 'hidden';
891     
892      $out .= sprintf('<%s%s />%s',
893                   $this->_conv_case('input', 'tag'),
894                   $this->create_attrib_string(),
895                   ($this->newline ? "\n" : ""));   
896      }
897
898    return $out;
899    }
900  }
901
902
903class select extends base_form_element
904  {
905  var $options = array();
906
907  /*
908  syntax:
909  -------
910  // create instance. arguments are used to set attributes of select-tag
911  $select = new select(array('name' => 'fieldname'));
912
913  // add one option
914  $select->add('Switzerland', 'CH');
915
916  // add multiple options
917  $select->add(array('Switzerland', 'Germany'),
918               array('CH', 'DE'));
919
920  // add 10 blank options with 50 chars
921  // used to fill with javascript (necessary for 4.x browsers)
922  $select->add_blank(10, 50);
923
924  // generate pulldown with selection 'Switzerland'  and return html-code
925  // as second argument the same attributes available to instanciate can be used
926  print $select->show('CH');
927  */
928
929  // PHP 5 constructor
930  function __construct($attrib=NULL)
931    {
932    if (is_array($attrib))
933      $this->attrib = $attrib;
934
935    if ($attrib['newline'])
936      $this->newline = TRUE;
937    }
938
939  // PHP 4 compatibility
940  function select($attrib=NULL)
941    {
942    $this->__construct($attrib);
943    }
944
945
946  function add($names, $values=NULL)
947    {
948    if (is_array($names))
949      {
950      foreach ($names as $i => $text)
951        $this->options[] = array('text' => $text, 'value' => (string)$values[$i]);
952      }
953    else
954      {
955      $this->options[] = array('text' => $names, 'value' => (string)$values);
956      }
957    }
958
959   
960  function add_blank($nr, $width=0)
961    {
962    $text = $width ? str_repeat('&nbsp;', $width) : '';
963   
964    for ($i=0; $i < $nr; $i++)
965      $this->options[] = array('text' => $text);
966    }
967
968 
969  function show($select=array(), $attrib=NULL)
970    {
971    $options_str = "\n";
972    $value_str = $this->_conv_case(' value="%s"', 'attrib');
973   
974    if (!is_array($select))
975      $select = array((string)$select);
976   
977    foreach ($this->options as $option)
978      {
979      $selected = ((strlen($option['value']) && in_array($option['value'], $select, TRUE)) ||
980                   (in_array($option['text'], $select, TRUE))) ? $this->_conv_case(' selected', 'attrib') : '';
981                 
982      $options_str .= sprintf("<%s%s%s>%s</%s>\n",
983                             $this->_conv_case('option', 'tag'),
984                             strlen($option['value']) ? sprintf($value_str, $option['value']) : '',
985                             $selected,
986                             rep_specialchars_output($option['text'], 'html', 'replace', FALSE),
987                             $this->_conv_case('option', 'tag'));
988      }
989                             
990    // return final tag
991    return sprintf('<%s%s>%s</%s>%s',
992                   $this->_conv_case('select', 'tag'),
993                   $this->create_attrib_string(),
994                   $options_str,
995                   $this->_conv_case('select', 'tag'),
996                   ($this->newline ? "\n" : ""));   
997    }
998  }
999
1000
1001
1002
1003// ********* rcube schared functions *********
1004
1005
1006// provide details about the client's browser
1007function rcube_browser()
1008  {
1009  $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
1010
1011  $bw['ver'] = 0;
1012  $bw['win'] = stristr($HTTP_USER_AGENT, 'win');
1013  $bw['mac'] = stristr($HTTP_USER_AGENT, 'mac');
1014  $bw['linux'] = stristr($HTTP_USER_AGENT, 'linux');
1015  $bw['unix']  = stristr($HTTP_USER_AGENT, 'unix');
1016
1017  $bw['ns4'] = stristr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie');
1018  $bw['ns']  = ($bw['ns4'] || stristr($HTTP_USER_AGENT, 'netscape'));
1019  $bw['ie']  = stristr($HTTP_USER_AGENT, 'msie');
1020  $bw['mz']  = stristr($HTTP_USER_AGENT, 'mozilla/5');
1021  $bw['opera'] = stristr($HTTP_USER_AGENT, 'opera');
1022  $bw['safari'] = stristr($HTTP_USER_AGENT, 'safari');
1023
1024  if($bw['ns'])
1025    {
1026    $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1027    $bw['ver'] = $test ? (float)$regs[1] : 0;
1028    }
1029  if($bw['mz'])
1030    {
1031    $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1032    $bw['ver'] = $test ? (float)$regs[1] : 0;
1033    }
1034  if($bw['ie'])
1035    {
1036    $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1037    $bw['ver'] = $test ? (float)$regs[1] : 0;
1038    }
1039  if($bw['opera'])
1040    {
1041    $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1042    $bw['ver'] = $test ? (float)$regs[1] : 0;
1043    }
1044
1045  if(eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs))
1046    $bw['lang'] =  $regs[1];
1047  else
1048    $bw['lang'] =  'en';
1049
1050  $bw['dom'] = ($bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5) || ($bw['opera'] && $bw['ver']>=7));
1051  $bw['pngalpha'] = $bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5.5) ||
1052                    ($bw['ie'] && $bw['ver']>=5 && $bw['mac']) || ($bw['opera'] && $bw['ver']>=7) ? TRUE : FALSE;
1053
1054  return $bw;
1055  }
1056
1057
1058// get text in the desired language from the language file
1059function rcube_label($attrib)
1060  {
1061  global $sess_user_lang, $INSTALL_PATH, $OUTPUT;
1062  static $sa_text_data, $s_language, $utf8_decode;
1063
1064  // extract attributes
1065  if (is_string($attrib))
1066    $attrib = array('name' => $attrib);
1067   
1068  $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1;
1069  $vars = isset($attrib['vars']) ? $attrib['vars'] : '';
1070
1071  $command_name = strlen($attrib['command']) ? $attrib['command'] : NULL;
1072  $alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : '');
1073
1074
1075  // load localized texts
1076  if (!$sa_text_data || $s_language != $sess_user_lang)
1077    {
1078    $sa_text_data = array();
1079   
1080    // get english labels (these should be complete)
1081    @include($INSTALL_PATH.'program/localization/en_US/labels.inc');
1082    @include($INSTALL_PATH.'program/localization/en_US/messages.inc');
1083
1084    if (is_array($labels))
1085      $sa_text_data = $labels;
1086    if (is_array($messages))
1087      $sa_text_data = array_merge($sa_text_data, $messages);
1088   
1089    // include user language files
1090    if ($sess_user_lang!='en' && is_dir($INSTALL_PATH.'program/localization/'.$sess_user_lang))
1091      {
1092      include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/labels.inc');
1093      include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/messages.inc');
1094
1095      if (is_array($labels))
1096        $sa_text_data = array_merge($sa_text_data, $labels);
1097      if (is_array($messages))
1098        $sa_text_data = array_merge($sa_text_data, $messages);
1099      }
1100     
1101    $s_language = $sess_user_lang;
1102    }
1103
1104  // text does not exist
1105  if (!($text_item = $sa_text_data[$alias]))
1106    {
1107    /*
1108    raise_error(array('code' => 500,
1109                      'type' => 'php',
1110                      'line' => __LINE__,
1111                      'file' => __FILE__,
1112                      'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE);
1113    */
1114    return "[$alias]";
1115    }
1116
1117  // make text item array
1118  $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item);
1119
1120  // decide which text to use
1121  if ($nr==1)
1122    $text = $a_text_item['single'];
1123  else if ($nr>0)
1124    $text = $a_text_item['multiple'];
1125  else if ($nr==0)
1126    {
1127    if ($a_text_item['none'])
1128      $text = $a_text_item['none'];
1129    else if ($a_text_item['single'])
1130      $text = $a_text_item['single'];
1131    else if ($a_text_item['multiple'])
1132      $text = $a_text_item['multiple'];
1133    }
1134
1135  // default text is single
1136  if ($text=='')
1137    $text = $a_text_item['single'];
1138
1139  // replace vars in text
1140  if (is_array($attrib['vars']))
1141    {
1142    foreach ($attrib['vars'] as $var_key=>$var_value)
1143      $a_replace_vars[substr($var_key, 0, 1)=='$' ? substr($var_key, 1) : $var_key] = $var_value;
1144    }
1145
1146  if ($a_replace_vars)
1147    $text = preg_replace('/\${?([_a-z]{1}[_a-z0-9]*)}?/ei', '$a_replace_vars["\1"]', $text);
1148
1149  // remove variables in text which were not available in arg $vars and $nr
1150  eval("\$text = <<<EOF
1151$text
1152EOF;
1153");
1154
1155  // format output
1156  if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])
1157    return ucfirst($text);
1158  else if ($attrib['uppercase'])
1159    return strtoupper($text);
1160  else if ($attrib['lowercase'])
1161    return strtolower($text);
1162  else
1163    return $text;
1164
1165  return $text;
1166  }
1167
1168
1169// send HTTP header for no-cacheing steps
1170function send_nocacheing_headers()
1171  {
1172  if (headers_sent())
1173    return;
1174
1175  header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
1176  header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
1177  header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
1178  header("Pragma: no-cache");
1179  }
1180
1181
1182// send header with expire date 30 days in future
1183function send_future_expire_header()
1184  {
1185  if (!headers_sent())
1186    header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+2600000)." GMT");
1187  }
1188
1189
1190// function to convert an array to a javascript array
1191function array2js($arr, $type='')
1192  {
1193  if (!$type)
1194    $type = 'mixed';
1195
1196  if (is_array($arr))
1197    {
1198    // no items in array
1199    if (!sizeof($arr))
1200      return 'new Array()';
1201    else
1202      {
1203      $a_pairs = array();
1204      $keys_arr = array_keys($arr);
1205      $is_assoc = $have_numeric = 0;
1206
1207      for ($i=0; $i<sizeof($keys_arr); ++$i)
1208        {
1209        if(is_numeric($keys_arr[$i]))
1210          $have_numeric = 1;
1211        if (!is_numeric($keys_arr[$i]) || $keys_arr[$i]!=$i)
1212          $is_assoc = 1;
1213        if($is_assoc && $have_numeric)
1214          break;
1215        }
1216
1217      $previous_was_array = false;
1218      while (list($key, $value) = each($arr))
1219        {
1220        // enclose key with quotes if it is not variable-name conform
1221        if (!ereg("^[_a-zA-Z]{1}[_a-zA-Z0-9]*$", $key) /* || is_js_reserved_word($key) */)
1222          $key = "'$key'";
1223
1224        if (!is_array($value))
1225          {
1226          $value = str_replace("\r\n", '\n', $value);
1227          $value = str_replace("\n", '\n', $value);
1228          }
1229
1230        $is_string = false;
1231        if (!is_array($value))
1232          {
1233          if ($type=='string')
1234            $is_string = true;
1235          else if ((($type=='mixed' && is_numeric($value)) || $type=='int') && strlen($value)<16)   // js interprets numbers with digits >15 as ...e+...
1236            $is_string = FALSE;
1237          else
1238            $is_string = TRUE;
1239          }
1240
1241        if ($is_string)
1242          $value = "'".preg_replace("/(?<!\\\)'/", "\'", $value)."'";
1243
1244        $a_pairs[] = sprintf("%s%s",
1245                             $is_assoc ? "$key:" : '',
1246                             is_array($value) ? array2js($value, $type) : $value);
1247        }
1248
1249      if ($a_pairs)
1250        {
1251        if ($is_assoc)
1252          $return = '{'.implode(',', $a_pairs).'}';
1253        else
1254          $return = '['.implode(',', $a_pairs).']';
1255        }
1256
1257      return $return;
1258      }
1259    }
1260  else
1261    return $arr;
1262  }
1263
1264
1265// similar function as in_array() ut case-insensitive
1266function in_array_nocase($needle, $haystack)
1267  {
1268  foreach ($haystack as $value)
1269    {
1270    if (strtolower($needle)===strtolower($value))
1271      return TRUE;
1272    }
1273   
1274  return FALSE;
1275  }
1276
1277
1278
1279// find out if the string content means TRUE or FALSE
1280function get_boolean($str)
1281  {
1282  $str = strtolower($str);
1283  if(in_array($str, array('false', '0', 'no', 'nein', ''), TRUE))
1284    return FALSE;
1285  else
1286    return TRUE;
1287  }
1288
1289
1290function show_bytes($numbytes)
1291  {
1292  if ($numbytes > 1024)
1293    return sprintf('%d KB', round($numbytes/1024));
1294  else
1295    return sprintf('%d B', $numbytes);
1296  }
1297
1298
1299// convert paths like ../xxx to an absolute path using a base url
1300function make_absolute_url($path, $base_url)
1301    {
1302    $host_url = $base_url;
1303    $abs_path = $path;
1304
1305    // cut base_url to the last directory
1306    if (strpos($base_url, '/')>7)
1307      {
1308      $host_url = substr($base_url, 0, strpos($base_url, '/'));
1309      $base_url = substr($base_url, 0, strrpos($base_url, '/'));
1310      }
1311
1312    // $path is absolute
1313    if ($path{0}=='/')
1314      $abs_path = $host_url.$path;
1315    else
1316      {
1317      // strip './' because its the same as ''
1318      $path = preg_replace('/^\.\//', '', $path);
1319
1320      if(preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER))
1321        foreach($matches as $a_match)
1322          {
1323          if (strrpos($base_url, '/'))
1324            $base_url = substr($base_url, 0, strrpos($base_url, '/'));
1325         
1326          $path = substr($path, 3);
1327          }
1328
1329      $abs_path = $base_url.'/'.$path;
1330      }
1331     
1332    return $abs_path;
1333    }
1334
1335
1336
1337function abbrevate_string($str, $maxlength, $place_holder='...')
1338  {
1339  $length = strlen($str);
1340  $first_part_length = floor($maxlength/2) - strlen($place_holder);
1341 
1342  if ($length > $maxlength)
1343    {
1344    $second_starting_location = $length - $maxlength + $first_part_length + 1;
1345    $str = substr($str, 0, $first_part_length) . $place_holder . substr($str, $second_starting_location, $length);
1346    }
1347
1348  return $str;
1349  }
1350
1351
1352// delete all files within a folder
1353function clear_directory($dir_path)
1354  {
1355  $dir = @opendir($dir_path);
1356  if(!$dir) return FALSE;
1357
1358  while ($file = readdir($dir))
1359    if (strlen($file)>2)
1360      unlink("$dir_path/$file");
1361
1362  closedir($dir);
1363  return TRUE;
1364  }
1365
1366
1367// create a unix timestamp with a specified offset from now
1368function get_offset_time($offset_str, $factor=1)
1369  {
1370  if (preg_match('/^([0-9]+)\s*([smhdw])/i', $offset_str, $regs))
1371    {
1372    $amount = (int)$regs[1];
1373    $unit = strtolower($regs[2]);
1374    }
1375  else
1376    {
1377    $amount = (int)$offset_str;
1378    $unit = 's';
1379    }
1380   
1381  $ts = mktime();
1382  switch ($unit)
1383    {
1384    case 'w':
1385      $amount *= 7;
1386    case 'd':
1387      $amount *= 24;
1388    case 'h':
1389      $amount *= 60;
1390    case 'h':
1391      $amount *= 60;
1392    case 's':
1393      $ts += $amount * $factor;
1394    }
1395
1396  return $ts;
1397  }
1398
1399
1400?>
Note: See TracBrowser for help on using the repository browser.