4 +-----------------------------------------------------------------------+
7 | This file is part of the RoundCube PHP suite |
8 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland |
9 | Licensed under the GNU GPL |
12 | Shared functions and classes used in PHP projects |
14 +-----------------------------------------------------------------------+
15 | Author: Thomas Bruederli <roundcube@gmail.com> |
16 +-----------------------------------------------------------------------+
18 $Id: rcube_shared.inc 543 2007-04-28 18:07:12Z thomasb $
23 // ********* round cube schared classes *********
29 var $scripts_path = '';
30 var $script_files = array();
31 var $external_scripts = array();
32 var $scripts = array();
33 var $charset = 'ISO-8859-1';
35 var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
36 var $script_tag = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
37 var $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
38 var $tag_format_external_script = "<script type=\"text/javascript\" src=\"%s\"></script>\n";
44 var $body_attrib = array();
45 var $meta_tags = array();
49 function __construct()
51 $this->css = new rcube_css();
54 // PHP 4 compatibility
55 function rcube_html_page()
61 function include_script($file, $position='head')
63 static $sa_files = array();
65 if (in_array($file, $sa_files))
68 if (!is_array($this->script_files[$position]))
69 $this->script_files[$position] = array();
71 $this->script_files[$position][] = $file;
74 function include_external_script($script_location, $position='head')
76 if (!is_array($this->external_scripts[$position]))
78 $this->external_scripts[$position] = array();
81 $this->external_scripts[$position][] = $script_location;
84 function add_script($script, $position='head')
86 if (!isset($this->scripts[$position]))
87 $this->scripts[$position] = "\n".rtrim($script);
89 $this->scripts[$position] .= "\n".rtrim($script);
92 function add_header($str)
94 $this->header .= "\n".$str;
97 function add_footer($str)
99 $this->footer .= "\n".$str;
102 function set_title($t)
108 function set_charset($charset)
112 $this->charset = $charset;
114 if ($MBSTRING && function_exists("mb_internal_encoding"))
116 if(!@mb_internal_encoding($charset))
121 function get_charset()
123 return $this->charset;
129 $this->css = new rcube_css();
130 $this->script_files = array();
131 $this->scripts = array();
138 function write($templ='', $base_path='')
140 $output = empty($templ) ? $this->default_template : trim($templ);
142 // set default page title
143 if (empty($this->title))
144 $this->title = 'RoundCube Mail';
146 // replace specialchars in content
147 $__page_title = Q($this->title, 'show', FALSE);
148 $__page_header = $__page_body = $__page_footer = '';
151 // include meta tag with charset
152 if (!empty($this->charset))
154 header('Content-Type: text/html; charset='.$this->charset);
155 $__page_header = '<meta http-equiv="content-type" content="text/html; charset='.$this->charset.'" />'."\n";
159 // definition of the code to be placed in the document header and footer
160 if (is_array($this->script_files['head']))
161 foreach ($this->script_files['head'] as $file)
162 $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file);
164 if (is_array($this->external_scripts['head']))
165 foreach ($this->external_scripts['head'] as $xscript)
166 $__page_header .= sprintf($this->tag_format_external_script, $xscript);
168 $head_script = $this->scripts['head_top'] . $this->scripts['head'];
169 if (!empty($head_script))
170 $__page_header .= sprintf($this->script_tag, $head_script);
172 if (!empty($this->header))
173 $__page_header .= $this->header;
175 if (is_array($this->script_files['foot']))
176 foreach ($this->script_files['foot'] as $file)
177 $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file);
179 if (!empty($this->scripts['foot']))
180 $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']);
182 if (!empty($this->footer))
183 $__page_footer .= $this->footer;
185 $__page_header .= $this->css->show();
188 if($hpos = strpos(strtolower($output), '</head>'))
189 $__page_header .= "\n";
192 if (!is_numeric($hpos))
193 $hpos = strpos(strtolower($output), '<body');
194 if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html')))
196 while($output[$hpos]!='>')
201 $__page_header = "<head>\n<title>$__page_title</title>\n$__page_header\n</head>\n";
206 $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output));
208 $output = $__page_header . $output;
212 if($bpos = strpos(strtolower($output), '<body'))
214 while($output[$bpos]!='>') $bpos++;
218 $bpos = strpos(strtolower($output), '</head>')+7;
221 if($bpos && $__page_body)
222 $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output));
225 // find and add page footer
226 $output_lc = strtolower($output);
227 if(($fpos = strrstr($output_lc, '</body>')) ||
228 ($fpos = strrstr($output_lc, '</html>')))
229 $output = substr($output, 0, $fpos) . "$__page_footer\n" . substr($output, $fpos);
231 $output .= "\n$__page_footer";
234 // reset those global vars
235 $__page_header = $__page_footer = '';
238 // correct absolute paths in images and other tags
239 $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output);
240 $output = str_replace('$__skin_path', $base_path, $output);
242 print rcube_charset_convert($output, 'UTF-8', $this->charset);
246 function _parse($templ)
257 var $css_data = array();
259 var $css_groups = array();
261 var $include_files = array();
263 var $grouped_output = TRUE;
265 var $content_type = 'text/css';
269 var $indent_chars = "\t";
272 // add or overwrite a css definition
273 // either pass porperty and value as separate arguments
274 // or provide an associative array as second argument
275 function set_style($selector, $property, $value='')
277 $a_elements = $this->_parse_selectors($selector);
278 foreach ($a_elements as $element)
280 if (!is_array($property))
281 $property = array($property => $value);
283 foreach ($property as $name => $value)
284 $this->css_data[$element][strtolower($name)] = $value;
288 $this->css_groups = array();
292 // unset a style property
293 function remove_style($selector, $property)
295 if (!is_array($property))
296 $property = array($property);
298 foreach ($property as $key)
299 unset($this->css_data[$selector][strtolower($key)]);
302 $this->css_groups = array();
306 // define base path for external css files
307 function set_basepath($path)
309 $this->base_path = preg_replace('/\/$/', '', $path);
313 // enable/disable grouped output
314 function set_grouped_output($grouped)
316 $this->grouped_output = $grouped;
320 // add a css file as external source
321 function include_file($filename, $media='')
323 // include multiple files
324 if (is_array($filename))
326 foreach ($filename as $file)
327 $this->include_file($file, $media);
330 else if (!in_array($filename, $this->include_files))
331 $this->include_files[] = array('file' => $filename,
337 function import_string($str)
341 $ret = $this->_parse($str);
347 // open and parse a css file
348 function import_file($file)
355 // for php version >= 4.3.0
356 if (function_exists('file_get_contents'))
357 $ret = $this->_parse(file_get_contents($file));
359 // for order php versions
360 else if ($fp = fopen($file, 'r'))
362 $ret = $this->_parse(fread($fp, filesize($file)));
370 // copy all properties inherited from superior styles to a specific selector
371 function copy_inherited_styles($selector)
373 // get inherited props from body and tag/class selectors
374 $css_props = $this->_get_inherited_styles($selector);
376 // write modified props back and clear goups array
377 if (sizeof($css_props))
379 $this->css_data[$selector] = $css_props;
380 $this->css_groups = array();
385 // return css definition for embedding in HTML
390 // include external css files
391 if (sizeof($this->include_files))
392 foreach ($this->include_files as $file_arr)
393 $out .= sprintf('<link rel="stylesheet" type="%s" href="%s"%s>'."\n",
395 $this->_get_file_path($file_arr['file']),
396 $file_arr['media'] ? ' media="'.$file_arr['media'].'"' : '');
399 // compose css string
400 if (sizeof($this->css_data))
401 $out .= sprintf("<style type=\"%s\">\n<!--\n\n%s-->\n</style>",
410 // return valid css code of the current styles grid
411 function to_string($selector=NULL)
413 // return code for a single selector
416 $indent_str = $this->indent_chars;
417 $this->indent_chars = '';
419 $prop_arr = $this->to_array($selector);
420 $out = $this->_style2string($prop_arr, TRUE);
422 $this->indent_chars = $indent_str;
425 // compose css code for complete data grid
429 $css_data = $this->to_array();
431 foreach ($css_data as $key => $prop_arr)
432 $out .= sprintf("%s {\n%s}\n\n",
434 $this->_style2string($prop_arr, TRUE));
441 // return a single-line string of a css definition
442 function to_inline($selector)
444 if ($this->css_data[$selector])
445 return str_replace('"', '\\"', $this->_style2string($this->css_data[$selector], FALSE));
449 // return an associative array with selector(s) as key and styles array as value
450 function to_array($selector=NULL)
452 if (!$selector && $this->grouped_output)
454 // build groups if desired
455 if (!sizeof($this->css_groups))
456 $this->_build_groups();
458 // modify group array to get an array(selector => properties)
460 foreach ($this->css_groups as $group_arr)
462 $key = join(', ', $group_arr['selectors']);
463 $out_arr[$key] = $group_arr['properties'];
467 $out_arr = $this->css_data;
469 return $selector ? $out_arr[$selector] : $out_arr;
474 function to_file($filepath)
476 if ($fp = fopen($filepath, 'w'))
478 fwrite($fp, $this->to_string());
487 // alias method for import_string() [DEPRECATED]
490 $this->import_string($str);
493 // alias method for to_string() [DEPRECATED]
496 return $this->to_string();
501 // ******** private methods ********
504 // parse a string and add styles to internal data grid
505 function _parse($str)
508 $str = preg_replace("/\/\*(.*)?\*\//Usi", '', $str);
510 // parse style definitions
511 if (!preg_match_all ('/([a-z0-9\.#*:_][a-z0-9\.\-_#:*,\[\]\(\)\s\"\'\+\|>~=]+)\s*\{([^\}]*)\}/ims', $str, $matches, PREG_SET_ORDER))
515 foreach ($matches as $match_arr)
517 // split selectors into array
518 $a_keys = $this->_parse_selectors(trim($match_arr[1]));
520 // parse each property of an element
521 $codes = explode(";", trim($match_arr[2]));
522 foreach ($codes as $code)
524 if (strlen(trim($code))>0)
526 // find the property and the value
527 if (!($sep = strpos($code, ':')))
530 $property = strtolower(trim(substr($code, 0, $sep)));
531 $value = trim(substr($code, $sep+1));
533 // add the property to the object array
534 foreach ($a_keys as $key)
535 $this->css_data[$key][$property] = $value;
541 if (sizeof($matches))
543 $this->css_groups = array();
551 // split selector group
552 function _parse_selectors($selector)
554 // trim selector and remove multiple spaces
555 $selector = preg_replace('/\s+/', ' ', trim($selector));
557 if (strpos($selector, ','))
558 return preg_split('/[\t\s\n\r]*,[\t\s\n\r]*/mi', $selector);
560 return array($selector);
564 // compare identical styles and make groups
565 function _build_groups()
568 $this->css_groups = array();
569 $string_group_map = array();
571 // bulild css string for each selector and check if the same is already defines
572 foreach ($this->css_data as $selector => $prop_arr)
574 // make shure to compare props in the same order
576 $compare_str = preg_replace('/[\s\t]+/', '', $this->_style2string($prop_arr, FALSE));
578 // add selector to extisting group
579 if (isset($string_group_map[$compare_str]))
581 $group_index = $string_group_map[$compare_str];
582 $this->css_groups[$group_index]['selectors'][] = $selector;
588 $i = sizeof($this->css_groups);
589 $string_group_map[$compare_str] = $i;
590 $this->css_groups[$i] = array('selectors' => array($selector),
591 'properties' => $this->css_data[$selector]);
597 // convert the prop array into a valid css definition
598 function _style2string($prop_arr, $multiline=TRUE)
601 $delm = $multiline ? "\n" : '';
602 $spacer = $multiline ? ' ' : '';
603 $indent = $multiline ? $this->indent_chars : '';
605 if (is_array($prop_arr))
606 foreach ($prop_arr as $prop => $value)
608 $out .= sprintf('%s%s:%s%s;%s',
619 // copy all properties inherited from superior styles to a specific selector
620 function _get_inherited_styles($selector, $loop=FALSE)
622 $css_props = $this->css_data[$selector] ? $this->css_data[$selector] : array();
624 // get styles from tag selector
625 if (preg_match('/(([a-z0-9]*)(\.[^\s]+)?)$/i', $selector, $regs))
631 if ($sel && is_array($this->css_data[$sel]))
632 $css_props = $this->_merge_styles($this->css_data[$sel], $css_props);
634 if ($class && is_array($this->css_data[$class]))
635 $css_props = $this->_merge_styles($this->css_data[$class], $css_props);
637 if ($tagname && is_array($this->css_data[$tagname]))
638 $css_props = $this->_merge_styles($this->css_data[$tagname], $css_props);
641 // analyse inheritance
642 if (strpos($selector, ' '))
644 $a_hier = split(' ', $selector);
645 if (sizeof($a_hier)>1)
648 $base_selector = join(' ', $a_hier);
650 // call this method recursively
651 $new_props = $this->_get_inherited_styles($base_selector, TRUE);
652 $css_props = $this->_merge_styles($new_props, $css_props);
657 if (!$loop && is_array($this->css_data['body']))
658 $css_props = $this->_merge_styles($this->css_data['body'], $css_props);
664 // merge two arrays with style properties together like a browser would do
665 function _merge_styles($one, $two)
667 // these properties are additive
668 foreach (array('text-decoration') as $prop)
669 if ($one[$prop] && $two[$prop])
671 // if value contains 'none' it's ignored
672 if (strstr($one[$prop], 'none'))
674 else if (strstr($two[$prop], 'none'))
677 $a_values_one = split(' ', $one[$prop]);
678 $a_values_two = split(' ', $two[$prop]);
679 $two[$prop] = join(' ', array_unique(array_merge($a_values_one, $a_values_two)));
682 return array_merge($one, $two);
687 function _get_file_path($file)
689 if (!$this->base_path && $GLOBALS['CSS_PATH'])
690 $this->set_basepath($GLOBALS['CSS_PATH']);
692 $base = ($file{0}=='/' || $file{0}=='.' || substr($file, 0, 7)=='http://') ? '' :
693 ($this->base_path ? $this->base_path.'/' : '');
701 class base_form_element
703 var $uppertags = FALSE;
704 var $upperattribs = FALSE;
705 var $upperprops = FALSE;
706 var $newline = FALSE;
708 var $attrib = array();
711 // create string with attributes
712 function create_attrib_string($tagname='')
714 if (!sizeof($this->attrib))
718 $this->attrib['name'] = $this->name;
720 $attrib_arr = array();
721 foreach ($this->attrib as $key => $value)
723 // don't output some internally used attributes
724 if (in_array($key, array('form', 'quicksearch')))
727 // skip if size if not numeric
728 if (($key=='size' && !is_numeric($value)))
731 // skip empty eventhandlers
732 if ((strpos($key,'on')===0 && $value==''))
735 // encode textarea content
737 $value = Q($value, 'strict', FALSE);
739 // attributes with no value
740 if (in_array($key, array('checked', 'multiple', 'disabled', 'selected')))
743 $attrib_arr[] = $key;
745 // don't convert size of value attribute
746 else if ($key=='value')
747 $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $value, 'value');
749 // regular tag attributes
751 $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case($value, 'value'));
754 return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
758 // convert tags and attributes to upper-/lowercase
759 // $type can either be "tag" or "attrib"
760 function _conv_case($str, $type='attrib')
763 return $this->uppertags ? strtoupper($str) : strtolower($str);
764 else if ($type == 'attrib')
765 return $this->upperattribs ? strtoupper($str) : strtolower($str);
766 else if ($type == 'value')
767 return $this->upperprops ? strtoupper($str) : strtolower($str);
772 class input_field extends base_form_element
777 function __construct($attrib=NULL)
779 if (is_array($attrib))
780 $this->attrib = $attrib;
783 $this->type = $attrib['type'];
785 if ($attrib['newline'])
786 $this->newline = TRUE;
789 // PHP 4 compatibility
790 function input_field($attrib=array())
792 $this->__construct($attrib);
796 function show($value=NULL, $attrib=NULL)
798 // overwrite object attributes
799 if (is_array($attrib))
800 $this->attrib = array_merge($this->attrib, $attrib);
802 // set value attribute
804 $this->attrib['value'] = $value;
806 $this->attrib['type'] = $this->type;
809 return sprintf('<%s%s />%s',
810 $this->_conv_case('input', 'tag'),
811 $this->create_attrib_string(),
812 ($this->newline ? "\n" : ""));
817 class textfield extends input_field
822 class passwordfield extends input_field
824 var $type = 'password';
827 class radiobutton extends input_field
832 class checkbox extends input_field
834 var $type = 'checkbox';
837 function show($value='', $attrib=NULL)
839 // overwrite object attributes
840 if (is_array($attrib))
841 $this->attrib = array_merge($this->attrib, $attrib);
843 $this->attrib['type'] = $this->type;
845 if ($value && (string)$value==(string)$this->attrib['value'])
846 $this->attrib['checked'] = TRUE;
848 $this->attrib['checked'] = FALSE;
851 return sprintf('<%s%s />%s',
852 $this->_conv_case('input', 'tag'),
853 $this->create_attrib_string(),
854 ($this->newline ? "\n" : ""));
859 class textarea extends base_form_element
862 function __construct($attrib=array())
864 $this->attrib = $attrib;
866 if ($attrib['newline'])
867 $this->newline = TRUE;
870 // PHP 4 compatibility
871 function textarea($attrib=array())
873 $this->__construct($attrib);
876 function show($value='', $attrib=NULL)
878 // overwrite object attributes
879 if (is_array($attrib))
880 $this->attrib = array_merge($this->attrib, $attrib);
882 // take value attribute as content
884 $value = $this->attrib['value'];
886 // make shure we don't print the value attribute
887 if (isset($this->attrib['value']))
888 unset($this->attrib['value']);
890 if (!empty($value) && !isset($this->attrib['mce_editable']))
891 $value = Q($value, 'strict', FALSE);
894 return sprintf('<%s%s>%s</%s>%s',
895 $this->_conv_case('textarea', 'tag'),
896 $this->create_attrib_string(),
898 $this->_conv_case('textarea', 'tag'),
899 ($this->newline ? "\n" : ""));
904 class hiddenfield extends base_form_element
906 var $fields_arr = array();
910 function __construct($attrib=NULL)
912 if (is_array($attrib))
916 // PHP 4 compatibility
917 function hiddenfield($attrib=NULL)
919 $this->__construct($attrib);
922 // add a hidden field to this instance
923 function add($attrib)
925 $this->fields_arr[] = $attrib;
932 foreach ($this->fields_arr as $attrib)
934 $this->attrib = $attrib;
935 $this->attrib['type'] = 'hidden';
937 $out .= sprintf('<%s%s />%s',
938 $this->_conv_case('input', 'tag'),
939 $this->create_attrib_string(),
940 ($this->newline ? "\n" : ""));
948 class select extends base_form_element
950 var $options = array();
955 // create instance. arguments are used to set attributes of select-tag
956 $select = new select(array('name' => 'fieldname'));
959 $select->add('Switzerland', 'CH');
961 // add multiple options
962 $select->add(array('Switzerland', 'Germany'),
965 // add 10 blank options with 50 chars
966 // used to fill with javascript (necessary for 4.x browsers)
967 $select->add_blank(10, 50);
969 // generate pulldown with selection 'Switzerland' and return html-code
970 // as second argument the same attributes available to instanciate can be used
971 print $select->show('CH');
975 function __construct($attrib=NULL)
977 if (is_array($attrib))
978 $this->attrib = $attrib;
980 if ($attrib['newline'])
981 $this->newline = TRUE;
984 // PHP 4 compatibility
985 function select($attrib=NULL)
987 $this->__construct($attrib);
991 function add($names, $values=NULL)
993 if (is_array($names))
995 foreach ($names as $i => $text)
996 $this->options[] = array('text' => $text, 'value' => (string)$values[$i]);
1000 $this->options[] = array('text' => $names, 'value' => (string)$values);
1005 function add_blank($nr, $width=0)
1007 $text = $width ? str_repeat(' ', $width) : '';
1009 for ($i=0; $i < $nr; $i++)
1010 $this->options[] = array('text' => $text);
1014 function show($select=array(), $attrib=NULL)
1016 $options_str = "\n";
1017 $value_str = $this->_conv_case(' value="%s"', 'attrib');
1019 if (!is_array($select))
1020 $select = array((string)$select);
1022 foreach ($this->options as $option)
1024 $selected = ((isset($option['value']) &&
1025 in_array($option['value'], $select, TRUE)) ||
1026 (in_array($option['text'], $select, TRUE))) ?
1027 $this->_conv_case(' selected', 'attrib') : '';
1029 $options_str .= sprintf("<%s%s%s>%s</%s>\n",
1030 $this->_conv_case('option', 'tag'),
1031 !empty($option['value']) ? sprintf($value_str, Q($option['value'])) : '',
1033 Q($option['text'], 'strict', FALSE),
1034 $this->_conv_case('option', 'tag'));
1038 return sprintf('<%s%s>%s</%s>%s',
1039 $this->_conv_case('select', 'tag'),
1040 $this->create_attrib_string(),
1042 $this->_conv_case('select', 'tag'),
1043 ($this->newline ? "\n" : ""));
1050 // ********* rcube schared functions *********
1053 // provide details about the client's browser
1054 function rcube_browser()
1056 $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
1059 $bw['win'] = stristr($HTTP_USER_AGENT, 'win');
1060 $bw['mac'] = stristr($HTTP_USER_AGENT, 'mac');
1061 $bw['linux'] = stristr($HTTP_USER_AGENT, 'linux');
1062 $bw['unix'] = stristr($HTTP_USER_AGENT, 'unix');
1064 $bw['ns4'] = stristr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie');
1065 $bw['ns'] = ($bw['ns4'] || stristr($HTTP_USER_AGENT, 'netscape'));
1066 $bw['ie'] = stristr($HTTP_USER_AGENT, 'msie');
1067 $bw['mz'] = stristr($HTTP_USER_AGENT, 'mozilla/5');
1068 $bw['opera'] = stristr($HTTP_USER_AGENT, 'opera');
1069 $bw['safari'] = stristr($HTTP_USER_AGENT, 'safari');
1073 $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1074 $bw['ver'] = $test ? (float)$regs[1] : 0;
1078 $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1079 $bw['ver'] = $test ? (float)$regs[1] : 0;
1083 $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1084 $bw['ver'] = $test ? (float)$regs[1] : 0;
1088 $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs);
1089 $bw['ver'] = $test ? (float)$regs[1] : 0;
1092 if(eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs))
1093 $bw['lang'] = $regs[1];
1097 $bw['dom'] = ($bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5) || ($bw['opera'] && $bw['ver']>=7));
1098 $bw['pngalpha'] = $bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5.5) ||
1099 ($bw['ie'] && $bw['ver']>=5 && $bw['mac']) || ($bw['opera'] && $bw['ver']>=7) ? TRUE : FALSE;
1105 // get text in the desired language from the language file
1106 function rcube_label($attrib)
1108 global $sess_user_lang, $INSTALL_PATH, $OUTPUT;
1109 static $sa_text_data, $s_language, $utf8_decode;
1111 // extract attributes
1112 if (is_string($attrib))
1113 $attrib = array('name' => $attrib);
1115 $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1;
1116 $vars = isset($attrib['vars']) ? $attrib['vars'] : '';
1118 $command_name = !empty($attrib['command']) ? $attrib['command'] : NULL;
1119 $alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : '');
1122 // load localized texts
1123 if (!$sa_text_data || $s_language != $sess_user_lang)
1125 $sa_text_data = array();
1127 // get english labels (these should be complete)
1128 @include($INSTALL_PATH.'program/localization/en_US/labels.inc');
1129 @include($INSTALL_PATH.'program/localization/en_US/messages.inc');
1131 if (is_array($labels))
1132 $sa_text_data = $labels;
1133 if (is_array($messages))
1134 $sa_text_data = array_merge($sa_text_data, $messages);
1136 // include user language files
1137 if ($sess_user_lang!='en' && is_dir($INSTALL_PATH.'program/localization/'.$sess_user_lang))
1139 include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/labels.inc');
1140 include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/messages.inc');
1142 if (is_array($labels))
1143 $sa_text_data = array_merge($sa_text_data, $labels);
1144 if (is_array($messages))
1145 $sa_text_data = array_merge($sa_text_data, $messages);
1148 $s_language = $sess_user_lang;
1151 // text does not exist
1152 if (!($text_item = $sa_text_data[$alias]))
1155 raise_error(array('code' => 500,
1159 'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE);
1164 // make text item array
1165 $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item);
1167 // decide which text to use
1169 $text = $a_text_item['single'];
1171 $text = $a_text_item['multiple'];
1174 if ($a_text_item['none'])
1175 $text = $a_text_item['none'];
1176 else if ($a_text_item['single'])
1177 $text = $a_text_item['single'];
1178 else if ($a_text_item['multiple'])
1179 $text = $a_text_item['multiple'];
1182 // default text is single
1184 $text = $a_text_item['single'];
1186 // replace vars in text
1187 if (is_array($attrib['vars']))
1189 foreach ($attrib['vars'] as $var_key=>$var_value)
1190 $a_replace_vars[substr($var_key, 0, 1)=='$' ? substr($var_key, 1) : $var_key] = $var_value;
1193 if ($a_replace_vars)
1194 $text = preg_replace('/\${?([_a-z]{1}[_a-z0-9]*)}?/ei', '$a_replace_vars["\1"]', $text);
1196 // remove variables in text which were not available in arg $vars and $nr
1197 eval("\$text = <<<EOF
1203 if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])
1204 return ucfirst($text);
1205 else if ($attrib['uppercase'])
1206 return strtoupper($text);
1207 else if ($attrib['lowercase'])
1208 return strtolower($text);
1214 // send HTTP header for no-cacheing steps
1215 function send_nocacheing_headers()
1220 header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
1221 header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
1222 header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
1223 header("Pragma: no-cache");
1227 // send header with expire date 30 days in future
1228 function send_future_expire_header($offset=2600000)
1233 header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+$offset)." GMT");
1234 header("Cache-Control: max-age=$offset");
1239 // check request for If-Modified-Since and send an according response
1240 function send_modified_header($mdate, $etag=null)
1246 if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $mdate)
1249 $etag = $etag ? "\"$etag\"" : null;
1250 if ($etag && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag)
1254 header("HTTP/1.x 304 Not Modified");
1256 header("Last-Modified: ".gmdate("D, d M Y H:i:s", $mdate)." GMT");
1258 header("Cache-Control: max-age=0");
1259 header("Expires: ");
1263 header("Etag: $etag");
1271 * Convert a variable into a javascript notation string
1273 function json_serialize($var)
1275 if (is_object($var))
1276 $var = get_object_vars($var);
1285 $keys_arr = array_keys($var);
1286 $is_assoc = $have_numeric = 0;
1288 for ($i=0; $i<sizeof($keys_arr); ++$i)
1290 if (is_numeric($keys_arr[$i]))
1292 if (!is_numeric($keys_arr[$i]) || $keys_arr[$i] != $i)
1294 if ($is_assoc && $have_numeric)
1298 $brackets = $is_assoc ? '{}' : '[]';
1301 foreach ($var as $key => $value)
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) */)
1307 $pairs[] = sprintf("%s%s", $is_assoc ? "$key:" : '', json_serialize($value));
1310 return $brackets{0} . implode(',', $pairs) . $brackets{1};
1313 else if (is_numeric($var) && strval(intval($var)) === strval($var))
1315 else if (is_bool($var))
1316 return $var ? '1' : '0';
1318 return "'".JQ($var)."'";
1323 * function to convert an array to a javascript array
1326 function array2js($arr, $type='')
1328 return json_serialize($arr);
1333 * Similar function as in_array() but case-insensitive
1335 function in_array_nocase($needle, $haystack)
1337 foreach ($haystack as $value)
1339 if (strtolower($needle)===strtolower($value))
1348 * Find out if the string content means TRUE or FALSE
1350 function get_boolean($str)
1352 $str = strtolower($str);
1353 if(in_array($str, array('false', '0', 'no', 'nein', ''), TRUE))
1360 // parse a human readable string for a number of bytes
1361 function parse_bytes($str)
1363 if (is_numeric($str))
1364 return intval($str);
1366 if (preg_match('/([0-9]+)([a-z])/i', $str, $regs))
1368 $bytes = floatval($regs[1]);
1369 switch (strtolower($regs[2]))
1372 $bytes *= 1073741824;
1383 return intval($bytes);
1386 // create a human readable string for a number of bytes
1387 function show_bytes($bytes)
1389 if ($bytes > 1073741824)
1391 $gb = $bytes/1073741824;
1392 $str = sprintf($gb>=10 ? "%d GB" : "%.1f GB", $gb);
1394 else if ($bytes > 1048576)
1396 $mb = $bytes/1048576;
1397 $str = sprintf($mb>=10 ? "%d MB" : "%.1f MB", $mb);
1399 else if ($bytes > 1024)
1400 $str = sprintf("%d KB", round($bytes/1024));
1402 $str = sprintf('%d B', $bytes);
1408 // convert paths like ../xxx to an absolute path using a base url
1409 function make_absolute_url($path, $base_url)
1411 $host_url = $base_url;
1414 // cut base_url to the last directory
1415 if (strpos($base_url, '/')>7)
1417 $host_url = substr($base_url, 0, strpos($base_url, '/'));
1418 $base_url = substr($base_url, 0, strrpos($base_url, '/'));
1421 // $path is absolute
1423 $abs_path = $host_url.$path;
1426 // strip './' because its the same as ''
1427 $path = preg_replace('/^\.\//', '', $path);
1429 if(preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER))
1430 foreach($matches as $a_match)
1432 if (strrpos($base_url, '/'))
1433 $base_url = substr($base_url, 0, strrpos($base_url, '/'));
1435 $path = substr($path, 3);
1438 $abs_path = $base_url.'/'.$path;
1445 // wrapper function for strlen
1446 function rc_strlen($str)
1448 if (function_exists('mb_strlen'))
1449 return mb_strlen($str);
1451 return strlen($str);
1454 // wrapper function for strtolower
1455 function rc_strtolower($str)
1457 if (function_exists('mb_strtolower'))
1458 return mb_strtolower($str);
1460 return strtolower($str);
1463 // wrapper function for substr
1464 function rc_substr($str, $start, $len=null)
1466 if (function_exists('mb_substr'))
1467 return mb_substr($str, $start, $len);
1469 return substr($str, $start, $len);
1472 // wrapper function for strpos
1473 function rc_strpos($haystack, $needle, $offset=0)
1475 if (function_exists('mb_strpos'))
1476 return mb_strpos($haystack, $needle, $offset);
1478 return strpos($haystack, $needle, $offset);
1481 // wrapper function for strrpos
1482 function rc_strrpos($haystack, $needle, $offset=0)
1484 if (function_exists('mb_strrpos'))
1485 return mb_strrpos($haystack, $needle, $offset);
1487 return strrpos($haystack, $needle, $offset);
1491 // replace the middle part of a string with ...
1492 // if it is longer than the allowed length
1493 function abbrevate_string($str, $maxlength, $place_holder='...')
1495 $length = rc_strlen($str);
1496 $first_part_length = floor($maxlength/2) - rc_strlen($place_holder);
1498 if ($length > $maxlength)
1500 $second_starting_location = $length - $maxlength + $first_part_length + 1;
1501 $str = rc_substr($str, 0, $first_part_length) . $place_holder . rc_substr($str, $second_starting_location, $length);
1508 // make sure the string ends with a slash
1509 function slashify($str)
1511 return unslashify($str).'/';
1515 // remove slash at the end of the string
1516 function unslashify($str)
1518 return preg_replace('/\/$/', '', $str);
1522 // delete all files within a folder
1523 function clear_directory($dir_path)
1525 $dir = @opendir($dir_path);
1526 if(!$dir) return FALSE;
1528 while ($file = readdir($dir))
1529 if (strlen($file)>2)
1530 unlink("$dir_path/$file");
1537 // create a unix timestamp with a specified offset from now
1538 function get_offset_time($offset_str, $factor=1)
1540 if (preg_match('/^([0-9]+)\s*([smhdw])/i', $offset_str, $regs))
1542 $amount = (int)$regs[1];
1543 $unit = strtolower($regs[2]);
1547 $amount = (int)$offset_str;
1563 $ts += $amount * $factor;
1573 * return the last occurence of a string in another string
1574 * @param haystack string string in which to search
1575 * @param needle string string for which to search
1576 * @return index of needle within haystack, or false if not found
1578 function strrstr($haystack, $needle)
1580 $pver = phpversion();
1583 return strrpos($haystack, $needle);
1587 $index = strpos(strrev($haystack), strrev($needle));
1588 if($index === false) {
1591 $index = strlen($haystack) - strlen($needle) - $index;