source: github/program/include/rcube_shared.inc @ 4b0f65a

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

Fixed minor bugs

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