1<?php
2// Pandora FMS - http://pandorafms.com
3// ==================================================
4// Copyright (c) 2005-2011 Artica Soluciones Tecnologicas
5// Please see http://pandorafms.org for full contribution list
6
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the  GNU Lesser General Public License
9// as published by the Free Software Foundation; version 2
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16/**
17 * @package Include
18 * @subpackage Generic_Functions
19 */
20
21/**
22 * Include the html and ui functions.
23 */
24require_once ('functions_html.php');
25require_once ('functions_ui.php');
26require_once('functions_io.php');
27
28/**
29 * Check referer to avoid external attacks
30 *
31 * @return bool true if all is ok, false if referer is not equal to current web page
32 */
33//function check_referer() {
34//	global $config;
35//
36//	//If it is disabled the check referer security
37//	if (!$config["referer_security"])
38//		return true;
39//
40//	$referer = '';
41//	if (isset($_SERVER['HTTP_REFERER'])) {
42//		$referer = $_SERVER['HTTP_REFERER'];
43//	}
44//
45//	// If refresh is performed then dont't check referer
46//	// This is done due to problems with HTTP_REFERER var when metarefresh is performed
47//	if ($config["refr"] > 0)
48//		return true;
49//
50//	//Check if the referer have a port (for example when apache run in other port to 80)
51//	if (preg_match('/http(s?):\/\/.*:[0-9]*/', $referer) == 1) {
52//		$url = $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $config["homeurl"];
53//	}
54//	else {
55//		$url = ui_get_full_url();
56//		$url = preg_replace('/http(s?):\/\//','',$url);
57//	}
58//
59//	// Remove protocol from referer
60//	$referer = preg_replace('/http(s?):\/\//','',$referer);
61//	$referer = preg_replace('/\?.*/','',$referer);
62//
63//	if (strpos($url, $referer) === 0) {
64//		return true;
65//	}
66//	else {
67//		return false;
68//	}
69//}
70
71function https_is_running() {
72	if (isset ($_SERVER['HTTPS'])
73		&& ($_SERVER['HTTPS'] === true
74		|| $_SERVER['HTTPS'] == 'on')) {
75
76		return true;
77	}
78
79	return false;
80}
81
82/**
83 * Cleans an object or an array and casts all values as integers
84 *
85 * @param mixed $value String or array of strings to be cleaned
86 * @param int $min If value is smaller than min it will return false
87 * @param int $max if value is larger than max it will return false
88 *
89 * @return mixed The cleaned string. If an array was passed, the invalid values
90 * will be removed
91 */
92function safe_int ($value, $min = false, $max = false) {
93	if (is_array ($value)) {
94		foreach ($value as $key => $check) {
95			$check = safe_int ($check, $min, $max);
96			if ($check !== false) {
97				$value[$key] = $check;
98			}
99			else {
100				unset ($value[$key]);
101			}
102		}
103	}
104	else {
105		$value = (int) $value; //Cast as integer
106		if (($min !== false && $value < $min) || ($max !== false && $value > $max)) {
107			//If it's smaller than min or larger than max return false
108			return false;
109		}
110	}
111
112	return $value;
113}
114
115/**
116 * Cleans a string of special characters (|,@,$,%,/,\,=,?,*,&,#)
117 * Useful for filenames and graphs
118 *
119 * @param string String to be cleaned
120 *
121 * @return string Special characters cleaned.
122 */
123function output_clean_strict ($string) {
124	return preg_replace ('/[\|\@\$\%\/\(\)\=\?\*\&\#]/', '', $string);
125}
126
127/**
128 * Performs an extra clean to a string removing all but alphanumerical
129 * characters _ and / The string is also stripped to 125 characters from after ://
130 * It's useful on sec and sec2, to avoid the use of malicious parameters.
131 *
132 * TODO: Make this multibyte safe (I don't know if there is an attack vector there)
133 *
134 * @param string String to clean
135 * @param default_string String that will be returned if invalid characters are found.
136 *
137 * @return string Cleaned string
138 */
139function safe_url_extraclean ($string, $default_string = '') {
140
141	/* Strip the string to 125 characters */
142	$string = substr ($string, 0, 125);
143
144	/* Search for unwanted characters */
145	if (preg_match ('/[^a-zA-Z0-9_\/\.\-]|(\/\/)|(\.\.)/', $string)) {
146		return $default_string;
147	}
148
149	return $string;
150}
151
152/**
153 * List files in a directory in the local path.
154 *
155 * @param string $directory Local path.
156 * @param string $stringSearch String to match the values.
157 * @param string $searchHandler Pattern of files to match.
158 * @param bool $return Whether to print or return the list.
159 *
160 * @return string he list of files if $return parameter is true.
161 */
162function list_files ($directory, $stringSearch, $searchHandler, $return = false) {
163	$errorHandler = false;
164	$result = array ();
165	if (! $directoryHandler = @opendir ($directory)) {
166		echo ("<pre>\nerror: directory \"$directory\" doesn't exist!\n</pre>\n");
167		return $errorHandler = true;
168	}
169	if ($searchHandler == 0) {
170		while (false !== ($fileName = @readdir ($directoryHandler))) {
171			$result[$fileName] = $fileName;
172		}
173	}
174	if ($searchHandler == 1) {
175		while (false !== ($fileName = @readdir ($directoryHandler))) {
176			if (@substr_count ($fileName, $stringSearch) > 0) {
177				$result[$fileName] = $fileName;
178			}
179		}
180	}
181	if (($errorHandler == true) && (@count ($result) === 0)) {
182		echo ("<pre>\nerror: no filetype \"$fileExtension\" found!\n</pre>\n");
183	}
184	else {
185		asort ($result);
186		if ($return === false) {
187			echo ("<pre>\n");
188			print_r ($result);
189			echo ("</pre>\n");
190		}
191		return $result;
192	}
193}
194
195/**
196 * Format a number with decimals and thousands separator.
197 *
198 * If the number is zero or it's integer value, no decimals are
199 * shown. Otherwise, the number of decimals are given in the call.
200 *
201 * @param float $number Number to be rendered
202 * @param int $decimals numbers after comma to be shown. Default value: 1
203 *
204 * @return string A formatted number for use in output
205 */
206function format_numeric ($number, $decimals = 1) {
207	//Translate to float in case there are characters in the string so
208	// fmod doesn't throw a notice
209	$number = (float) $number;
210
211	if ($number == 0)
212		return 0;
213
214	// Translators: This is separator of decimal point
215	$dec_point = __(".");
216	// Translators: This is separator of decimal point
217	$thousands_sep = __(",");
218
219	/* If has decimals */
220	if (fmod ($number, 1) > 0)
221		return number_format ($number, $decimals, $dec_point, $thousands_sep);
222
223	return number_format ($number, 0, $dec_point, $thousands_sep);
224}
225
226/**
227 * Render numeric data for a graph. It adds magnitude suffix to the number
228 * (M for millions, K for thousands...) base-10
229 *
230 * TODO: base-2 multiplication
231 *
232 * @param float $number Number to be rendered
233 * @param int $decimals Numbers after comma. Default value: 1
234 * @param dec_point Decimal separator character. Default value: .
235 * @param thousands_sep Thousands separator character. Default value: ,
236 *
237 * @return string A string with the number and the multiplier
238 */
239function format_for_graph ($number , $decimals = 1, $dec_point = ".", $thousands_sep = ",") {
240	$shorts = array ("", "K", "M", "G", "T", "P", "E", "Z", "Y");
241	$pos = 0;
242	while ($number >= 1000) { //as long as the number can be divided by 1000
243		$pos++; //Position in array starting with 0
244		$number = $number / 1000;
245	}
246
247	return format_numeric ($number, $decimals). $shorts[$pos]; //This will actually do the rounding and the decimals
248}
249
250/**
251 * Rounds an integer to a multiple of 5.
252 *
253 * Example:
254 * <code>
255 * echo format_integer_round (18);
256 * // Will return 20
257 *
258 * echo format_integer_round (21);
259 * // Will return 25
260 *
261 * echo format_integer_round (25, 10);
262 * // Will return 30
263 * </code>
264 *
265 * @param int Number to be rounded.
266 * @param int Rounder number, default value is 5.
267 *
268 * @param Number rounded to a multiple of rounder
269 */
270function format_integer_round ($number, $rounder = 5) {
271	return (int) ($number / $rounder + 0.5) * $rounder;
272}
273
274/**
275 * INTERNAL: Use ui_print_timestamp for output Get a human readable string of
276 * the difference between current time and given timestamp.
277 *
278 * TODO: Make sense out of all these time functions and stick with 2 or 3
279 *
280 * @param int $timestamp Unixtimestamp to compare with current time.
281 * @param string $units The type of unit, by default 'large'.
282 *
283 * @return string A human readable string of the diference between current
284 * time and a given timestamp.
285 */
286function human_time_comparation ($timestamp, $units = 'large') {
287	global $config;
288
289	if (!is_numeric ($timestamp)) {
290		$timestamp = strtotime ($timestamp);
291	}
292
293	$seconds = get_system_time () - $timestamp;
294
295	// $seconds could be negative, because get_system_time() could return cached value
296	// (that might be the time a session begins at).
297	// So negative values are to be rounded off to 'NOW'.
298	if ( $seconds < 0 ) {
299		$seconds = 0;
300	}
301
302	return human_time_description_raw($seconds, false, $units);
303}
304
305/**
306 * This function gets the time from either system or sql based on preference and returns it
307 *
308 * @return int Unix timestamp
309 */
310function get_system_time () {
311	global $config;
312
313	switch ($config["dbtype"]) {
314		case "mysql":
315			return mysql_get_system_time();
316			break;
317		case "postgresql":
318			return postgresql_get_system_time();
319			break;
320		case "oracle":
321			return oracle_get_system_time();
322			break;
323	}
324}
325
326/**
327 * This function provide the user language configuration if is not default, otherwise return the system language
328 *
329 *  @param string $id_user
330 *
331 *  @return string user active language code
332 */
333function get_user_language ($id_user = null) {
334	global $config;
335
336	$quick_language = get_parameter('quick_language_change', 0);
337
338	if ($quick_language) {
339		$language = get_parameter('language', 0);
340
341		if (defined('METACONSOLE')) {
342
343			if ($id_user == null)
344				$id_user = $config['id_user'];
345
346			if ($language !== 0)
347				update_user($id_user, array('language' => $language));
348
349		}
350
351		if ($language === 'default') {
352			return $config['language'];
353		}
354
355		if ($language !== 0) {
356			return $language;
357		}
358	}
359
360	if ($id_user === null && isset($config['id_user'])) {
361		$id_user = $config['id_user'];
362	}
363
364	if ($id_user !== null) {
365		$userinfo = get_user_info ($id_user);
366		if ($userinfo['language'] != 'default') {
367			return $userinfo['language'];
368		}
369	}
370
371	return $config['language'];
372}
373
374/**
375 * This function get the user language and set it on the system
376 */
377function set_user_language() {
378	global $config;
379	global $l10n;
380
381	$l10n = NULL;
382	$user_language = get_user_language ();
383
384	if (file_exists ('./include/languages/' . $user_language . '.mo')) {
385		$l10n = new gettext_reader (new CachedFileReader ('./include/languages/'.$user_language.'.mo'));
386		$l10n->load_tables();
387	}
388}
389
390/**
391 * INTERNAL (use ui_print_timestamp for output): Transform an amount of time in seconds into a human readable
392 * strings of minutes, hours or days.
393 *
394 * @param int $seconds Seconds elapsed time
395 * @param int $exactly If it's true, return the exactly human time
396 * @param string $units The type of unit, by default 'large'.
397 *
398 * @return string A human readable translation of minutes.
399 */
400function human_time_description_raw ($seconds, $exactly = false, $units = 'large') {
401
402	switch ($units) {
403		case 'large':
404			$secondsString = __('seconds');
405			$daysString = __('days');
406			$monthsString = __('months');
407			$yearsString = __('years');
408			$minutesString = __('minutes');
409			$hoursString = __('hours');
410			$nowString = __('Now');
411			break;
412		case 'tiny':
413			$secondsString = __('s');
414			$daysString = __('d');
415			$monthsString = __('M');
416			$yearsString = __('Y');
417			$minutesString = __('m');
418			$hoursString = __('h');
419			$nowString = __('N');
420			break;
421	}
422
423	if (empty ($seconds)) {
424		return $nowString;
425		// slerena 25/03/09
426		// Most times $seconds is empty is because last contact is current date
427		// Put here "uknown" or N/A or something similar is not a good idea
428	}
429
430	if ($exactly) {
431		$returnDate = '';
432
433		$years = floor($seconds / SECONDS_1YEAR);
434
435		if ($years != 0) {
436			$seconds = $seconds - ($years * SECONDS_1YEAR);
437
438			$returnDate .= "$years $yearsString ";
439		}
440
441		$months = floor($seconds / SECONDS_1MONTH);
442
443		if ($months != 0) {
444			$seconds = $seconds - ($months * SECONDS_1MONTH);
445
446			$returnDate .= "$months $monthsString ";
447		}
448
449		$days = floor($seconds / SECONDS_1DAY);
450
451		if ($days != 0) {
452			$seconds = $seconds - ($days * SECONDS_1DAY);
453
454			$returnDate .= "$days $daysString ";
455		}
456
457		$returnTime = '';
458
459		$hours = floor($seconds / SECONDS_1HOUR);
460
461		if ($hours != 0) {
462			$seconds = $seconds - ($hours * SECONDS_1HOUR);
463
464			$returnTime .= "$hours $hoursString ";
465		}
466
467		$mins = floor($seconds / 60);
468
469		if ($mins != 0) {
470			$seconds = $seconds - ($mins * 60);
471
472			$returnTime .= "$mins $minutesString ";
473
474		}
475
476		$seconds = (int) $seconds;
477
478		if ($seconds != 0) {
479			$returnTime .= "$seconds $secondsString ";
480		}
481
482		$return = ' ';
483
484		if ($returnDate != '') {
485			$return = $returnDate;
486		}
487
488		if ($returnTime != '') {
489			$return .= $returnTime;
490		}
491
492		if ($return == ' ') {
493			return $nowString;
494		}
495		else {
496			return $return;
497		}
498
499	}
500
501	if ($seconds < SECONDS_1MINUTE)
502		return format_numeric ($seconds, 0)." " . $secondsString;
503
504	if ($seconds < SECONDS_1HOUR) {
505		$minutes = floor($seconds / 60);
506		$seconds = $seconds % SECONDS_1MINUTE;
507		if ($seconds == 0)
508			return $minutes.' ' . $minutesString;
509		$seconds = sprintf ("%02d", $seconds);
510		return $minutes.' '. $minutesString . ' ' .$seconds.' ' . $secondsString;
511	}
512
513	if ($seconds < SECONDS_1DAY)
514		return format_numeric ($seconds / SECONDS_1HOUR, 0)." " . $hoursString;
515
516	if ($seconds < SECONDS_1MONTH)
517		return format_numeric ($seconds / SECONDS_1DAY, 0) . " " . $daysString;
518
519	if ($seconds < SECONDS_6MONTHS)
520		return format_numeric ($seconds / SECONDS_1MONTH, 0)." ". $monthsString;
521
522	return "+6 " . $monthsString;
523}
524
525/**
526 * INTERNAL (use ui_print_timestamp for output): Transform an amount of time in seconds into a human readable
527 * strings of minutes, hours or days. Used in alert views.
528 *
529 * @param int $seconds Seconds elapsed time
530 * @param int $exactly If it's true, return the exactly human time
531 * @param string $units The type of unit, by default 'large'.
532 *
533 * @return string A human readable translation of minutes.
534 */
535function human_time_description_alerts ($seconds, $exactly = false, $units = 'tiny') {
536	switch ($units) {
537		case 'large':
538			$secondsString = __('seconds');
539			$daysString = __('days');
540			$monthsString = __('months');
541			$yearsString = __('years');
542			$minutesString = __('minutes');
543			$hoursString = __('hours');
544			$nowString = __('Now');
545			break;
546		case 'tiny':
547			$secondsString = __('s');
548			$daysString = __('d');
549			$monthsString = __('M');
550			$yearsString = __('Y');
551			$minutesString = __('m');
552			$hoursString = __('h');
553			$nowString = __('N');
554			break;
555	}
556
557	if (empty ($seconds)) {
558		return $nowString;
559		// slerena 25/03/09
560		// Most times $seconds is empty is because last contact is current date
561		// Put here "uknown" or N/A or something similar is not a good idea
562	}
563
564	if ($exactly) {
565		$returnDate = '';
566
567		$years = floor($seconds / SECONDS_1YEAR);
568
569		if ($years != 0) {
570			$seconds = $seconds - ($years * SECONDS_1YEAR);
571
572			$returnDate .= "$years $yearsString ";
573		}
574
575		$months = floor($seconds / SECONDS_1MONTH);
576
577		if ($months != 0) {
578			$seconds = $seconds - ($months * SECONDS_1MONTH);
579
580			$returnDate .= "$months $monthsString ";
581		}
582
583		$days = floor($seconds / SECONDS_1DAY);
584
585		if ($days != 0) {
586			$seconds = $seconds - ($days * SECONDS_1DAY);
587
588			$returnDate .= "$days $daysString ";
589		}
590
591		$returnTime = '';
592
593		$hours = floor($seconds / SECONDS_1HOUR);
594
595		if ($hours != 0) {
596			$seconds = $seconds - ($hours * SECONDS_1HOUR);
597
598			$returnTime .= "$hours $hoursString ";
599		}
600
601		$mins = floor($seconds / SECONDS_1MINUTE);
602
603		if ($mins != 0) {
604			$seconds = $seconds - ($mins * SECONDS_1MINUTE);
605
606			if ($hours == 0) {
607				$returnTime .= "$mins $minutesString ";
608			}
609			else {
610				$returnTime = sprintf("%02d",$hours) . "$hoursString" .
611					sprintf("%02d",$mins) . "$minutesString";
612			}
613		}
614
615		if ($seconds != 0) {
616			if ($hours == 0) {
617				$returnTime .= "$seconds $secondsString ";
618			}
619			else {
620				$returnTime = sprintf("%02d",$hours) . "$hoursString" .
621					sprintf("%02d",$mins) . "$minutesString" .
622					sprintf("%02d",$seconds) . "$secondsString";
623			}
624		}
625
626		$return = ' ';
627
628		if ($returnDate != '') {
629			$return = $returnDate;
630		}
631
632		if ($returnTime != '') {
633			$return .= $returnTime;
634		}
635
636		if ($return == ' ') {
637			return $nowString;
638		}
639		else {
640			return $return;
641		}
642
643	}
644
645	if ($seconds < 60)
646		return format_numeric ($seconds, 0)." " . $secondsString;
647
648	if ($seconds < SECONDS_1HOUR) {
649		$minutes = floor($seconds / SECONDS_1MINUTE);
650		$seconds = $seconds % SECONDS_1MINUTE;
651		if ($seconds == 0)
652			return $minutes.' ' . $minutesString;
653		$seconds = sprintf ("%02d", $seconds);
654		return $minutes.' '. $minutesString . ' ' .$seconds.' ' . $secondsString;
655	}
656
657	if ($seconds < SECONDS_1DAY)
658		return format_numeric ($seconds / SECONDS_1HOUR, 0)." " . $hoursString;
659
660	if ($seconds < SECONDS_1MONTH)
661		return format_numeric ($seconds / SECONDS_1DAY, 0) . " " . $daysString;
662
663	if ($seconds < SECONDS_6MONTHS)
664		return format_numeric ($seconds / SECONDS_1MONTH, 0)." ". $monthsString;
665
666	return "+6 " . $monthsString;
667}
668
669/**
670 * @deprecated Get current time minus some seconds. (Do your calculations yourself on unix timestamps)
671 *
672 * @param int $seconds Seconds to substract from current time.
673 *
674 * @return int The current time minus the seconds given.
675 */
676function human_date_relative ($seconds) {
677	$ahora = date("Y/m/d H:i:s");
678	$ahora_s = date("U");
679	$ayer = date ("Y/m/d H:i:s", $ahora_s - $seconds);
680
681	return $ayer;
682}
683
684/**
685 * @deprecated Use ui_print_timestamp instead
686 */
687function render_time ($lapse) {
688	$myhour = intval (($lapse*30) / 60);
689	if ($myhour == 0)
690		$output = "00";
691	else
692		$output = $myhour;
693	$output .= ":";
694	$mymin = fmod ($lapse * 30, 60);
695	if ($mymin == 0)
696		$output .= "00";
697	else
698		$output .= $mymin;
699
700	return $output;
701}
702
703/**
704 * Get a parameter from a request between values.
705 *
706 * It checks first on post request, if there were nothing defined, it
707 * would return get request
708 *
709 * @param string $name key of the parameter in the $_POST or $_GET array
710 * @param array $values The list of values that parameter to be.
711 * @param mixed $default default value if the key wasn't found
712 *
713 * @return mixed Whatever was in that parameter, cleaned however
714 */
715function get_parameterBetweenListValues ($name, $values, $default) {
716	$parameter = $default;
717	// POST has precedence
718	if (isset($_POST[$name]))
719		$parameter = get_parameter_post ($name, $default);
720
721	if (isset($_GET[$name]))
722		$parameter = get_parameter_get ($name, $default);
723
724	foreach($values as $value) {
725		if ($value == $parameter) {
726			return $value;
727		}
728	}
729
730	return $default;
731}
732
733/**
734 * Get a parameter from a checkbox.
735 *
736 * Is checked if the checkbox is sent to fix html bad design
737 *
738 * @param string $name key of the parameter in the $_POST or $_GET array
739 * @param mixed $default default value if the key wasn't found
740 *
741 * @return mixed Whatever was in that parameter, cleaned however
742 *
743 */
744
745function get_parameter_checkbox ($name, $default = '') {
746	$sent = get_parameter($name.'_sent', 0);
747
748	// If is not sent, return the default
749	if (!$sent) {
750		return $default;
751	}
752
753	// If sent, get parameter normally
754	return get_parameter($name, 0);
755}
756
757function get_cookie($name, $default = '') {
758	if (isset($_COOKIE[$name])) {
759		return $_COOKIE[$name];
760	}
761	else {
762		return $default;
763	}
764}
765
766function set_cookie($name, $value) {
767	if (is_null($value)) {
768		unset($_COOKIE[$value]);
769		setcookie($value, null, -1, '/');
770	}
771	setcookie($name, $value);
772}
773
774/**
775 * Get a parameter from a request.
776 *
777 * It checks first on post request, if there were nothing defined, it
778 * would return get request
779 *
780 * @param string $name key of the parameter in the $_POST or $_GET array
781 * @param mixed $default default value if the key wasn't found
782 *
783 * @return mixed Whatever was in that parameter, cleaned however
784 */
785function get_parameter ($name, $default = '') {
786	// POST has precedence
787	if (isset($_POST[$name]))
788		return get_parameter_post ($name, $default);
789
790	if (isset($_GET[$name]))
791		return get_parameter_get ($name, $default);
792
793	return $default;
794}
795
796/**
797 * Get a parameter from a get request.
798 *
799 * @param string $name key of the parameter in the $_GET array
800 * @param mixed $default default value if the key wasn't found
801 *
802 * @return mixed Whatever was in that parameter, cleaned however
803 */
804function get_parameter_get ($name, $default = "") {
805	if ((isset ($_GET[$name])) && ($_GET[$name] != ""))
806		return io_safe_input ($_GET[$name]);
807
808	return $default;
809}
810
811/**
812 * Get a parameter from a post request.
813 *
814 * @param string $name key of the parameter in the $_POST array
815 * @param mixed $default default value if the key wasn't found
816 *
817 * @return mixed Whatever was in that parameter, cleaned however
818 */
819function get_parameter_post ($name, $default = "") {
820	if ((isset ($_POST[$name])) && ($_POST[$name] != "")) {
821		return io_safe_input ($_POST[$name]);
822	}
823
824	return $default;
825}
826
827/**
828 * Get name of a priority value.
829 *
830 * @param int $priority Priority value
831 *
832 * @return string Name of given priority
833 */
834function get_alert_priority ($priority = 0) {
835	global $config;
836
837	switch ($priority) {
838		case 0:
839			return __('Maintenance');
840			break;
841		case 1:
842			return __('Informational');
843			break;
844		case 2:
845			return __('Normal');
846			break;
847		case 3:
848			return __('Warning');
849			break;
850		case 4:
851			return __('Critical');
852			break;
853		case 5:
854			return __('Minor');
855			break;
856		case 6:
857			return __('Major');
858			break;
859	}
860
861	return '';
862}
863
864/**
865 * Gets a translated string of names of days based on the boolean properties of it's input ($row["monday"] = (bool) 1 will output Mon)
866 *
867 * @param  array $row The array of boolean values to check. They should have monday -> sunday in boolean
868 *
869 * @return string Translated names of days
870 */
871function get_alert_days ($row) {
872	global $config;
873	$days_output = "";
874
875	$check = $row["monday"] + $row["tuesday"] + $row["wednesday"] + $row["thursday"] + $row["friday"] + $row["saturday"] + $row["sunday"];
876
877	if ($check == 7) {
878		return __('All');
879	}
880	elseif ($check == 0) {
881		return __('None');
882	}
883
884	if ($row["monday"] != 0)
885		$days_output .= __('Mon')." ";
886	if ($row["tuesday"] != 0)
887		$days_output .= __('Tue')." ";
888	if ($row["wednesday"] != 0)
889		$days_output .= __('Wed')." ";
890	if ($row["thursday"] != 0)
891		$days_output .= __('Thu')." ";
892	if ($row["friday"] != 0)
893		$days_output .= __('Fri')." ";
894	if ($row["saturday"] != 0)
895		$days_output .= __('Sat')." ";
896	if ($row["sunday"] != 0)
897		$days_output .= __('Sun');
898
899	if ($check > 1) {
900		return str_replace (" ",", ",$days_output);
901	}
902
903	return rtrim ($days_output);
904}
905
906/**
907 * Gets the alert times values and returns them as string
908 *
909 * @param array Array with time_from and time_to in it's keys
910 *
911 * @return string A string with the concatenated values
912 */
913function get_alert_times ($row2) {
914	if ($row2["time_from"]) {
915		$time_from_table = $row2["time_from"];
916	}
917	else {
918		$time_from_table = __('N/A');
919	}
920	if ($row2["time_to"]) {
921		$time_to_table = $row2["time_to"];
922	}
923	else {
924		$time_to_table = __('N/A');
925	}
926	if ($time_to_table == $time_from_table)
927		return __('N/A');
928
929	return substr ($time_from_table, 0, 5)." - ".substr ($time_to_table, 0, 5);
930}
931
932/**
933 * Checks if a module is of type "data"
934 *
935 * @param string $module_name Module name to check.
936 *
937 * @return bool True if the module is of type "data"
938 */
939function is_module_data ($module_name) {
940	return preg_match ('/\_data$/', $module_name);
941}
942
943/**
944 * Checks if a module is of type "proc"
945 *
946 * @param string $module_name Module name to check.
947 *
948 * @return bool true if the module is of type "proc"
949 */
950function is_module_proc ($module_name) {
951	return preg_match ('/\_proc$/', $module_name);
952}
953
954/**
955 * Checks if a module is of type "inc"
956 *
957 * @param string $module_name Module name to check.
958 *
959 * @return bool true if the module is of type "inc"
960 */
961function is_module_inc ($module_name) {
962	return preg_match ('/\_inc$/', $module_name);
963}
964
965/**
966 * Checks if a module is of type "string"
967 *
968 * @param string $module_name Module name to check.
969 *
970 * @return bool true if the module is of type "string"
971 */
972function is_module_data_string ($module_name) {
973	return preg_match ('/\_string$/', $module_name);
974}
975
976/**
977 * Checks if a module data is uncompressed according
978 * to the module type.
979 *
980 * @param string module_type Type of the module.
981 *
982 * @return bool true if the module data is uncompressed.
983 */
984function is_module_uncompressed ($module_type) {
985	if (strstr($module_type, 'async') !== false || strstr($module_type, 'log4x') !== false) {
986		return true;
987	}
988	return false;
989}
990
991/**
992 * Get all event types in an array
993 *
994 * @return array module_name Module name to check.
995 */
996function get_event_types ($id_type = false) {
997	global $config;
998
999	$types = array();
1000
1001	$types['critical'] = __('Monitor Critical');
1002	$types['warning'] = __('Monitor Warning');
1003	$types['normal'] = __('Monitor Normal');
1004	$types['unknown'] = __('Unknown');
1005	$types['going_unknown'] = __('Monitor Unknown');
1006
1007	$types['alert_fired'] = __('Alert fired');
1008	$types['alert_recovered'] = __('Alert recovered');
1009	$types['alert_ceased'] = __('Alert ceased');
1010	$types['alert_manual_validation'] = __('Alert manual validation');
1011
1012	$types['new_agent'] = __('Agent created');
1013	$types['recon_host_detected'] = __('Recon host detected');
1014	$types['system'] = __('System');
1015	$types['error'] = __('Error');
1016	$types['configuration_change'] = __('Configuration change');
1017
1018	// This types are impersonated by the monitor 'x' types
1019	// $types['going_up_normal'] = __('Going Normal');
1020	// $types['going_up_warning'] = __('Going Warning');
1021	// $types['going_up_critical'] = __('Going Critical');
1022	// $types['going_down_warning'] = __('Going down Warning');
1023	// $types['going_down_normal'] = __('Going down Normal');
1024	// $types['going_down_critical'] = __('Going down Critical');
1025
1026	foreach ($types as $key => $type) {
1027		$types[$key] = ui_print_truncate_text($type, GENERIC_SIZE_TEXT, false, true, false);
1028	}
1029
1030	if ($id_type === false) {
1031		return $types;
1032	}
1033	else {
1034		return $types[$id_type];
1035	}
1036}
1037
1038/**
1039 * Get an array with all the priorities.
1040 *
1041 * @return array An array with all the priorities.
1042 */
1043function get_priorities ($priority_param = false) {
1044	global $config;
1045
1046	$priorities = array ();
1047	$priorities[EVENT_CRIT_MAINTENANCE] = __('Maintenance');
1048	$priorities[EVENT_CRIT_INFORMATIONAL] = __('Informational');
1049	$priorities[EVENT_CRIT_NORMAL] = __('Normal');
1050	$priorities[EVENT_CRIT_MINOR] = __('Minor');
1051	$priorities[EVENT_CRIT_WARNING] = __('Warning');
1052	$priorities[EVENT_CRIT_MAJOR] = __('Major');
1053	$priorities[EVENT_CRIT_CRITICAL] = __('Critical');
1054	$priorities[EVENT_CRIT_WARNING_OR_CRITICAL] = __('Warning').'/'.__('Critical');
1055	$priorities[EVENT_CRIT_NOT_NORMAL] = __('Not normal');
1056	$priorities[EVENT_CRIT_OR_NORMAL] = __('Critical') . '/' . __('Normal');
1057
1058	foreach ($priorities as $key => $priority) {
1059		$priorities[$key] = ui_print_truncate_text($priority, GENERIC_SIZE_TEXT, false, true, false);
1060	}
1061
1062	if ($priority_param === false) {
1063		return $priorities;
1064	}
1065	else {
1066		return $priorities[$priority_param];
1067	}
1068}
1069
1070/**
1071 * Get priority name from priority value.
1072 *
1073 * @param int $priority value (integer) as stored eg. in database.
1074 *
1075 * @return string priority string.
1076 */
1077function get_priority_name ($priority) {
1078	switch ($priority) {
1079		case 0:
1080			return __('Maintenance');
1081			break;
1082		case 1:
1083			return __('Informational');
1084			break;
1085		case 2:
1086			return __('Normal');
1087			break;
1088		case 3:
1089			return __('Warning');
1090			break;
1091		case 4:
1092			return __('Critical');
1093			break;
1094		case 5:
1095			return __('Minor');
1096			break;
1097		case 6:
1098			return __('Major');
1099			break;
1100		default:
1101			return __('All');
1102			break;
1103	}
1104}
1105
1106/**
1107 * Get priority class (CSS class) from priority value.
1108 *
1109 * @param int priority value (integer) as stored eg. in database.
1110 *
1111 * @return string CSS priority class.
1112 */
1113function get_priority_class($priority) {
1114	switch ($priority) {
1115		case 0:
1116			return "datos_blue";
1117			break;
1118		case 1:
1119			return "datos_grey";
1120			break;
1121		case 2:
1122			return "datos_green";
1123			break;
1124		case 3:
1125			return "datos_yellow";
1126			break;
1127		case 4:
1128			return "datos_red";
1129			break;
1130		case 5:
1131			return "datos_pink";
1132			break;
1133		case 6:
1134			return "datos_brown";
1135			break;
1136		default:
1137			return "datos_grey";
1138			break;
1139	}
1140}
1141
1142/**
1143 * Get priority style from priority class (CSS class).
1144 *
1145 * @param string priority class.
1146 *
1147 * @return string CSS priority class.
1148 */
1149function get_priority_style($priority_class) {
1150	switch ($priority_class) {
1151		case "datos_blue":
1152			$style_css_criticity = 'background-color: ' . COL_MAINTENANCE . '; color: #FFFFFF;';
1153			break;
1154		case "datos_grey":
1155			$style_css_criticity = 'background-color: ' . COL_UNKNOWN . '; color: #FFFFFF;';
1156			break;
1157		case "datos_green":
1158			$style_css_criticity = 'background-color: ' . COL_NORMAL . '; color: #FFFFFF;';
1159			break;
1160		case "datos_yellow":
1161			$style_css_criticity = 'background-color: ' . COL_WARNING . ';';
1162			break;
1163		case "datos_red":
1164			$style_css_criticity = 'background-color: ' . COL_CRITICAL . '; color: #FFFFFF;';
1165			break;
1166		case "datos_pink":
1167			$style_css_criticity = 'background-color: ' . COL_MINOR . ';';
1168			break;
1169		case "datos_brown":
1170			$style_css_criticity = 'background-color: ' . COL_MAJOR . '; color: #FFFFFF;';
1171			break;
1172		case "datos_grey":
1173		default:
1174			$style_css_criticity = 'background-color: ' . COL_UNKNOWN . '; color: #FFFFFF;';
1175			break;
1176	}
1177
1178	return $style_css_criticity;
1179}
1180
1181/**
1182 * Check if the enterprise version is installed.
1183 *
1184 * @return boolean If it is installed return true, otherwise return false.
1185 */
1186function enterprise_installed() {
1187	$return = false;
1188
1189	if (defined('PANDORA_ENTERPRISE')) {
1190		if (PANDORA_ENTERPRISE) {
1191			$return = true;
1192		}
1193	}
1194
1195	return $return;
1196}
1197
1198/**
1199 * TODO: Document enterprise functions
1200 */
1201function enterprise_hook ($function_name, $parameters = false) {
1202	if (function_exists ($function_name)) {
1203		if (!is_array ($parameters))
1204			return call_user_func ($function_name);
1205
1206		return call_user_func_array ($function_name, $parameters);
1207	}
1208
1209	return ENTERPRISE_NOT_HOOK;
1210}
1211
1212/**
1213 * TODO: Document enterprise functions
1214 */
1215function enterprise_include ($filename) {
1216	global $config;
1217
1218	// Load enterprise extensions
1219	$filepath = realpath ($config["homedir"] . '/' . ENTERPRISE_DIR . '/' . $filename);
1220
1221	if ($filepath === false)
1222		return ENTERPRISE_NOT_HOOK;
1223
1224	if (strncmp ($config["homedir"], $filepath, strlen ($config["homedir"])) != 0) {
1225		return ENTERPRISE_NOT_HOOK;
1226	}
1227
1228	if (file_exists ($filepath)) {
1229		include ($filepath);
1230		return true;
1231	}
1232
1233	return ENTERPRISE_NOT_HOOK;
1234}
1235
1236function enterprise_include_once ($filename) {
1237	global $config;
1238
1239	// Load enterprise extensions
1240	$filepath = realpath ($config["homedir"].'/'.ENTERPRISE_DIR.'/'.$filename);
1241
1242	if ($filepath === false)
1243		return ENTERPRISE_NOT_HOOK;
1244
1245	if (strncmp ($config["homedir"], $filepath, strlen ($config["homedir"])) != 0)
1246		return ENTERPRISE_NOT_HOOK;
1247
1248	if (file_exists ($filepath)) {
1249		require_once ($filepath);
1250		return true;
1251	}
1252
1253	return ENTERPRISE_NOT_HOOK;
1254}
1255
1256
1257//These are wrapper functions for PHP. Don't document them
1258if (!function_exists ("mb_strtoupper")) {
1259	//Multibyte not loaded - use wrapper functions
1260	//You should really load multibyte especially for foreign charsets
1261
1262	/**
1263	 * @ignore
1264	 */
1265	function mb_strtoupper ($string, $encoding = false) {
1266			return strtoupper ($string);
1267		}
1268
1269	/**
1270	 * @ignore
1271	 */
1272	function mb_strtolower ($string, $encoding = false) {
1273		return strtoupper ($string);
1274	}
1275
1276	/**
1277	 * @ignore
1278	 */
1279	function mb_substr ($string, $start, $length, $encoding = false) {
1280		return substr ($string, $start, $length);
1281	}
1282
1283	/**
1284	 * @ignore
1285	 */
1286	function mb_strlen ($string, $encoding = false) {
1287		return strlen ($string);
1288	}
1289
1290	/**
1291	 * @ignore
1292	 */
1293	function mb_strimwidth ($string, $start, $length, $trimmarker = false, $encoding = false) {
1294		return substr ($string, $start, $length);
1295	}
1296}
1297
1298/**
1299 * Put quotes if magic_quotes protection
1300 *
1301 * @param string Text string to be protected with quotes if magic_quotes protection is disabled
1302 */
1303function safe_sql_string($string) {
1304	global $config;
1305
1306	switch ($config["dbtype"]) {
1307		case "mysql":
1308			return mysql_safe_sql_string($string);
1309			break;
1310		case "postgresql":
1311			return postgresql_safe_sql_string($string);
1312			break;
1313		case "oracle":
1314			return oracle_safe_sql_string($string);
1315			break;
1316	}
1317}
1318
1319function is_metaconsole() {
1320	global $config;
1321
1322	if ($config['metaconsole'])
1323		return true;
1324	else
1325		return false;
1326}
1327
1328/**
1329 * Checks if current execution is under an AJAX request.
1330 *
1331 * This functions checks if an 'AJAX' constant is defined
1332 *
1333 * @return bool True if the request was done via AJAX. False otherwise
1334 */
1335function is_ajax () {
1336	return defined ('AJAX');
1337}
1338
1339/**
1340 * Check if a code is an error code
1341 *
1342 * @param int code of an operation. Tipically the id of a module, agent... or a code error
1343 *
1344 * @return bool true if a result code is an error or false otherwise
1345 */
1346function is_error($code) {
1347	if ($code !== true AND ($code <= ERR_GENERIC || $code === false)) {
1348		return true;
1349	}
1350	else {
1351		return false;
1352	}
1353}
1354/**
1355 * Transform an array of database result into an indexed array.
1356 *
1357 * This function is useful when the results of a database needs to be used
1358 * in a html_print_select() function.
1359 *
1360 * @param array Array with the results.
1361 * @param string Field of each row in the given array that will act as index. False
1362 * will set all the values.
1363 * @param string Field of each row in the array that will act as value.
1364 *
1365 * @return array An array having the given index as fields and the given values
1366 * as value.
1367 */
1368function index_array ($array, $index = 'id', $value = 'name') {
1369	$retval = array ();
1370
1371	if (! is_array ($array))
1372		return $retval;
1373
1374	foreach ($array as $element) {
1375		if (! isset ($element[$index]))
1376			continue;
1377		if ($value === false) {
1378			$retval[$element[$index]] = $element;
1379			continue;
1380		}
1381
1382		if (! isset ($element[$value]))
1383			continue;
1384		$retval[$element[$index]] = $element[$value];
1385	}
1386
1387	return $retval;
1388}
1389
1390/**
1391 * Return a graph type (string) given a module_type
1392 *
1393 * This function is useful to determine what kind of graph will be
1394 * used, depending on the source data type, depending if it's
1395 * numeric, boolean or a string type.
1396 *
1397 * @param int Id of module type
1398 * @return string Graph type, as used in stat_win.php (Graphs launcher)
1399 */
1400
1401function return_graphtype ($id_module_type) {
1402	switch ($id_module_type) {
1403		case 3:
1404		case 10:
1405		case 17:
1406		case 23:
1407			return "string";
1408			break;
1409		case 2:
1410		case 6:
1411		case 21:
1412		case 18:
1413		case 9:
1414			return "boolean";
1415			break;
1416		case 24:
1417			return "log4x";
1418			break;
1419		default:
1420			return "sparse";
1421			break;
1422	}
1423}
1424
1425/**
1426 * Translate the key in assoc array to numeric offset.
1427 *
1428 * @param array $array The array to return the offset.
1429 * @param mixed $key The key to translate to offset.
1430 *
1431 * @return mixed The offset or false is fail.
1432 */
1433function array_key_to_offset($array, $key) {
1434	$offset = array_search($key, array_keys($array));
1435
1436	return $offset;
1437}
1438
1439/**
1440 * Make a snmpwalk and return it.
1441 *
1442 * @param string $ip_target The target address.
1443 * @param string $snmp_version Version of the snmp: 1,2,2c or 3.
1444 * @param string $snmp_community.
1445 * @param string $snmp3_auth_user.
1446 * @param string $snmp3_security_level.
1447 * @param string $snmp3_auth_method.
1448 * @param string $snmp3_auth_pass.
1449 * @param string $snmp3_privacy_method.
1450 * @param string $snmp3_privacy_pass.
1451 * @param integer $quick_print 0 for all details, 1 for only value.
1452 *
1453 * @return array SNMP result.
1454 */
1455function get_snmpwalk($ip_target, $snmp_version, $snmp_community = '',
1456	$snmp3_auth_user = '', $snmp3_security_level = '',
1457	$snmp3_auth_method = '', $snmp3_auth_pass = '',
1458	$snmp3_privacy_method = '', $snmp3_privacy_pass = '',
1459	$quick_print = 0, $base_oid = "", $snmp_port = '') {
1460
1461	global $config;
1462
1463	// Note: quick_print is ignored
1464
1465	// Fix for snmp port
1466	if (!empty($snmp_port)) {
1467		$ip_target = $ip_target.':'.$snmp_port;
1468	}
1469
1470	// Escape the base OID
1471	if ($base_oid != "") {
1472		$base_oid = escapeshellarg ($base_oid);
1473	}
1474
1475	if (empty($config['snmpwalk'])) {
1476		switch (PHP_OS) {
1477			case "DragonFly":
1478			case "FreeBSD":
1479				$snmpwalk_bin = '/usr/local/bin/snmpwalk';
1480				break;
1481			case "NetBSD":
1482				$snmpwalk_bin = '/usr/pkg/bin/snmpwalk';
1483				break;
1484			default:
1485				$snmpwalk_bin = 'snmpwalk';
1486				break;
1487		}
1488	}
1489	else {
1490		$snmpwalk_bin = $config['snmpwalk'];
1491	}
1492
1493	switch (PHP_OS) {
1494		case "WIN32":
1495		case "WINNT":
1496		case "Windows":
1497			$error_redir_dir = 'NUL';
1498			break;
1499		default:
1500			$error_redir_dir = '/dev/null';
1501			break;
1502	}
1503
1504	$output = array();
1505	$rc = 0;
1506	switch ($snmp_version) {
1507		case '3':
1508			switch ($snmp3_security_level) {
1509				case "authNoPriv":
1510					$command_str = $snmpwalk_bin .
1511						' -m ALL -Oa -v 3' .
1512						' -u ' . escapeshellarg($snmp3_auth_user) .
1513						' -A ' . escapeshellarg($snmp3_auth_pass) .
1514						' -l ' . escapeshellarg($snmp3_security_level) .
1515						' -a ' . escapeshellarg($snmp3_auth_method) .
1516						' ' . escapeshellarg($ip_target)  .
1517						' ' . $base_oid .
1518						' 2> ' . $error_redir_dir;
1519					break;
1520				case "noAuthNoPriv":
1521					$command_str = $snmpwalk_bin .
1522						' -m ALL -Oa -v 3' .
1523						' -u ' . escapeshellarg($snmp3_auth_user) .
1524						' -l ' . escapeshellarg($snmp3_security_level) .
1525						' ' . escapeshellarg($ip_target)  .
1526						' ' . $base_oid .
1527						' 2> ' . $error_redir_dir;
1528					break;
1529				default:
1530					$command_str = $snmpwalk_bin .
1531						' -m ALL -Oa -v 3' .
1532						' -u ' . escapeshellarg($snmp3_auth_user) .
1533						' -A ' . escapeshellarg($snmp3_auth_pass) .
1534						' -l ' . escapeshellarg($snmp3_security_level) .
1535						' -a ' . escapeshellarg($snmp3_auth_method) .
1536						' -x ' . escapeshellarg($snmp3_privacy_method) .
1537						' -X ' . escapeshellarg($snmp3_privacy_pass) .
1538						' ' . escapeshellarg($ip_target)  .
1539						' ' . $base_oid .
1540						' 2> ' . $error_redir_dir;
1541					break;
1542			}
1543			break;
1544		case '2':
1545		case '2c':
1546		case '1':
1547		default:
1548			$command_str = $snmpwalk_bin . ' -m ALL -Oa -v ' . escapeshellarg($snmp_version) . ' -c ' . escapeshellarg($snmp_community) . ' ' . escapeshellarg($ip_target)  . ' ' . $base_oid . ' 2> ' . $error_redir_dir;
1549			break;
1550	}
1551
1552	//html_debug_print($command_str);
1553
1554	exec($command_str, $output, $rc);
1555
1556	// Parse the output of snmpwalk
1557	$snmpwalk = array();
1558	foreach ($output as $line) {
1559
1560		// Separate the OID from the value
1561		$full_oid = explode (' = ', $line);
1562		if (isset ($full_oid[1])) {
1563			$snmpwalk[$full_oid[0]] = $full_oid[1];
1564		}
1565	}
1566
1567	return $snmpwalk;
1568}
1569
1570/**
1571 * Copy from:
1572 * http://stackoverflow.com/questions/1605844/imagettfbbox-returns-wrong-dimensions-when-using-space-characters-inside-text
1573 */
1574function calculateTextBox($font_size, $font_angle, $font_file, $text) {
1575	$box = imagettfbbox($font_size, $font_angle, $font_file, $text);
1576
1577	$min_x = min(array($box[0], $box[2], $box[4], $box[6]));
1578	$max_x = max(array($box[0], $box[2], $box[4], $box[6]));
1579	$min_y = min(array($box[1], $box[3], $box[5], $box[7]));
1580	$max_y = max(array($box[1], $box[3], $box[5], $box[7]));
1581
1582	return array(
1583		'left' => ($min_x >= -1) ? -abs($min_x + 1) : abs($min_x + 2),
1584		'top' => abs($min_y),
1585		'width' => $max_x - $min_x,
1586		'height' => $max_y - $min_y,
1587		'box' => $box
1588	);
1589}
1590
1591/**
1592 * Convert a string to an image
1593 *
1594 * @param string $ip_target The target address.
1595 *
1596 * @return array SNMP result.
1597 */
1598function string2image($string, $width, $height, $fontsize = 3,
1599	$degrees = '0', $bgcolor = '#FFFFFF', $textcolor = '#000000',
1600	$padding_left = 4, $padding_top = 1, $home_url = '') {
1601
1602	global $config;
1603
1604	$string = str_replace('#','',$string);
1605
1606	//Set the size of image from the size of text
1607	if ($width === false) {
1608		$size = calculateTextBox($fontsize, 0, $config['fontpath'], $string);
1609
1610		$fix_value = 1 * $fontsize; //Fix the imagettfbbox cut the tail of "p" character.
1611
1612		$width = $size['width'] + $padding_left + $fix_value;
1613		$height = $size['height'] + $padding_top + $fix_value;
1614
1615		$padding_top = $padding_top + $fix_value;
1616	}
1617
1618	$im = ImageCreate($width,$height);
1619	$bgrgb = html_html2rgb($bgcolor);
1620	$bgc = ImageColorAllocate($im,$bgrgb[0],$bgrgb[1],$bgrgb[2]);
1621	// Set the string
1622	$textrgb = html_html2rgb($textcolor);
1623	imagettftext ($im, $fontsize, 0, $padding_left, $height - $padding_top,
1624		ImageColorAllocate($im,$textrgb[0],$textrgb[1],$textrgb[2]),
1625		$config['fontpath'], $string);
1626	//imagestring($im, $fontsize, $padding_left, $padding_top, $string, ImageColorAllocate($im,$textrgb[0],$textrgb[1],$textrgb[2]));
1627	// Rotates the image
1628	$rotated = imagerotate($im, $degrees, 0) ;
1629
1630	//Cleaned string file name (as the slash)
1631	$stringFile = str_replace('/', '___', $string);
1632
1633	// Generate the image
1634	$file_url = $config['attachment_store'] . '/string2image-'.$stringFile.'.gif';
1635	imagegif($rotated, $file_url);
1636	imagedestroy($rotated);
1637
1638	$file_url = str_replace('#','%23',$file_url);
1639	$file_url = str_replace('%','%25',$file_url);
1640	$file_url = str_replace($config['attachment_store'], $home_url . 'attachment', $file_url);
1641
1642	return $file_url;
1643}
1644
1645/**
1646* Function to restrict SQL on custom-user-defined queries
1647*
1648* @param string SQL code
1649* @return string SQL code validated (it will return empty if SQL is not ok)
1650**/
1651
1652function check_sql ($sql) {
1653	// We remove "*" to avoid things like SELECT * FROM tusuario
1654
1655	//Check that it not delete_ as "delete_pending" (this is a common field in pandora tables).
1656
1657	if (preg_match("/\*|delete[^_]|drop|alter|modify|union|password|pass|insert|update/i", $sql)) {
1658		return "";
1659	}
1660	return $sql;
1661}
1662
1663/**
1664 * Check if login session variables are set.
1665 *
1666 * It will stop the execution if those variables were not set
1667 *
1668 * @param boolean $output Set return instead the output. By default true.
1669 *
1670 * @return bool 0 on success exit() on no success
1671 */
1672
1673function check_login ($output = true) {
1674	global $config;
1675
1676	if (!isset ($config["homedir"])) {
1677		if (!$output) {
1678			return false;
1679		}
1680
1681		// No exists $config. Exit inmediatly
1682		include("general/noaccess.php");
1683		exit;
1684	}
1685
1686	if ((isset($_SESSION["id_usuario"])) AND ($_SESSION["id_usuario"] != "")) {
1687		if (is_user ($_SESSION["id_usuario"])) {
1688			$config['id_user'] = $_SESSION["id_usuario"];
1689
1690			return true;
1691		}
1692	}
1693	else {
1694		require_once($config["homedir"].'/mobile/include/user.class.php');
1695		if(session_id() == '') {
1696			session_start ();
1697		}
1698		session_write_close ();
1699		if (isset($_SESSION['user'])) {
1700			$user = $_SESSION['user'];
1701			$id_user = $user->getIdUser();
1702			if (is_user ($id_user)) {
1703				return true;
1704			}
1705		}
1706	}
1707
1708	if (!$output) {
1709		return false;
1710	}
1711
1712	db_pandora_audit("No session", "Trying to access without a valid session", "N/A");
1713	include ($config["homedir"]."/general/noaccess.php");
1714	exit;
1715}
1716
1717/**
1718 * Check access privileges to resources
1719 *
1720 * Access can be:
1721 * IR - Incident/report Read
1722 * IW - Incident/report Write
1723 * IM - Incident/report Management
1724 * AR - Agent Read
1725 * AW - Agent Write
1726 * LW - Alert Write
1727 * UM - User Management
1728 * DM - DB Management
1729 * LM - Alert Management
1730 * PM - Pandora Management
1731 *
1732 * @param int $id_user User id
1733 * @param int $id_group Agents group id to check from
1734 * @param string $access Access privilege
1735 * @param int $id_agent The agent id.
1736 *
1737 * @return bool 1 if the user has privileges, 0 if not.
1738 */
1739function check_acl($id_user, $id_group, $access, $id_agent = 0) {
1740	if (empty ($id_user)) {
1741		//User ID needs to be specified
1742		trigger_error ("Security error: check_acl got an empty string for user id", E_USER_WARNING);
1743		return 0;
1744	}
1745	elseif (is_user_admin ($id_user)) {
1746		return 1;
1747	}
1748	else {
1749		$id_group = (int) $id_group;
1750	}
1751
1752	$parents_id = array($id_group);
1753	if ($id_group != 0) {
1754		$group = db_get_row_filter('tgrupo', array('id_grupo' => $id_group));
1755		$parents = groups_get_parents($group['parent'], true);
1756
1757		foreach ($parents as $parent) {
1758			$parents_id[] = $parent['id_grupo'];
1759		}
1760	}
1761	else {
1762		$parents_id = array();
1763	}
1764
1765	// TODO: To reduce this querys in one adding the group condition if necessary (only one line is different)
1766	//Joined multiple queries into one. That saves on the query overhead and query cache.
1767	if ($id_group == 0) {
1768		$query = sprintf("SELECT tperfil.incident_view, tperfil.incident_edit,
1769				tperfil.incident_management, tperfil.agent_view,
1770				tperfil.agent_edit, tperfil.alert_edit,
1771				tperfil.alert_management, tperfil.pandora_management,
1772				tperfil.db_management, tperfil.user_management,
1773				tperfil.report_view, tperfil.report_edit,
1774				tperfil.report_management, tperfil.event_view,
1775				tperfil.event_edit, tperfil.event_management,
1776				tperfil.agent_disable,
1777				tperfil.map_view, tperfil.map_edit, tperfil.map_management,
1778				tperfil.vconsole_view, tperfil.vconsole_edit, tperfil.vconsole_management
1779			FROM tusuario_perfil, tperfil
1780			WHERE tusuario_perfil.id_perfil = tperfil.id_perfil
1781				AND tusuario_perfil.id_usuario = '%s'", $id_user);
1782		//GroupID = 0, group id doesnt matter (use with caution!)
1783	}
1784	else {
1785		$query = sprintf("SELECT tperfil.incident_view, tperfil.incident_edit,
1786				tperfil.incident_management, tperfil.agent_view,
1787				tperfil.agent_edit, tperfil.alert_edit,
1788				tperfil.alert_management, tperfil.pandora_management,
1789				tperfil.db_management, tperfil.user_management,
1790				tperfil.report_view, tperfil.report_edit,
1791				tperfil.report_management, tperfil.event_view,
1792				tperfil.event_edit, tperfil.event_management,
1793				tperfil.agent_disable,
1794				tperfil.map_view, tperfil.map_edit, tperfil.map_management,
1795				tperfil.vconsole_view, tperfil.vconsole_edit, tperfil.vconsole_management
1796			FROM tusuario_perfil, tperfil
1797			WHERE tusuario_perfil.id_perfil = tperfil.id_perfil
1798				AND tusuario_perfil.id_usuario = '%s'
1799				AND (tusuario_perfil.id_grupo IN (%s)
1800				OR tusuario_perfil.id_grupo = 0)", $id_user, implode(', ', $parents_id));
1801	}
1802
1803	$rowdup = db_get_all_rows_sql ($query);
1804
1805	if (empty ($rowdup))
1806		return 0;
1807
1808	$result = 0;
1809	$acl_column = get_acl_column($access);
1810	foreach ($rowdup as $row) {
1811		// For each profile for this pair of group and user do...
1812		if (isset($row[$acl_column])) {
1813			$result += $row[$acl_column];
1814		}
1815	}
1816
1817	if ($result >= 1) {
1818		return 1;
1819	}
1820
1821	return 0;
1822}
1823
1824/**
1825 * Get the name of the database column of one access flag
1826 *
1827 * @param string access flag
1828 *
1829 * @return string Column name
1830 */
1831function get_acl_column($access) {
1832	switch ($access) {
1833		case "IR":
1834			return "incident_view";
1835			break;
1836		case "IW":
1837			return "incident_edit";
1838			break;
1839		case "IM":
1840			return "incident_management";
1841			break;
1842		case "AR":
1843			return "agent_view";
1844			break;
1845		case "AW":
1846			return "agent_edit";
1847			break;
1848		case "AD":
1849			return "agent_disable";
1850			break;
1851		case "LW":
1852			return "alert_edit";
1853			break;
1854		case "LM":
1855			return "alert_management";
1856			break;
1857		case "PM":
1858			return "pandora_management";
1859			break;
1860		case "DM":
1861			return "db_management";
1862			break;
1863		case "UM":
1864			return "user_management";
1865			break;
1866		case "RR":
1867			return "report_view";
1868			break;
1869		case "RW":
1870			return "report_edit";
1871			break;
1872		case "RM":
1873			return "report_management";
1874			break;
1875		case "ER":
1876			return "event_view";
1877			break;
1878		case "EW":
1879			return "event_edit";
1880			break;
1881		case "EM":
1882			return "event_management";
1883			break;
1884		case "MR":
1885			return "map_view";
1886			break;
1887		case "MW":
1888			return "map_edit";
1889			break;
1890		case "MM":
1891			return "map_management";
1892			break;
1893		case "VR":
1894			return "vconsole_view";
1895			break;
1896		case "VW":
1897			return "vconsole_edit";
1898			break;
1899		case "VM":
1900			return "vconsole_management";
1901			break;
1902		default:
1903			return "";
1904			break;
1905	}
1906}
1907
1908/**
1909 * Get the name of a plugin
1910 *
1911 * @param int id_plugin Plugin id.
1912 *
1913 * @return string The name of the given plugin
1914 */
1915function dame_nombre_pluginid ($id_plugin) {
1916	return (string) db_get_value ('name', 'tplugin', 'id', (int) $id_plugin);
1917}
1918
1919/**
1920 * Get the operating system id.
1921 *
1922 * @param string Operating system name.
1923 *
1924 * @return id Id of the given operating system.
1925 */
1926function get_os_id ($os_name) {
1927	return (string) db_get_value ('id_os', 'tconfig_os', 'name', $os_name);
1928}
1929
1930/**
1931 * Get the operating system name.
1932 *
1933 * @param int Operating system id.
1934 *
1935 * @return string Name of the given operating system.
1936 */
1937function get_os_name ($id_os) {
1938	return (string) db_get_value ('name', 'tconfig_os', 'id_os', (int) $id_os);
1939}
1940
1941/**
1942 * Get user's dashboards
1943 *
1944 * @param int user id.
1945 *
1946 * @return array Dashboard name of the given user.
1947 */
1948function get_user_dashboards ($id_user) {
1949	$sql = "SELECT name
1950		FROM tdashboard
1951		WHERE id_user="."'".$id_user."'";
1952
1953	return db_get_all_rows_sql ($sql);
1954}
1955
1956/**
1957 * Get all the possible periods in seconds.
1958 *
1959 * @param bool Flag to show or not custom fist option
1960 * @param bool Show the periods by default if it is empty
1961 *
1962 * @return The possible periods in an associative array.
1963 */
1964function get_periods ($custom = true, $show_default = true) {
1965	global $config;
1966
1967
1968	$periods = array ();
1969
1970	if ($custom) {
1971		$periods[-1] = __('custom');
1972	}
1973
1974	if (empty($config['interval_values'])) {
1975		if ($show_default) {
1976			$periods[SECONDS_5MINUTES] = sprintf(__('%s minutes'), '5');
1977			$periods[SECONDS_30MINUTES] = sprintf(__('%s minutes'), '30 ');
1978			$periods[SECONDS_1HOUR] = __('1 hour');
1979			$periods[SECONDS_6HOURS] = sprintf(__('%s hours'), '6 ');
1980			$periods[SECONDS_12HOURS] = sprintf(__('%s hours'), '12 ');
1981			$periods[SECONDS_1DAY] = __('1 day');
1982			$periods[SECONDS_1WEEK] = __('1 week');
1983			$periods[SECONDS_15DAYS] = __('15 days');
1984			$periods[SECONDS_1MONTH] = __('1 month');
1985			$periods[SECONDS_3MONTHS] = sprintf(__('%s months'), '3 ');
1986			$periods[SECONDS_6MONTHS] = sprintf(__('%s months'), '6 ');
1987			$periods[SECONDS_1YEAR] = __('1 year');
1988			$periods[SECONDS_2YEARS] = sprintf(__('%s years'), '2 ');
1989			$periods[SECONDS_3YEARS] = sprintf(__('%s years'), '3 ');
1990		}
1991		else {
1992			$periods[-1] = __('Empty').': '.__('Default values will be used');
1993		}
1994	}
1995	else {
1996		$values = explode(',',$config['interval_values']);
1997		foreach($values as $v) {
1998			$periods[$v] = human_time_description_raw ($v, true);
1999		}
2000	}
2001
2002	return $periods;
2003}
2004
2005
2006/**
2007 * Recursive copy directory
2008 */
2009function copy_dir($src, $dst) {
2010	$dir = opendir($src);
2011	$return = true;
2012
2013	if (!$dir)
2014		return false;
2015
2016	@mkdir($dst);
2017	while (false !== ( $file = readdir($dir)) ) {
2018		if (( $file != '.' ) && ( $file != '..' )) {
2019			if ( is_dir($src . '/' . $file) ) {
2020				$return = copy_dir($src . '/' . $file, $dst . '/' . $file);
2021
2022				if (!$return) {
2023					break;
2024				}
2025			}
2026			else {
2027				$r = copy($src . '/' . $file, $dst . '/' . $file);
2028			}
2029		}
2030	}
2031
2032	closedir($dir);
2033
2034	return $return;
2035}
2036
2037function delete_dir($dir) {
2038	if (!file_exists($dir))
2039		return true;
2040
2041	if (!is_dir($dir))
2042		return unlink($dir);
2043
2044	foreach (scandir($dir) as $item) {
2045		if ($item == '.' || $item == '..')
2046			continue;
2047
2048		if (!delete_dir($dir . "/" . $item))
2049			return false;
2050	}
2051
2052	return rmdir($dir);
2053}
2054
2055/**
2056*  Returns 1 if this is Snapshot data, 0 otherwise
2057*  Looks for two or more carriage returns.
2058*/
2059
2060function is_snapshot_data ($data) {
2061
2062	// TODO IDEA: In the future, we can set a variable in setup
2063	// to define how many \n must have a snapshot to define it's
2064	// a snapshot. I think two or three is a good value anyway.
2065
2066	$temp = array();
2067	$count = preg_match_all ("/\n/", $data, $temp);
2068
2069	if ($count > 2)
2070		return 1;
2071	else
2072		return 0;
2073}
2074
2075/**
2076*  Create an invisible div with a provided ID and value to
2077* can retrieve it from javascript with function get_php_value(name)
2078*/
2079function set_js_value($name, $value) {
2080	html_print_div(array('id' => 'php_to_js_value_' . $name,
2081		'content' => json_encode($value), 'hidden' => true));
2082}
2083
2084
2085function is_array_empty($InputVariable)
2086{
2087	$Result = true;
2088
2089	if (is_array($InputVariable) && count($InputVariable) > 0) {
2090		foreach ($InputVariable as $Value) {
2091			$Result = $Result && is_array_empty($Value);
2092		}
2093	}
2094	else {
2095		$Result = empty($InputVariable);
2096	}
2097
2098	return $Result;
2099}
2100
2101// This function is used to give or not access to nodes in
2102// Metaconsole. Sometimes is used in common code between
2103// Meta and normal console, so if Meta is not activated, it
2104// will return 1 always
2105
2106// Return 0 if the user hasnt access to node/detail 1 otherwise
2107function can_user_access_node () {
2108	global $config;
2109
2110	$userinfo = get_user_info ($config['id_user']);
2111
2112	if (defined('METACONSOLE')) {
2113		return $userinfo["is_admin"] == 1 ? 1 :
2114			$userinfo["metaconsole_access_node"];
2115	}
2116	else {
2117		return 1;
2118	}
2119}
2120
2121/**
2122 *  Get the upload status code
2123 */
2124function get_file_upload_status ($file_input_name) {
2125	if (!isset($_FILES[$file_input_name]))
2126		return -1;
2127
2128	return $_FILES[$file_input_name]['error'];
2129}
2130
2131/**
2132 *  Get a human readable message with the upload status code
2133 */
2134function translate_file_upload_status ($status_code) {
2135	switch ($status_code) {
2136		case UPLOAD_ERR_OK:
2137			$message = true;
2138			break;
2139		case UPLOAD_ERR_INI_SIZE:
2140			$message = __('The file exceeds the maximum size');
2141			break;
2142		case UPLOAD_ERR_FORM_SIZE:
2143			$message = __('The file exceeds the maximum size');
2144			break;
2145		case UPLOAD_ERR_PARTIAL:
2146			$message = __('The uploaded file was only partially uploaded');
2147			break;
2148		case UPLOAD_ERR_NO_FILE:
2149			$message = __('No file was uploaded');
2150			break;
2151		case UPLOAD_ERR_NO_TMP_DIR:
2152			$message = __('Missing a temporary folder');
2153			break;
2154		case UPLOAD_ERR_CANT_WRITE:
2155			$message = __('Failed to write file to disk');
2156			break;
2157		case UPLOAD_ERR_EXTENSION:
2158			$message = __('File upload stopped by extension');
2159			break;
2160
2161		default:
2162			$message = __('Unknown upload error');
2163			break;
2164	}
2165
2166	return $message;
2167}
2168
2169/**
2170 *  Get the arguments given in a function returning default value if not defined
2171 *  @param string name of the argument
2172 *  @param mixed array with arguments
2173 *  @param string defualt value for this argument
2174 *
2175 *  @return string value for the argument
2176 */
2177function get_argument ($argument, $arguments, $default) {
2178	if (isset($arguments[$argument])) {
2179		return $arguments[$argument];
2180	}
2181	else {
2182		return $default;
2183	}
2184}
2185
2186/**
2187 *  Get the arguments given in a function returning default value if not defined
2188 *  @param mixed arguments
2189 * 			- id_user: user who can see the news
2190 *  		- modal: true if want to get modal news. false to return not modal news
2191 * 			- limit: number of max news returned
2192 *  @return mixed list of news
2193 */
2194function get_news($arguments) {
2195	global $config;
2196
2197	$id_user = get_argument ('id_user', $arguments, $config['id_user']);
2198	$modal = get_argument ('modal', $arguments, false);
2199	$limit = get_argument ('limit', $arguments, 99999999);
2200
2201	$id_group = array_keys(users_get_groups($id_user, false, true));
2202	$id_group = implode(',',$id_group);
2203	$current_datetime = date('Y-m-d H:i:s', time());
2204	$modal = (int) $modal;
2205
2206	switch ($config["dbtype"]) {
2207		case "mysql":
2208		case "postgresql":
2209			$sql = sprintf("SELECT subject,timestamp,text,author
2210				FROM tnews WHERE id_group IN (%s) AND
2211								modal = %s AND
2212								(expire = 0 OR (expire = 1 AND expire_timestamp > '%s'))
2213				ORDER BY timestamp DESC
2214				LIMIT %s", $id_group, $modal, $current_datetime, $limit);
2215			break;
2216		case "oracle":
2217			$sql = sprintf("SELECT subject,timestamp,text,author
2218				FROM tnews
2219				WHERE rownum <= %s AND id_group IN (%s) AND
2220								modal = %s AND
2221								(expire = 0 OR (expire = 1 AND expire_timestamp > '%s'))
2222				ORDER BY timestamp DESC", $limit, $id_group, $modal, $current_datetime);
2223			break;
2224	}
2225
2226	$news = db_get_all_rows_sql ($sql);
2227
2228	if (empty($news)) {
2229		$news = array();
2230	}
2231
2232	return $news;
2233}
2234
2235
2236/**
2237 * Print audit data in CSV format.
2238 *
2239 * @param array Audit data.
2240 *
2241 */
2242function print_audit_csv ($data) {
2243	global $config;
2244	global $graphic_type;
2245
2246	$config['ignore_callback'] = true;
2247	while (@ob_end_clean ());
2248
2249	header("Content-type: application/octet-stream");
2250	header("Content-Disposition: attachment; filename=audit_log".date("Y-m-d_His").".csv");
2251	header("Pragma: no-cache");
2252	header("Expires: 0");
2253
2254	if ($data) {
2255		echo __('User') . ';' .
2256			__('Action') . ';' .
2257			__('Date') . ';' .
2258			__('Source ID') . ';' .
2259			__('Comments') ."\n";
2260		foreach ($data as $line) {
2261			echo io_safe_output($line['id_usuario']) . ';' .  io_safe_output($line['accion']) . ';' .  $line['fecha'] . ';' .  $line['ip_origen'] . ';'.  io_safe_output($line['descripcion']). "\n";
2262		}
2263	}
2264	else {
2265		echo __('No data found to export');
2266	}
2267}
2268
2269/**
2270 * Validate the code given to surpass the 2 step authentication
2271 *
2272 * @param string User name
2273 * @param string Code given by the authenticator app
2274 *
2275 * @return	-1 if the parameters introduced are incorrect,
2276 * 			there is a problem accessing the user secret or
2277 *			if an exception are launched.
2278 *			true if the code is valid.
2279 *			false if the code is invalid.
2280 */
2281function validate_double_auth_code ($user, $code) {
2282	global $config;
2283	require_once ($config['homedir'].'/include/auth/GAuth/Auth.php');
2284	$result = false;
2285
2286	if (empty($user) || empty($code)) {
2287		$result = -1;
2288	}
2289	else {
2290		$secret = db_get_value('secret', 'tuser_double_auth', 'id_user', $user);
2291
2292		if ($secret === false) {
2293			$result = -1;
2294		}
2295		else if (!empty($secret)) {
2296			try {
2297				$gAuth = new \GAuth\Auth($secret);
2298				$result = $gAuth->validateCode($code);
2299			}
2300			catch (Exception $e) {
2301				$result = -1;
2302			}
2303		}
2304	}
2305
2306	return $result;
2307}
2308
2309/**
2310 * Get if the 2 step authentication is enabled for the user given
2311 *
2312 * @param string User name
2313 *
2314 * @return true if the user has the double auth enabled or false otherwise.
2315 */
2316function is_double_auth_enabled ($user) {
2317	$result = (bool) db_get_value('id', 'tuser_double_auth', 'id_user', $user);
2318
2319	return $result;
2320}
2321
2322function clear_pandora_error_for_header() {
2323	global $config;
2324
2325	$config["alert_cnt"] = 0;
2326	$_SESSION["alert_msg"] = array();
2327}
2328
2329function set_pandora_error_for_header($message, $title = null) {
2330	global $config;
2331
2332	if (!isset($config['alert_cnt']))
2333		$config['alert_cnt'] = 0;
2334
2335	if (!isset($_SESSION['alert_msg']))
2336		$_SESSION['alert_msg'] = array();
2337
2338	$message_config = array();
2339	if (isset($title))
2340		$message_config['title'] = $title;
2341	$message_config['message'] = $message;
2342	$message_config['no_close'] = true;
2343
2344	$config['alert_cnt']++;
2345	$_SESSION['alert_msg'][] = array('type' => 'error', 'message' => $message_config);
2346}
2347
2348function get_pandora_error_for_header() {
2349	$result = '';
2350
2351	if (isset($_SESSION['alert_msg']) && is_array($_SESSION['alert_msg'])) {
2352		foreach ($_SESSION['alert_msg'] as $key => $value) {
2353			if (!isset($value['type']) || !isset($value['message']))
2354				continue;
2355
2356			switch ($value['type']) {
2357				case 'error':
2358					$result .= ui_print_error_message($value['message'], '', true);
2359					break;
2360				case 'info':
2361					$result .= ui_print_info_message($value['message'], '', true);
2362					break;
2363				default:
2364					break;
2365			}
2366		}
2367	}
2368
2369	return $result;
2370}
2371
2372function set_if_defined (&$var, $test) {
2373	if (isset($test)) {
2374		$var = $test;
2375
2376		return true;
2377	}
2378	else {
2379		return false;
2380	}
2381}
2382
2383function set_unless_defined (&$var, $default) {
2384	if (! isset($var)) {
2385		$var = $default;
2386
2387		return true;
2388	}
2389	else {
2390		return false;
2391	}
2392}
2393
2394function set_when_empty (&$var, $default) {
2395	if (empty($var)) {
2396		$var = $default;
2397
2398		return true;
2399	}
2400	else {
2401		return false;
2402	}
2403}
2404
2405function sort_by_column (&$array_ref, $column_parameter) {
2406	global $column;
2407
2408	$column = $column_parameter;
2409
2410	if (!empty($column)) {
2411		usort($array_ref, function ($a, $b) {
2412			global $column;
2413
2414			return strcmp($a[$column], $b[$column]);
2415		});
2416	}
2417}
2418
2419function array2XML($data, $root = null, $xml = NULL) {
2420	if ($xml == null) {
2421		$xml = simplexml_load_string(
2422			"<?xml version='1.0' encoding='UTF-8'?>\n<" . $root . " />");
2423	}
2424
2425	foreach($data as $key => $value) {
2426		if (is_numeric($key)) {
2427			$key = "item_" . $key;
2428		}
2429
2430		if (is_array($value)) {
2431			$node = $xml->addChild($key);
2432			array2XML($value, $root, $node);
2433		}
2434		else {
2435			$value = htmlentities($value);
2436
2437			if (!is_numeric($value) && !is_bool($value)) {
2438				if (!empty($value)) {
2439					$xml->addChild($key, $value);
2440				}
2441			}
2442			else {
2443				$xml->addChild($key, $value);
2444			}
2445		}
2446	}
2447
2448	return $xml->asXML();
2449}
2450
2451/**
2452 * Returns an array by extracting a column or columns.
2453 *
2454 * @param array Array
2455 * @param mixed (string/array) Column name/s
2456 *
2457 * @return array Array formed by the extracted columns of every array iteration.
2458 */
2459function extract_column ($array, $column) {
2460	$column_is_arr = is_array($column);
2461
2462	return array_map(function($item) use ($column_is_arr, $column) {
2463		if ($column_is_arr) {
2464			return array_reduce($column, function($carry, $col) use ($item) {
2465				$carry[$col] = $item[$col];
2466				return $item[$col];
2467			}, array());
2468		}
2469		else {
2470			return $item[$column];
2471		}
2472	}, $array);
2473}
2474
2475
2476function get_percentile($percentile, $array) {
2477	sort($array);
2478	$index = ($percentile / 100) * count($array);
2479
2480	if (floor($index) == $index) {
2481		 $result = ($array[$index-1] + $array[$index]) / 2;
2482	}
2483	else {
2484		$result = $array[floor($index)];
2485	}
2486
2487	return $result;
2488}
2489
2490if (!function_exists('hex2bin')) {
2491	function hex2bin($data) {
2492		static $old;
2493		if ($old === null) {
2494			$old = version_compare(PHP_VERSION, '5.2', '<');
2495		}
2496		$isobj = false;
2497		if (is_scalar($data) || (($isobj = is_object($data)) && method_exists($data, '__toString'))) {
2498			if ($isobj && $old) {
2499				ob_start();
2500				echo $data;
2501				$data = ob_get_clean();
2502			}
2503			else {
2504				$data = (string) $data;
2505			}
2506		}
2507		else {
2508			trigger_error(__FUNCTION__.'() expects parameter 1 to be string, ' . gettype($data) . ' given', E_USER_WARNING);
2509			return;//null in this case
2510		}
2511		$len = strlen($data);
2512		if ($len % 2) {
2513			trigger_error(__FUNCTION__.'(): Hexadecimal input string must have an even length', E_USER_WARNING);
2514			return false;
2515		}
2516		if (strspn($data, '0123456789abcdefABCDEF') != $len) {
2517			trigger_error(__FUNCTION__.'(): Input string must be hexadecimal string', E_USER_WARNING);
2518			return false;
2519		}
2520		return pack('H*', $data);
2521	}
2522}
2523
2524
2525function get_refresh_time_array() {
2526	return array (
2527		'0' => __('Disable'),
2528		'5' => __('5 seconds'),
2529		'10' => __('10 seconds'),
2530		'15' => __('15 seconds'),
2531		'30' => __('30 seconds'),
2532		(string)SECONDS_1MINUTE => __('1 minute'),
2533		(string)SECONDS_2MINUTES => __('2 minutes'),
2534		(string)SECONDS_5MINUTES => __('5 minutes'),
2535		(string)SECONDS_15MINUTES => __('15 minutes'),
2536		(string)SECONDS_30MINUTES => __('30 minutes'),
2537		(string)SECONDS_1HOUR => __('1 hour'));
2538}
2539?>
2540