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.
11 // | There are only two ways to violate the license:
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).
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).
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
24 // +----------------------------------------------------------------------+
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
29 // import() function loads a class.
30 function import($class_name) {
32 dirname($_SERVER["SCRIPT_FILENAME"]),
36 $pos = strpos($class_name, ".");
37 if (!($pos === false)) {
38 $peaces = explode(".", $class_name);
40 for ($i=0; $i<count($peaces)-1; $i++) {
41 $p = $p . "/" . $peaces[$i];
43 $libs = array_merge(array(LIBRARY_DIR . $p),$libs);
44 $class_name = $peaces[count($peaces)-1];
47 $filename = $class_name . '.class.php';
49 foreach($libs as $lib) {
50 $inc_filename = $lib . '/' . $filename;
51 if (file_exists($inc_filename)) {
52 require_once($inc_filename);
57 print '<br><b>load_class: error loading file "'.$filename.'"</b>';
61 // The mu_sort function is used to sort a multi-dimensional array.
62 // It looks like the code example is taken from the PHP manual http://ca2.php.net/manual/en/function.sort.php
63 function mu_sort($array, $key_sort) {
65 if (!is_array($array) || count($array)==0)
68 $key_sorta = explode(",", $key_sort);
69 $keys = array_keys($array[0]);
71 for($m=0; $m < count($key_sorta); $m++) {
72 $nkeys[$m] = trim($key_sorta[$m]);
74 $n += count($key_sorta);
76 for($i=0; $i < count($keys); $i++) {
77 if(!in_array($keys[$i], $key_sorta)) {
78 $nkeys[$n] = $keys[$i];
83 for($u=0;$u<count($array); $u++) {
85 for($s=0; $s<count($nkeys); $s++) {
87 $output[$u][$k] = $array[$u][$k];
97 * @param unknown $value
100 function toFloat($value) {
101 if (isset($value) && (strlen($value) > 0)) {
102 $value = str_replace(",",".",$value);
103 return floatval($value);
108 function stripslashes_deep($value) {
109 $value = is_array($value) ?
110 array_map('stripslashes_deep', $value) :
111 stripslashes($value);
115 function &getConnection() {
116 if (!isset($GLOBALS["_MDB2_CONNECTION"])) {
118 require_once('MDB2.php');
120 $mdb2 = MDB2::connect(DSN);
121 if (is_a($mdb2, 'PEAR_Error')) {
122 die($mdb2->getMessage());
125 $mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
127 $GLOBALS["_MDB2_CONNECTION"] = $mdb2;
129 return $GLOBALS["_MDB2_CONNECTION"];
133 // time_to_decimal converts a time string such as 1:15 to its decimal representation such as 1.25 or 1,25.
134 function time_to_decimal($val) {
136 $parts = explode(':', $val); // parts[0] is hours, parts[1] is minutes.
138 $minutePercent = round($parts[1]*100/60); // Integer value (0-98) of percent of minutes portion in the hour.
139 if($minutePercent < 10) $minutePercent = '0'.$minutePercent; // Pad small values with a 0 to always have 2 digits.
141 $decimalTime = $parts[0].$user->decimal_mark.$minutePercent; // Construct decimal representation of time value.
146 function sec_to_time_fmt_hm($sec)
148 return sprintf("%d:%02d", $sec / 3600, $sec % 3600 / 60);
151 function magic_quotes_off()
153 $_POST = array_map('stripslashes_deep', $_POST);
154 $_GET = array_map('stripslashes_deep', $_GET);
155 $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
158 // check_extension checks whether a required PHP extension is loaded and dies if not so.
159 function check_extension($ext)
161 if (!extension_loaded($ext))
162 die("PHP extension '{$ext}' is required but is not loaded. Read Time Tracker Install Guide for help.");
165 // isTrue is a helper function to return correct false for older config.php values defined as a string 'false'.
166 function isTrue($val)
168 return ($val == false || $val === 'false') ? false : true;
171 // ttValidString is used to check user input to validate a string.
172 function ttValidString($val, $emptyValid = false)
175 if (strlen($val) == 0 && !$emptyValid)
178 // String must not be XSS evil (to insert JavaScript).
179 if (stristr($val, '<script>') || stristr($val, '<script '))
185 // ttValidEmail is used to check user input to validate an email string.
186 function ttValidEmail($val, $emptyValid = false)
189 if (strlen($val) == 0)
190 return ($emptyValid ? true : false);
192 // String must not be XSS evil (to insert JavaScript).
193 if (stristr($val, '<script>') || stristr($val, '<script '))
196 // Validate a single email address. TODO: improve for compliancy with RFC.
197 if (!preg_match("/^[_a-zA-Z\d\'-\.]+@([_a-zA-Z\d\-]+(\.[_a-zA-Z\d\-]+)+)$/", $val))
203 // ttValidEmailList is used to check user input to validate an email string.
204 function ttValidEmailList($val, $emptyValid = false)
207 if (strlen($val) == 0)
208 return ($emptyValid ? true : false);
210 // String must not be XSS evil (to insert JavaScript).
211 if (stristr($val, '<script>') || stristr($val, '<script '))
214 // Validates a list of email addresses separated by a comma with optional spaces.
215 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))
221 // ttValidFloat is used to check user input to validate a float value.
222 function ttValidFloat($val, $emptyValid = false)
225 if (strlen($val) == 0)
226 return ($emptyValid ? true : false);
229 $decimal = $user->decimal_mark;
231 if (!preg_match('/^-?[0-9'.$decimal.']+$/', $val))
237 // ttValidDate is used to check user input to validate a date.
238 function ttValidDate($val)
241 if (strlen($val) == 0)
244 // This should accept a string in format 'YYYY-MM-DD', 'MM/DD/YYYY', 'DD.MM.YYYY', or 'DD.MM.YYYY whatever'.
245 if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $val) &&
246 !preg_match('/^\d\d\/\d\d\/\d\d\d\d$/', $val) &&
247 !preg_match('/^\d\d\.\d\d\.\d\d\d\d$/', $val) &&
248 !preg_match('/^\d\d\.\d\d\.\d\d\d\d .+$/', $val))
254 // ttValidInteger is used to check user input to validate an integer.
255 function ttValidInteger($val, $emptyValid = false)
258 if (strlen($val) == 0)
259 return ($emptyValid ? true : false);
261 if (!preg_match('/^[0-9]+$/', $val))
267 // ttValidCronSpec is used to check user input to validate cron specification.
268 function ttValidCronSpec($val)
270 // This code is adapted from http://stackoverflow.com/questions/235504/validating-crontab-entries-w-php
273 'hour'=>'[01]?\d|2[0-3]',
274 'day'=>'0?[1-9]|[12]\d|3[01]',
275 'month'=>'[1-9]|1[012]',
279 foreach($numbers as $field=>$number) {
280 $range= "($number)(-($number)(\/\d+)?)?";
281 $field_re[$field]= "\*(\/\d+)?|$range(,$range)*";
284 $field_re['month'].='|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec';
285 $field_re['dow'].='|mon|tue|wed|thu|fri|sat|sun';
287 $fields_re= '('.join(')\s+(', $field_re).')';
290 $replacements= '@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly';
297 "|($replacements)\s+\S".
300 // The above block from the link did not work for me.
303 $regexp = '/^'.$fields_re.'$/';
305 if (!preg_match($regexp, $val))
311 // ttValidCondition is used to check user input to validate a notification condition.
312 function ttValidCondition($val, $emptyValid = true)
315 if (strlen($val) == 0)
316 return ($emptyValid ? true : false);
318 // String must not be XSS evil (to insert JavaScript).
319 if (stristr($val, '<script>') || stristr($val, '<script '))
322 if (!preg_match("/^count\s?>\s?\d+$/", $val))
328 // ttValidIP is used to check user input to validate a comma-separated
329 // list of IP subnet "prefixes", for example 192.168.0 (note: no .* in the end).
330 // We keep regexp checks here simple - they are not precise.
331 // For example, IPv4-mapped IPv6 addresses will fail. This may need to be fixed.
332 function ttValidIP($val, $emptyValid = false)
335 if (strlen($val) == 0 && $emptyValid)
338 $subnets = explode(',', $val);
339 foreach ($subnets as $subnet) {
340 $ipv4 = preg_match('/^\d\d?\d?(\.\d\d?\d?){0,3}\.?$/', $subnet); // Not precise check.
341 $ipv6 = preg_match('/^([0-9a-fA-F]{4})(:[0-9a-fA-F]{4}){0,7}$/', $subnet); // Not precise check.
342 if (!$ipv4 && !$ipv6)
348 // ttAccessAllowed checks whether user is allowed access to a particular page.
349 // It is used as an initial check on all publicly available pages
350 // (except login.php, register.php, and others where we don't have to check).
351 function ttAccessAllowed($required_right)
356 // Redirect to login page if user is not authenticated.
357 if (!$auth->isAuthenticated()) {
358 header('Location: login.php');
362 // Check IP restriction, if set.
363 if ($user->allow_ip && !$user->can('override_allow_ip')) {
364 $access_allowed = false;
365 $user_ip = $_SERVER['REMOTE_ADDR'];
366 $allowed_ip_array = explode(',', $user->allow_ip);
367 foreach ($allowed_ip_array as $allowed_ip) {
368 $len = strlen($allowed_ip);
369 if (substr($user_ip, 0, $len) === $allowed_ip) { // startsWith check.
370 $access_allowed = true;
374 if (!$access_allowed) return false;
377 // Check if user has the right.
378 if (in_array($required_right, $user->rights)) {
379 import('ttUserHelper');
380 ttUserHelper::updateLastAccess();