source: github/program/include/rcube_shared.inc @ 9fee0ed

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

Fixed folder display; added Portuguese and Catalan

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