Fix report exports to honor user decimal mark designation.
[timetracker.git] / WEB-INF / lib / common.lib.php
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Anuko Time Tracker
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) Anuko International Ltd. (https://www.anuko.com)
6 // +----------------------------------------------------------------------+
7 // | LIBERAL FREEWARE LICENSE: This source code document may be used
8 // | by anyone for any purpose, and freely redistributed alone or in
9 // | combination with other software, provided that the license is obeyed.
10 // |
11 // | There are only two ways to violate the license:
12 // |
13 // | 1. To redistribute this code in source form, with the copyright
14 // |    notice or license removed or altered. (Distributing in compiled
15 // |    forms without embedded copyright notices is permitted).
16 // |
17 // | 2. To redistribute modified versions of this code in *any* form
18 // |    that bears insufficient indications that the modifications are
19 // |    not the work of the original author(s).
20 // |
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
23 // |
24 // +----------------------------------------------------------------------+
25 // | Contributors:
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
28
29         /**
30          * @return unknown
31          * @param file unknown
32          * @param version = "" unknown
33          * @desc Loads a class
34          */
35         function import( $class_name ) {
36             $libs = array(
37                         dirname($_SERVER["SCRIPT_FILENAME"]),
38                         LIBRARY_DIR
39                 );
40
41             $pos = strpos($class_name, ".");
42         if (!($pos === false)) {
43             $peaces = explode(".", $class_name);
44             $p = "";
45             for ($i=0; $i<count($peaces)-1; $i++) {
46                 $p = $p . "/" . $peaces[$i];
47             }
48                         $libs = array_merge(array(LIBRARY_DIR . $p),$libs);
49             $class_name = $peaces[count($peaces)-1];
50         }
51
52                 $filename = $class_name . '.class.php';
53
54                 foreach($libs as $lib) {
55                         $inc_filename = $lib . '/' . $filename;
56                         if (file_exists($inc_filename)) {
57                                         require_once($inc_filename);
58                                         return $class_name;
59                         }
60                 }
61
62                 print '<br><b>load_class: error loading file "'.$filename.'"</b>';
63                 die();
64         }
65
66         // The mu_sort function is used to sort a multi-dimensional array.
67         // It looks like the code example is taken from the PHP manual http://ca2.php.net/manual/en/function.sort.php
68         function mu_sort($array, $key_sort) {
69                 $n = 0;
70                 if (!is_array($array) || count($array)==0)
71                         return array();
72
73                 $key_sorta = explode(",", $key_sort);
74                 $keys = array_keys($array[0]);
75
76                 for($m=0; $m < count($key_sorta); $m++) {
77                         $nkeys[$m] = trim($key_sorta[$m]);
78                 }
79                 $n += count($key_sorta);
80
81                 for($i=0; $i < count($keys); $i++) {
82                         if(!in_array($keys[$i], $key_sorta)) {
83                                 $nkeys[$n] = $keys[$i];
84                                 $n += "1";
85                         }
86                 }
87
88                 for($u=0;$u<count($array); $u++) {
89                         $arr = $array[$u];
90                         for($s=0; $s<count($nkeys); $s++) {
91                                 $k = $nkeys[$s];
92                                 $output[$u][$k] = $array[$u][$k];
93                         }
94                 }
95                 sort($output);
96                 return $output;
97         }
98
99         /**
100          * return float type
101          *
102          * @param unknown $value
103          * @return unknown
104          */
105         function toFloat($value) {
106                 if (isset($value) && (strlen($value) > 0)) {
107                         $value = str_replace(",",".",$value);
108                         return floatval($value);
109                 }
110                 return null;
111         }
112
113         function stripslashes_deep($value) {
114             $value = is_array($value) ?
115                 array_map('stripslashes_deep', $value) :
116                 stripslashes($value);
117         return $value;
118         }
119
120         function &getConnection() {
121         if (!isset($GLOBALS["_MDB2_CONNECTION"])) {
122
123                 require_once('MDB2.php');
124
125                 $mdb2 = MDB2::connect(DSN);
126                         if (is_a($mdb2, 'PEAR_Error')) {
127                         die($mdb2->getMessage());
128                         }
129
130                         $mdb2->setOption('debug', true);
131                         $mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
132                         
133                         $GLOBALS["_MDB2_CONNECTION"] = $mdb2;
134         }
135         return $GLOBALS["_MDB2_CONNECTION"];
136         }
137
138
139         function closeConnection() {
140                 if (isset($GLOBALS["_DB_CONNECTION"])) {
141                         $GLOBALS["_DB_CONNECTION"]->close();
142                         unset($GLOBALS["_DB_CONNECTION"]);
143                 }
144         }
145
146 function time_to_decimal($a) {
147   global $user;
148   $tmp = explode(":", $a);
149   if($tmp[1]{0}=="0") $tmp[1] = $tmp[1]{1};
150
151   $m = round($tmp[1]*100/60);
152
153   if($m<10) $m = "0".$m;
154   $time = $tmp[0].$user->decimal_mark.$m;
155   return $time;
156 }
157
158 function sec_to_time_fmt_hm($sec)
159 {
160   return sprintf("%d:%02d", $sec / 3600, $sec % 3600 / 60);
161 }
162
163 function magic_quotes_off()
164 {
165   // if (get_magic_quotes_gpc()) { // This check is now done before calling this function.
166     $_POST = array_map('stripslashes_deep', $_POST);
167     $_GET = array_map('stripslashes_deep', $_GET);
168     $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
169   // }
170 }
171
172 // check_extension checks whether a required PHP extension is loaded and dies if not so.
173 function check_extension($ext)
174 {
175   if (!extension_loaded($ext))
176     die("PHP extension '{$ext}' is required but is not loaded. Read Time Tracker Install Guide for help.");
177 }
178
179 // isTrue is a helper function to return correct false for older config.php values defined as a string 'false'.
180 function isTrue($val)
181 {
182   return ($val == false || $val === 'false') ? false : true;
183 }
184
185 // ttValidString is used to check user input to validate a string.
186 function ttValidString($val, $emptyValid = false)
187 {
188   $val = trim($val);
189   if (strlen($val) == 0 && !$emptyValid)
190     return false;
191     
192   // String must not be XSS evil (to insert JavaScript).
193   if (stristr($val, '<script>') || stristr($val, '<script '))
194     return false;
195     
196   return true;    
197 }
198
199 // ttValidEmail is used to check user input to validate an email string.
200 function ttValidEmail($val, $emptyValid = false)
201 {
202   $val = trim($val);
203   if (strlen($val) == 0)
204     return ($emptyValid ? true : false);
205         
206   // String must not be XSS evil (to insert JavaScript).
207   if (stristr($val, '<script>') || stristr($val, '<script '))
208     return false;
209     
210   // Validate a single email address. TODO: improve for compliancy with RFC.
211   if (!preg_match("/^[_a-zA-Z\d\'-\.]+@([_a-zA-Z\d\-]+(\.[_a-zA-Z\d\-]+)+)$/", $val))
212     return false;
213   
214   return true;    
215 }
216
217 // ttValidEmailList is used to check user input to validate an email string.
218 function ttValidEmailList($val, $emptyValid = false)
219 {
220   $val = trim($val);
221   if (strlen($val) == 0)
222     return ($emptyValid ? true : false);
223         
224   // String must not be XSS evil (to insert JavaScript).
225   if (stristr($val, '<script>') || stristr($val, '<script '))
226     return false;
227     
228   // Validates a list of email addresses separated by a comma with optional spaces.
229   if (!preg_match("/^[_a-zA-Z\d\'-\.]+@([_a-zA-Z\d\-]+(\.[_a-zA-Z\d\-]+)+)(,\s*[_a-zA-Z\d\'-\.]+@([_a-zA-Z\d\-]+(\.[_a-zA-Z\d\-]+)+))*$/", $val))
230     return false;
231     
232   return true;
233 }
234
235 // ttValidFloat is used to check user input to validate a float value.
236 function ttValidFloat($val, $emptyValid = false)
237 {
238   $val = trim($val);
239   if (strlen($val) == 0)
240     return ($emptyValid ? true : false);
241     
242   global $user;
243   $decimal = $user->decimal_mark;
244         
245   if (!preg_match('/^-?[0-9'.$decimal.']+$/', $val))
246     return false;
247     
248   return true;    
249 }
250
251 // ttValidDate is used to check user input to validate a date.
252 function ttValidDate($val)
253 {
254   $val = trim($val);
255   if (strlen($val) == 0)
256     return false;
257
258   // This should accept a string in format 'YYYY-MM-DD', 'MM/DD/YYYY', 'DD.MM.YYYY', or 'DD.MM.YYYY whatever'.
259   if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $val) &&
260     !preg_match('/^\d\d\/\d\d\/\d\d\d\d$/', $val) &&
261     !preg_match('/^\d\d\.\d\d\.\d\d\d\d$/', $val) &&
262     !preg_match('/^\d\d\.\d\d\.\d\d\d\d .+$/', $val))
263     return false;
264     
265   return true;    
266 }
267
268 // ttValidInteger is used to check user input to validate an integer.
269 function ttValidInteger($val, $emptyValid = false)
270 {
271   $val = trim($val);
272   if (strlen($val) == 0)
273     return ($emptyValid ? true : false);
274     
275   if (!preg_match('/^[0-9]+$/', $val))
276     return false;
277
278   return true;
279 }
280
281 // ttValidCronSpec is used to check user input to validate cron specification.
282 function ttValidCronSpec($val)
283 {
284   // This code is adapted from http://stackoverflow.com/questions/235504/validating-crontab-entries-w-php
285   $numbers= array(
286      'min'=>'[0-5]?\d',
287      'hour'=>'[01]?\d|2[0-3]',
288      'day'=>'0?[1-9]|[12]\d|3[01]',
289      'month'=>'[1-9]|1[012]',
290      'dow'=>'[0-7]'
291   );
292
293   foreach($numbers as $field=>$number) {
294     $range= "($number)(-($number)(\/\d+)?)?";
295     $field_re[$field]= "\*(\/\d+)?|$range(,$range)*";
296   }
297
298   $field_re['month'].='|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec';
299   $field_re['dow'].='|mon|tue|wed|thu|fri|sat|sun';
300
301   $fields_re= '('.join(')\s+(', $field_re).')';
302
303   /*
304   $replacements= '@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly';
305
306   $regexp = '^\s*('.
307                 '$'.
308                 '|#'.
309                 '|\w+\s*='.
310                 "|$fields_re\s+\S".
311                 "|($replacements)\s+\S".
312             ')';
313    */
314   // The above block from the link did not work for me.
315
316   // But this works.
317   $regexp = '/^'.$fields_re.'$/';
318         
319   if (!preg_match($regexp, $val))
320     return false;
321
322   return true;
323 }
324
325 // ttAccessCheck is used to check whether user is allowed to proceed. This function is used
326 // as an initial check on all publicly available pages.
327 function ttAccessCheck($required_rights)
328 {
329   global $auth;
330   global $user;
331   
332   // Redirect to login page if user is not authenticated.
333   if (!$auth->isAuthenticated()) {
334     header('Location: login.php');
335     exit();
336   }
337   
338   // Check rights.
339   if (!($required_rights & $user->rights))
340     return false;
341     
342   return true;
343 }