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