<?php
//WIN REQUEST_URI fix
if (!isset($_SERVER['REQUEST_URI'])) {
	if (isset($_SERVER['SCRIPT_NAME'])) {
		$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
	} else {
		$_SERVER['REQUEST_URI'] = $_SERVER['PHP_SELF'];
	}
	if ($_SERVER['QUERY_STRING']){
		$_SERVER['REQUEST_URI'] .=  '?'.$_SERVER['QUERY_STRING'];
	}
}

function getBaseURL() {
	if ($GLOBALS['cliMode']) {
		return false;
	}
	$protocol = isSSL()?'https':'http';
	$port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? '' : (":".$_SERVER["SERVER_PORT"]);
	$path = $_SERVER['REQUEST_URI'];
	//deal with full URLs
	$fullURL = false;
	if (strtolower(substr($path, 0, 8)) == 'https://') {
		$fullURL = true;
		$path = substr($path, 8);
	}
	if (strtolower(substr($path, 0, 7)) == 'http://') {
		$fullURL = true;
		$path = substr($path, 7);
	}
	if ($fullURL) {
		//strip everything before the first slash
		$firstSlash = strpos($path, '/');
		$path = substr($path, $firstSlash);
	}
	//strip query string
	$posOfQuestionMark = strpos($path, '?');
	if ($posOfQuestionMark) {
		$path = substr($path, 0, $posOfQuestionMark);
	}
	//strip virtual path after the php script file name
	if (isset($_SERVER['PATH_INFO'])) {
		$posOfVirtualPath = strrpos($path, $_SERVER['PATH_INFO']);
		if ($posOfVirtualPath) {
			$path = substr($path, 0, $posOfVirtualPath);
		}
	}
	//strip oauth2 subpaths
	$posOfOauth2Folder = strpos($path, '/oauth2/');
	if ($posOfOauth2Folder !== false) {
		$path = substr($path, 0, $posOfOauth2Folder);
	}
	//strip script name
	$posOfScript = strpos($path, basename($_SERVER['SCRIPT_NAME']));
	if ($posOfScript !== false) {
		$path = substr($path, 0, $posOfScript);
	}
	$path = rtrim($path, '#');
	$path = rtrim($path, '/');
	$host = $_SERVER['HTTP_HOST'];
	if ($port) {$host = str_replace($port, '', $host);}
	return $protocol.'://'.$host.$port.$path;
}


function compare_passwords_plain($readablePass, $encodedPass) {
	return ($readablePass == $encodedPass);
}
function compare_passwords_md5($readablePass, $encodedPass) {
	return (md5($readablePass) == $encodedPass);
}

function dirFilterByPattern($filename) {
	global $config;
	foreach ($config['app']['hidden_folder_names'] as $pattern) {
		if (fnmatch($pattern, $filename)) {return false;}
	}
	return true;
}

function fileFilterByPattern($filename) {
	global $config;
	foreach ($config['app']['hidden_file_names'] as $pattern) {
		if (fnmatch($pattern, $filename)) {return false;}
	}
	return true;
}

function siteRedirect($location = false) {
	global $config;
	header('Location: '.$config['url']['root'].'/'.$location);
	exit();
}

function forURL($str) {
	return htmlspecialchars(rawurlencode($str), ENT_QUOTES);
}

function safeJS($str) {
	return addslashes(str_replace("\n","",str_replace("\n","",str_replace("\r","",$str))));
}

function safeSQL($str) {
	return (!get_magic_quotes_gpc())?addslashes($str):$str;
}

function HTMLforSafeJS($str) {
	$str = str_replace("'","\'", $str);
	$str = str_replace("\'+","'+", $str);
	$str = str_replace("+\'","+'", $str);
	$str = str_replace("\n","", $str);
	$str = str_replace("\r","", $str);
	return $str;
}

function fromHTML($input) {
	global $str;
	return $str->fromHTML($input);
}

function forhtml($s) {
	global $str;
	return $str->forHTML($s);
}

function safeHTML($str) {
	return htmlspecialchars($str, ENT_QUOTES);
}

function safeHTML2($string) {
	$string = str_replace ('<', '&lt;', $string);
	$string = str_replace ('>', '&gt;', $string);
	$string = str_replace ('<', '&lt;', $string);
	$string = str_replace ('>', '&gt;', $string);
	$string = str_replace ('"', '&quot;', $string );
	return $string;
}

function percent($nr1, $nr2, $dec = 1) {
	if ($nr2 < 1) {return 0;}
	return round($nr1*100/$nr2, $dec);
}

function addTrailingSlash($s) {
	return rtrim($s, '/').'/';
}

function gluePath() {
	$i = 0;
	foreach (func_get_args() as $p) {
		if ($i == 0) {
			$p = rtrim($p, '/');
		} else {
			$p = trim($p, '/');
		}
		if (strlen($p) > 0) {$parts[] = $p;}
		$i++;
	}
	return @implode($parts, '/');
}

function isCfgOn($option) {
	return (strtolower(ini_get($option)) == "on" || ini_get($option) == "1" || strtolower(ini_get($option)) == "yes");
}

function isEmptyMySQLDate($v) {
	if ($v == '0000-00-00 00:00:00' || $v == '0000-00-00' || $v == NULL || $v == '' || $v == false) {
		return true;
	}
}

function HTMLDate2MySQL($date, $end = false, $separator = "/", $order = array("y" => 2, "m" => 1, "d" => 0)) {
	if (strlen($date) < 10) {return NULL;}
	$pieces = explode($separator, $date);
	$y = $pieces[$order['y']];
	$m = $pieces[$order['m']];
	$d = $pieces[$order['d']];
	if ($end) {
		return $y."-".$m."-".$d." 23:59:59";
	} else {
		return $y."-".$m."-".$d." 00:00:00";
	}
}

function MySQLDate2HTML($date, $separator = "-", $order = array("y" => 0, "m" => 1, "d" => 2)) {
	if (isEmptyMySQLDate($date)) {return NULL;}
	$p = explode(" ", $date);
	$pieces = explode($separator, $p[0]);
	$y = $pieces[$order['y']];
	$m = $pieces[$order['m']];
	$d = $pieces[$order['d']];
	return $m."/".$d."/".$y;
}

function MySQLTimeDiff($t1) {
	return localizedDateDiffString(MySQLDateToUnix($t1));
}

function MySQLDateToUnix($datetime) {
    if ($datetime) $parts = explode(' ', $datetime);
    $datebits = explode('-', $parts[0]);
    if (3 != count($datebits)) return -1;
    if (isset($parts[1])) {
        $timebits = explode(':', $parts[1]);
        if (3 != count($timebits)) return -1;
        return mktime($timebits[0], $timebits[1], $timebits[2], $datebits[1], $datebits[2], $datebits[0]);
    }
    return mktime (0, 0, 0, $datebits[1], $datebits[2], $datebits[0]);
}

function dateDiff($t1, $t2 = false) {
	if (!$t2) {
		$now = true;
		$t2 = time();
	}
	if ($t2 < $t1) {
		return false;
	}
	$d = $t2-$t1;
	if ($d > 31556926) {
		$p = round($d/31556926, 1);
		if ($now) {
			$str = 'years ago';
		} else {
			$str = 'years';
		}
	} if ($d > 31556926 && $d < 63113852) {
		$p = false;
		if ($now) {
			$str = 'one year ago';
		} else {
			$str = 'one year';
		}
	} else if ($d > 5256000 && $d < 31556926) {
		$p = floor($d/2628000);
		if ($now) {
			$str = 'months ago';
		} else {
			$str = 'months';
		}
	} else if ($d > 2628000 && $d < 5256000) {
		$p = false;
		if ($now) {
			$str = 'one month ago';
		} else {
			$str = 'one month';
		}
	} else if ($d > 1209600 && $d < 2628000) {
		$p = floor($d/604800);
		if ($now) {
			$str = 'weeks ago';
		} else {
			$str = 'weeks';
		}
	} else if ($d > 604800 && $d < 1209600) {
		$p = false;
		if ($now) {
			$str = 'one week ago';
		} else {
			$str = 'one week';
		}
	} else if ($d > 172800 && $d < 604800) {
		$p = floor($d/86400);
		if ($now) {
			$str = 'days ago';
		} else {
			$str = 'days';
		}
	} else if ($d > 86400 && $d < 172800) {
		$p = false;
		if ($now) {
			$str = 'yesterday';
		} else {
			$str = 'one day';
		}
	} else if ($d < 86400 && $d > 3600) {
		$p = floor($d/3600);
		if ($p > 1) {
			if ($now) {
				$str = 'hours ago';
			} else {
				$str = 'hours';
			}
		} else {
			$p = false;
			if ($now) {
				$str = 'one hour ago';
			} else {
				$str = 'one hour';
			}
		}
	} else if ($d < 3600) {
		$p = floor($d/60);
		if ($p >= 2) {
			if ($now) {
				$str = 'minutes ago';
			} else {
				$str = 'minutes';
			}
		} else if ($p >= 1 && $p < 2) {
			$p = false;
			if ($now) {
				$str = 'one minute ago';
			} else {
				$str = 'one minute';
			}
		} else if ($p < 1) {
			$str = 'just now';
		}
	}
	return array($str, $p, $d);
}

function localizedDateDiffString($seconds, $section = 'General') {
	global $locale;
	if ($seconds == 0) {
		$timer = "-";
	} else {
		$ddiff = dateDiff($seconds);
		if (!$ddiff) {return false;}
		if ($ddiff[1]) {
			$timer = $locale->get("%1 ".$ddiff[0], $section, array($ddiff[1]));
		} else {
			$timer = $locale->get($ddiff[0], $section);
		}
	}
	return $timer;
}

function getMemoryLimit() {
	$v_memory_limit = ini_get('memory_limit');
	$v_memory_limit = trim($v_memory_limit);
	$last = strtolower(substr($v_memory_limit, -1));
	if($last == 'g')
	    $v_memory_limit = $v_memory_limit*1073741824;
	if($last == 'm')
	    $v_memory_limit = $v_memory_limit*1048576;
	if($last == 'k')
	    $v_memory_limit = $v_memory_limit*1024;
	return $v_memory_limit;
}

function getAvailableMemory() {
	return getMemoryLimit()-memory_get_usage();
}

function trim_array($a) {
	return array_map('trim', array_filter($a));
}

function mapNetworkDrive($UNCpath, $username, $password, $driveLetter) {
	if (!is_readable($driveLetter.":/")) {
		$cmd = "net use ".$driveLetter.": \"".str_replace("/", "\\", $UNCpath)."\" ".$password." /user:".$username." /persistent:no > nul 2>&1";
		$b = system($cmd, $a);
		return array($a, $b);
	}
}

function jsonOutput($rs) {
	header('Content-type: application/json');
	exit(json_encode($rs));
}

function jsonFeedback($success, $msg, $errors = false) {
	$locale = FileRun::getLocale();
	if (is_array($msg)) {
		$tmp = array();
		foreach($msg as $m) {
			$tmp[] = $locale->get($m);
		}
		$msg = implode('<br>', $tmp);
	} else {
		$msg = $locale->get($msg);
	}
	$rs = array("success" => $success, "msg" => $msg);
	if (!$success) {$rs['errors'] = $errors;}
	jsonOutput($rs);
}

function getUploadChunkSize() {
	$upload_max_filesize = strtoupper(ini_get("upload_max_filesize"));
	$post_max_size = strtoupper(ini_get("post_max_size"));
	//UPLOAD_MAX_FILESIZE
	$minSafe = 2097152; //just less than 2MB
	$maxUseful = 20971520; //20 megabytes
	$lastChar = substr($upload_max_filesize, -1);
	if ($lastChar == "K") {
		$chunkSize1 = (int)$upload_max_filesize * 1024;
	} else if ($lastChar == "M") {
		$chunkSize1 = (int)$upload_max_filesize * 1048576;
	} else if ($lastChar == "G") {
		$chunkSize1 = $maxUseful;
	} else {
		$chunkSize1 = $minSafe;
	}
	//POST_MAX_SIZE
	$lastChar = substr($post_max_size, -1);
	if ($lastChar == "K") {
		$chunkSize2 = (int)$post_max_size * 1024;
	} else if ($lastChar == "M") {
		$chunkSize2 = (int)$post_max_size * 1048576;
	} else if ($lastChar == "G") {
		$chunkSize2 = $maxUseful;
	} else {
		$chunkSize2 = $minSafe;
	}
	$chunkSize = min($maxUseful, $chunkSize1, $chunkSize2);
	$chunkSize = $chunkSize-10240; //minus 10KB just to make sure
	return $chunkSize;
}

function ini_get_bytes($dir) {
	$val = trim(strtoupper(ini_get($dir)));
	$lastChar = substr($val, -1);
	if ($lastChar == "K") {
		$val = (int)$val * 1024;
	} else if ($lastChar == "M") {
		$val = (int)$val * 1048576;
	} else if ($lastChar == "G") {
		$val = (int)$val * 1073741824;
	}
    return $val;
}

function natksort(&$array) {
	$keys = array_keys($array);
	natcasesort($keys);
	$new_array = array();
	foreach ($keys as $k) {
		$new_array[$k] = $array[$k];
	}
	$array = $new_array;
	return true;
}

function getIP() {
	foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
		if (array_key_exists($key, $_SERVER) === true) {
			foreach (array_map('trim', explode(',', $_SERVER[$key])) as $ip) {
				if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
					return $ip;
				}
			}
			return $ip ?: 'unknown';
		}
	}
}

// decbin32
// In order to simplify working with IP addresses (in binary) and their
// netmasks, it is easier to ensure that the binary strings are padded
// with zeros out to 32 characters - IP addresses are 32 bit numbers
function decbin32 ($dec) {
	return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT);
}

// ip_in_range
// This function takes 2 arguments, an IP address and a "range" in several
// different formats.
// Network ranges can be specified as:
// 1. Wildcard format:     1.2.3.*
// 2. CIDR format:         1.2.3/24  OR  1.2.3.4/255.255.255.0
// 3. Start-End IP format: 1.2.3.0-1.2.3.255
// The function will return true if the supplied IP is within the range.
// Note little validation is done on the range inputs - it expects you to
// use one of the above 3 formats.
function ip_in_range($ip, $range) {
	if (strpos($range, '/') !== false) {
		// $range is in IP/NETMASK format
		list($range, $netmask) = explode('/', $range, 2);
		if (strpos($netmask, '.') !== false) {
			// $netmask is a 255.255.0.0 format
			$netmask = str_replace('*', '0', $netmask);
			$netmask_dec = ip2long($netmask);
			return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) );
		} else {
			// $netmask is a CIDR size block
			// fix the range argument
			$x = explode('.', $range);
			while(count($x)<4) $x[] = '0';
			list($a,$b,$c,$d) = $x;
			$range = sprintf("%u.%u.%u.%u", empty($a)?'0':$a, empty($b)?'0':$b,empty($c)?'0':$c,empty($d)?'0':$d);
			$range_dec = ip2long($range);
			$ip_dec = ip2long($ip);

			# Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
			#$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));

			# Strategy 2 - Use math to create it
			$wildcard_dec = pow(2, (32-$netmask)) - 1;
			$netmask_dec = ~ $wildcard_dec;

			return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
		}
	} else {
		// range might be 255.255.*.* or 1.2.3.0-1.2.3.255
		if (strpos($range, '*') !==false) { // a.b.*.* format
			// Just convert to A-B format by setting * to 0 for A and 255 for B
			$lower = str_replace('*', '0', $range);
			$upper = str_replace('*', '255', $range);
			$range = "$lower-$upper";
		}

		if (strpos($range, '-')!==false) { // A-B format
			list($lower, $upper) = explode('-', $range, 2);
			$lower_dec = (float)sprintf("%u",ip2long($lower));
			$upper_dec = (float)sprintf("%u",ip2long($upper));
			$ip_dec = (float)sprintf("%u",ip2long($ip));
			return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) );
		}

		//echo 'Range argument is not in 1.2.3.4/24 or 1.2.3.4/255.255.255.0 format';
		return false;
	}

}

function isSSL() {
	if($_SERVER['https'] == 1 || $_SERVER['HTTPS'] == 1) /* Apache */ {
		return true;
	} elseif (strtolower($_SERVER['https']) == 'on' || strtolower($_SERVER['HTTPS']) == 'on') /* IIS */ {
		return true;
	} elseif ($_SERVER['SERVER_PORT'] == 443) /* others */ {
		return true;
	}
}

function browserIsChrome() {
	return (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'chrome') !== false);
}

function browserIsFirefox() {
	return (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox') !== false);
}

function browserIsIE8OrLower() {
	return preg_match('/(?i)msie [2-8]/',$_SERVER['HTTP_USER_AGENT']);
}

function intOrNULL($v) {
	if ($v == '') {return NULL;}
	return intval($v);
}
function intOrZero($v) {
	return intval($v);
}
function oneOrZero($v) {
	return intval($v) == 1 ? 1 : 0;
}

if (!function_exists('http_response_code')) {
	function http_response_code($code = NULL) {
		if ($code !== NULL) {
			switch ($code) {
				case 100: $text = 'Continue'; break;
				case 101: $text = 'Switching Protocols'; break;
				case 200: $text = 'OK'; break;
				case 201: $text = 'Created'; break;
				case 202: $text = 'Accepted'; break;
				case 203: $text = 'Non-Authoritative Information'; break;
				case 204: $text = 'No Content'; break;
				case 205: $text = 'Reset Content'; break;
				case 206: $text = 'Partial Content'; break;
				case 300: $text = 'Multiple Choices'; break;
				case 301: $text = 'Moved Permanently'; break;
				case 302: $text = 'Moved Temporarily'; break;
				case 303: $text = 'See Other'; break;
				case 304: $text = 'Not Modified'; break;
				case 305: $text = 'Use Proxy'; break;
				case 400: $text = 'Bad Request'; break;
				case 401: $text = 'Unauthorized'; break;
				case 402: $text = 'Payment Required'; break;
				case 403: $text = 'Forbidden'; break;
				case 404: $text = 'Not Found'; break;
				case 405: $text = 'Method Not Allowed'; break;
				case 406: $text = 'Not Acceptable'; break;
				case 407: $text = 'Proxy Authentication Required'; break;
				case 408: $text = 'Request Time-out'; break;
				case 409: $text = 'Conflict'; break;
				case 410: $text = 'Gone'; break;
				case 411: $text = 'Length Required'; break;
				case 412: $text = 'Precondition Failed'; break;
				case 413: $text = 'Request Entity Too Large'; break;
				case 414: $text = 'Request-URI Too Large'; break;
				case 415: $text = 'Unsupported Media Type'; break;
				case 500: $text = 'Internal Server Error'; break;
				case 501: $text = 'Not Implemented'; break;
				case 502: $text = 'Bad Gateway'; break;
				case 503: $text = 'Service Unavailable'; break;
				case 504: $text = 'Gateway Time-out'; break;
				case 505: $text = 'HTTP Version not supported'; break;
				default:
					exit('Unknown http status code "' . htmlentities($code) . '"');
					break;
			}
			$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
			header($protocol . ' ' . $code . ' ' . $text);
			$GLOBALS['http_response_code'] = $code;
		} else {
			$code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);
		}
		return $code;
	}
}

function asdf($a) {
	header('Content-type: text/plain');
	print_r($a);
	exit();
}
