<?php

/**
 *--------------------------------------
 * Framework Function Library
 *--------------------------------------
 * @project		: pfa
 * @author		: cblee
 * @created		: 2012-9-23
 * @copyright	: (c)2012 AsThis
 *--------------------------------------
 */

defined('PFA_PATH') or exit('Access Denied');

/* Instantiate Ctrlr */
function A($name = '') {
	static $_ctrlr = array();
	if(empty($name)) {
		return new Ctrlr;
	}
	if(isset($_ctrlr[$name])) {
		return $_ctrlr[$name];
	}
	$OriClassName = $name;
	if(strpos($name, C('APP.GROUP_DEPR'))) {
		$array = explode(C('APP.GROUP_DEPR'), $name);
		$name = array_pop($array);
		$className = $name.'Ctrlr';
		import(implode(C('APP.GROUP_DEPR'), $array).'.'.$className, LIB_CTRLR_PATH);
	}
	else {
		$className = $name.'Ctrlr';
		import($className, LIB_CTRLR_PATH);
	}
	if(class_exists($className, false)) {
		$ctrlr = new $className();
		$_ctrlr[$OriClassName] = $ctrlr;
		return $ctrlr;
	}
	else {
		return false;
	}
}

/* Instantiate Modl */
function M($name = '') {
	static $_modl = array();
	if(empty($name)) {
		return new Modl;
	}
	if(isset($_modl[$name])) {
		return $_modl[$name];
	}
	$OriClassName = $name;
	$className = $name.'Modl';
	if(class_exists($className)) {
		$modl = new $className();
	}
	else {
		$modl = new Modl($name);
	}
	$_modl[$OriClassName] = $modl;
	return $modl;
}

/* Simple data (string, array) get and set */
function F($name, $value = '', $path = DATA_PATH) {
	static $_cache = array();
	$name = str_replace('.', '', $name); // prevent parent directory
	$path = rtrim($path, "/\\").D_S;
	$filename = $path.$name.'.php';
	if('' !== $value) {
		if(is_null($value)) {
			if(is_file($filename)) {
				@unlink($filename); // delete cache
			}
			return;
		}
		else {
			$dir = dirname($filename);
			/* build cache */
			if(!is_dir($dir)) {
				mk_dir($dir);
			}
			$_cache[$name] = $value;
			return file_put_contents($filename, "<?php\r\nreturn ".var_export($value, true).";\r\n?>");
		}
	}
	if(isset($_cache[$name])) {
		return $_cache[$name];
	}
	if(is_file($filename)) {
		$value = include $filename;
		$_cache[$name] = $value;
		return $value;
	}
	return false;
}

/* The global cache get and set */
function S($name, $value = '', $expire = null, $options = null) {
	$type = isset($options['cacheType']) ? $options['cacheType'] : '';
	static $_cache = array();
	$cache = Cache::connect($options);
	if('' !== $value) {
		/* delete cache */
		if(is_null($value)) {
			$result = $cache->del($name);
			if($result) {
				unset($_cache[$type.'_'.$name]);
			}
			return $result;
		}
		/* set cache */
		else {
			$cache->set($name, $value, $expire);
			$_cache[$type.'_'.$name] = $value;
		}
		return;
	}
	if(isset($_cache[$type.'_'.$name])) {
		return $_cache[$type.'_'.$name];
	}
	/* get cache */
	$value = $cache->get($name);
	$_cache[$type.'_'.$name] = $value;
	return $value;
}

/* get and set count */
function N($key, $step = 0) {
	static $_num = array();
	if(!isset($_num[$key]) or null === $step) {
		$_num[$key] = 0;
	}
	if(0 === $step) {
		return $_num[$key];
	}
	else {
		$_num[$key] = $_num[$key] + (int)$step;
	}
}

/* get and set config */
function C($name = null, $value = null) {
	return _SG($name, $value, 'config');
}

/* get and set language */
function L($name = null, $value = null, $data = null) {
	$return = _SG($name, $value, 'language');
	if(is_array($data)) {
		foreach($data as $k => $v) {
			$return = str_replace("{\${$k}}", $v, $return);
		}
	}
	return $return;
}

/* get and set */
function _SG($key = null, $value = null, $name = 'default') {
	static $_temp = array();
	if(!isset($_temp[$name])) {
		$_temp[$name] = array();
	}
	/* get all */
	if(empty($key)) {
		return $_temp[$name];
	}
	if(is_string($key)) {
		if(!strpos($key, '.')) {
			if(is_null($value)) {
				return isset($_temp[$name][$key]) ? $_temp[$name][$key] : $key;
			}
			$_temp[$name][$key] = $value;
			return;
		}
		/* 2 dimensional array */
		$key = explode('.', $key);
		if(is_null($value)) {
			return isset($_temp[$name][$key[0]][$key[1]]) ? $_temp[$name][$key[0]][$key[1]] : $key[0].'.'.$key[1];
		}
		$_temp[$name][$key[0]][$key[1]] = $value;
		return;
	}
	/* Batch definitions */
	if(is_array($key)) {
		foreach($key as $k => $v) {
			if(is_array($v)) {
				if(isset($_temp[$name][$k])) {
					$_temp[$name][$k] = array_merge($_temp[$name][$k], $v);
				}
				else {
					$_temp[$name][$k] = $v;
				}
			}
			else {
				$_temp[$name][$k] = $v;
			}
		}
	}
	return;
}

/* record and check time interval. record: I($name), check: I($name, $interval) */
function I($name = 'interaction', $interval = 0) {
	/* record */
	$name = 'I_'.$name;
	if(0 == $interval) {
		return ASession::set($name, time());
	}

	/* check */
	if(!ASession::get($name)) {
		ASession::set($name, time());
	}
	elseif((ASession::get($name) > time()) or ((time() - ASession::get($name)) < $interval)) {
		return false;
	}
	return true;
}

/* Interval debugging Start */
function debug_start($label = '') {
	$GLOBALS[$label]['_beginTime'] = microtime(true);
	if(MEMORY_ANALYSE) {
		$GLOBALS[$label]['_beginMem'] = memory_get_usage();
	}
}

/* Interval debugging End */
function debug_end($label = '') {
	$GLOBALS[$label]['_endTime'] = microtime(true);
	echo 'Process '.$label.': Times '.number_format($GLOBALS[$label]['_endTime'] - $GLOBALS[$label]['_beginTime'], 6).'s ';
	if(MEMORY_ANALYSE) {
		$GLOBALS[$label]['_endMem'] = memory_get_usage();
		echo ' Memories '.byte_format($GLOBALS[$label]['_endMem'] - $GLOBALS[$label]['_beginMem']);
	}
}

/* format print for debug */
function P($var, $label = '', $return = false) {
	$label = empty($label) ? '' : trim($label).': ';

	if(is_array($var)) {
		$output = print_r($var, true);
	}
	elseif(is_string($var)) {
		$output = $var;
	}
	else {
		ob_start();
		var_dump($var);
		$output = ob_get_contents();
		ob_end_clean();
	}

	if(ini_get('html_errors')) {
		$output = "<pre>".$label.htmlspecialchars($output, ENT_QUOTES)."</pre>";
	}
	else {
		$output = $label.$output;
	}

	if($return) {
		return $output;
	}
	echo($output);
}

/* multiple format print */
function MP() {
	$args = func_get_args();
	if(count($args) < 1) {
		echo L('_NONE_ARGS_');
		return;
	}
	echo "<div><pre>\r\n";
	foreach($args as $arg) {
		P($arg);
	}
	echo "</pre></div>\r\n";
}

/* get object instance */
function get_instance($class, $classArgs = array(), $method = '', $methodArgs = array()) {
	static $_instance = array();
	$identify = empty($classArgs) ? $class : $class.get_guidString($classArgs);
	if(!isset($_instance[$identify])) {
		if(class_exists($class)) {
			$o = new $class($classArgs);
			if(method_exists($o, $method)) {
				if(!empty($args)) {
					$_instance[$identify] = call_user_func_array(array(&$o, $method), $methodArgs);
				}
				else {
					$_instance[$identify] = $o->$method();
				}
			}
			else {
				if('' == $method) {
					$_instance[$identify] = $o;
				}
				else {
					halt(L('_METHOD_INEXISTENCE_', null, array('method' => $method)), true, true);
				}
			}
		}
		else {
			halt(L('_CLASS_INEXISTENCE_', null, array('class' => $class)), true, true);
		}
	}
	return $_instance[$identify];
}

/* autoload class */
function __autoload($className) {
	/* load app's Ctrlr and Modl class */
	if('Modl' == substr($className, -4)) {
		$classfile = LIB_MODL_PATH.D_S.$className.'.class.php';
		require_cache($classfile);
	}
	elseif('Ctrlr' == substr($className, -5)) {
		if(defined('GROUP_NAME')) {
			$classfile = LIB_CTRLR_PATH.D_S.GROUP_NAME.D_S.$className.'.class.php';
			require_cache($classfile);
		}
		if(!file_exists($classfile)) {
			$classfile = LIB_CTRLR_PATH.D_S.$className.'.class.php';
			require_cache($classfile);
		}
	}
	else {
		/* search autoload path */
		$include_path = PFA_EXT_PATH; // PFA extension library
		if(C('APP.AUTOLOAD_PATH')) {
			$include_path .= P_S.str_replace(',', P_S, C('APP.AUTOLOAD_PATH'));
		}
		$paths = explode(P_S, $include_path);
		foreach($paths as $path) {
			if(import($className, $path)) {
				return;
			}
		}
	}
	return;
}

/* import common file(filename replace ['/', '.'] by ['.', '#']) */
function comm($name, $baseUrl = '', $ext = '.php') {
	$name = str_replace(array('.', '#'), array('/', '.'), $name);
	if(empty($baseUrl)) {
		$baseUrl = LIB_COMM_PATH; // default library path
	}
	$baseUrl = rtrim($baseUrl, '/\\').D_S;
	return include_cache($baseUrl.$name.$ext);
}

/* import function library(filename replace ['/', '.'] by ['.', '#']) */
function load($name, $baseUrl = '', $ext = '.php') {
	$name = str_replace(array('.', '#'), array('/', '.'), $name);
	if(empty($baseUrl)) {
		$baseUrl = LIB_COMM_PATH; // default library path
	}
	$baseUrl = rtrim($baseUrl, '/\\').D_S;
	return require_cache($baseUrl.$name.$ext);
}

/* import class(filename replace ['/', '.'] by ['.', '#']) ext autoload */
function import($class, $baseUrl = '', $ext = '.class.php') {
	static $_file = array();
	static $_class = array();
	$class = str_replace(array('.', '#'), array('/', '.'), $class);
	if(isset($_file[$class.$baseUrl])) {
		return true;
	}
	else {
		$_file[$class.$baseUrl] = true;
	}
	if(empty($baseUrl)) {
		$classStrut = explode('/', $class);
		$appName = $classStrut[0];
		if('pfa' == $appName) { // PFA core class
			$baseUrl = PFA_PATH.'/lib/';
			$class = substr_replace($class, '', 0, strlen($appName) + 1);
		}
		elseif('@' == $appName or APP_NAME == $appName) { // current app
			$baseUrl = dirname(LIB_PATH);
			$class = substr_replace($class, 'lib/', 0, strlen($appName) + 1);
		}
		else { // other app
			$baseUrl = APP_PATH.'/../'.$appName.'/'.LIB_DIR.'/';
			$class = substr_replace($class, '', 0, strlen($appName) + 1);
		}
	}
	if(substr($baseUrl, -1) != '/') {
		$baseUrl .= '/';
	}
	$classfile = $baseUrl.$class.$ext;
	if($ext == '.class.php' && is_file($classfile)) {
		/* class conflict detection */
		$class = basename($classfile, $ext);
		if(isset($_class[$class])) {
			halt(L('_CLASS_CONFLICT_', null, array('class' => $class)).' : '.$classfile, true, true);
		}
		$_class[$class] = $classfile;
	}
	return require_cache($classfile);
}

/* import class in vendor dir, (filename replace ['/', '.'] by ['.', '#']) */
function vendor($class, $baseUrl = LIB_VENDOR_PATH, $ext = '.php') {
	return import($class, $baseUrl, $ext);
}

/* optimization include_once */
function include_cache($filename) {
	static $_includeFiles = array();
	$filename = realpath($filename);
	if(!isset($_includeFiles[$filename]) && file_exists($filename)) {
		$_includeFiles[$filename] = include $filename;
	}
	return $_includeFiles[$filename];
}

/* optimization require_once */
function require_cache($filename) {
	static $_importFiles = array();
	$filename = realpath($filename);
	if(!isset($_importFiles[$filename]) && file_exists($filename)) {
		return $_importFiles[$filename] = require $filename;
	}
}

/* dir writable, attempt to create*/
function dir_writable($dir) {
	if(!is_dir($dir)) {
		mk_dir($dir, 0777);
	}
	if(is_dir($dir)) {
		if($fp = @fopen("$dir/test.txt", 'w')) {
			@fclose($fp);
			@unlink(realpath("$dir/test.txt"));
			return true;
		}
	}
	return false;
}

/* create dir(attempt to create parent dir) */
function mk_dir($path, $mode = 0777) {
	//$folder_path = array(strstr($path, '.') ? dirname($path) : $path);
	$folder_path = array($path);

	while(!@is_dir(dirname(end($folder_path))) && dirname(end($folder_path)) != '/' && dirname(end($folder_path)) != '.' && dirname(end($folder_path)) != '') {
		array_push($folder_path, dirname(end($folder_path)));
	}

	while($parent_folder_path = array_pop($folder_path)) {
		if(!@mkdir($parent_folder_path, $mode)) {
			return false;
		}
	}
	return true;
}

/* batch create dir */
function mk_dirs($dirs, $mode = 0777) {
	foreach($dirs as $dir) {
		if(!is_dir($dir)) {
			mk_dir($dir, $mode);
		}
	}
}

/* clear file in dir. $sub:if clear sub dir, $exclude: exclude filename array, $self:if delete self */
function clear_dir($dir, $sub = false, $exclude = array(), $self = false) {
	if(!is_dir($dir)) {
		return true;
	}
	if(false == ($handle = @opendir($dir))) {
		return false;
	}

	while(($file = readdir($handle)) !== false) {
		if('.' == $file || '..' == $file || (!empty($exclude) and in_array($file, $exclude))) {
			continue;
		}
		if(is_dir("$dir/$file")) {
			if($sub and !clear_dir("$dir/$file", true, $exclude, true)) {
				return false;
			}
		}
		else {
			if(!@unlink(realpath("$dir/$file"))) {
				return false;
			}
		}
	}
	if(readdir($handle) == false) {
		closedir($handle);
		if($self and empty($exclude)) {
			if(!@rmdir($dir)) {
				return false;
			}
		}
	}
	return true;
}

/* remove empty directory */
function rm_emptyDir($path) {
	if(is_dir($path) && ($handle = opendir($path)) !== false) {
		while(($file = readdir($handle)) !== false) {
			if($file != '.' && $file != '..') {
				// current directory
				$curfile = $path.'/'.$file;
				if(is_dir($curfile)) {
					rm_emptyDir($curfile);
					// empty directory, =2 for '.' and '..'
					if(count(scandir($curfile)) == 2) {
						rmdir($curfile);
					}
				}
			}
		}
		closedir($handle);
	}
}

/* copy dir. $cover: cover dist, $del: delete src */
function copy_dir($src, $dist, $cover = false, $del = false) {
	if($cover && file_exists($dist)) {
		clear_dir($dist, true, array(), true);
	}
	if(is_dir($src)) {
		mk_dir($dist, 0777);
		$files = scandir($src);
		foreach($files as $file) {
			if($file != '.' && $file != '..') {
				copy_dir("$src/$file", "$dist/$file");
			}
		}
	}
	elseif(file_exists($src)) {
		copy($src, $dist);
	}
	if($del && file_exists($src)) {
		clear_dir($src, true, array(), true);
	}
}

/* converts a relative path to absolute url */
function path_to_url($path) {
	$realpath = str_replace('\\', '/', clean_path($path));
	$root = preg_replace(',/$,', '', $_SERVER['DOCUMENT_ROOT']);
	if(strlen($root) && strpos($realpath, $root) === 0) {
		$url = substr($realpath, strlen($root));
	}
	else {
		$dir = dirname(!empty($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] :
			(!empty($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] :
			(!empty($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : str_replace('\\', '/', __FILE__)
		)));
		$url = clean_path($dir.'/'.$path);
	}
	return (C('URL.HOST_PREFIX') ? __HOST__ : '').$url;
}

/* get the canonical path from a path containing "../" and "./" */
function clean_path($path) {
	$result = array();
	$path = str_replace(array('\\', '//'), '/', $path);
	$pathArray = explode('/', $path);
	if(!$pathArray[0]) {
		$result[] = '';
	}
	foreach($pathArray as $key => $dir) {
		if('..' == $dir) {
			if('..' == end($result)) {
				$result[] = '..';
			}
			elseif(!array_pop($result)) {
				$result[] = '..';
			}
		}
		elseif($dir && '.' != $dir) {
			$result[] = $dir;
		}
	}
	if(!end($pathArray)) {
		$result[] = '';
	}
	return implode('/', $result);
}

/* URL redirect */
function redirect($url, $time = 0, $msg = '') {
	/* deal with multi-line url */
	$url = str_replace(array("\n", "\r"), '', $url);

	if(!headers_sent()) {
		if(0 === $time) {
			header('Location: '.$url);
		}
		else {
			header('refresh: '.$time.'; url='.$url);
			echo ($msg);
		}
		exit();
	}
	else {
		$str = '<meta http-equiv="Refresh" content="'.$time.'; url='.$url.'">';
		if(0 != $time) {
			$str .= $msg;
		}
		exit($str);
	}
}

/* halt print when error */
function halt($error = '', $parseTpl = false, $header404 = false) {
	if($header404) {
		AServer::send_http_status(404);
	}
	if(IS_CLI) {
		exit($error);
	}
	if(C('DEBUG.SWITCH')) {
		if(!is_array($error)) {
			$e = array();
			$traceInfo = '';
			$trace = debug_backtrace();
			$e['message'] = $error;
			$e['file'] = $trace[0]['file'];
			$e['class'] = isset($trace[0]['class']) ? $trace[0]['class'] : '';
			$e['function'] = isset($trace[0]['function']) ? $trace[0]['function'] : '';
			$e['line'] = $trace[0]['line'];
			$time = date('c');
			foreach($trace as $t) {
				$traceInfo .= isset($t['file']) ? '['.$time.'] '.$t['file'].' ('.$t['line'].') ' : '';
				$traceInfo .= isset($t['class']) ? $t['class'] : '';
				$traceInfo .= isset($t['type']) ? $t['type'] : '';
				$traceInfo .= $t['function'].'('.array_to_string($t['args']);
				$traceInfo .= ')<br/>';
			}
			$e['trace'] = $traceInfo;
		}
		else {
			$e = $error;
		}

		if(ob_get_length()) {
			ob_clean();
		}
		include C('TPL.ERR_DEBUG');
		exit();
	}
	else {
		if($parseTpl) {
			$app = A();
			$app->assign('_ERR', $error);
			$app->display(C('TPL.ERR'));
			exit;
		}

		if(file_exists(C('TPL.ERR'))) {
			if(ob_get_length()) {
				ob_clean();
			}
			include C('TPL.ERR');
			exit();
		}
		else {
			exit($error);
		}
	}
}

/* get base language set */
function get_baseLangset() {
	$langset = include PFA_PATH.'/comm/langset.php';
	return $langset;
}

/* get app language set. $enable: filter enable */
function get_langset($enable = true, $dir = '') {
	$items = array();

	$langset = get_baseLangset();
	$_langset = array();
	if(is_file(CFG_PATH.'/langset.php')) {
		$_langset = include(CFG_PATH.'/langset.php');
	}

	if(empty($dir)) {
		$dir = LANG_PATH;
	}

	$langDir = glob(rtrim($dir, '/\\').D_S.'*');
	if(is_array($langDir)) {
		foreach($langDir as $v) {
			if(is_file($v) and '.lang.php' != substr($v, -9)) {
				continue;
			}
			$v = basename($v);
			if('.lang.php' == substr($v, -9)) {
				$v = substr($v, 0, -9);
			}

			/* language name */
			$n = array_key_exists($v, $langset) ? $langset[$v] : $v;

			if(array_key_exists($v, $_langset)) {
				if(is_array($_langset[$v])) {
					if(false === $_langset[$v]['enable'] and $enable) {
						continue;
					}
					$n = isset($_langset[$v]['name']) ? $_langset[$v]['name'] : $n;
				}
				else {
					if(false === $_langset[$v] and $enable) {
						continue;
					}
					$n = !empty($_langset[$v]) ? $_langset[$v] : $n;
				}
			}
			$items[$v] = $n;
		}
	}
	return $items;
}
/* get app platform set */
function get_platformset() {
	$items = array();
	$platformset = array(
		'desktop' => L('_DESKTOP_VERSION_'),
		'tablet' => L('_TABLET_VERSION_'),
		'mobile' => L('_MOBILE_VERSION_'),
		'wml' => L('_WML_VERSION_')
	);
	$_tuab = C('TE.TPL_USER_AGENT_BRANCH');
	foreach($_tuab as $v) {
		$n = array_key_exists($v, $platformset) ? $platformset[$v] : $v;
		$items[] = array('alias' => $v, 'name' => $n);
	}
	return $items;
}

/* get language name from alias */
function get_langName($alias = 'en') {
	$langset = get_langset();
	return array_key_exists($alias, $langset) ? $langset[$alias] : $alias;
}

/* detect device */
function detect_device($name = true) {
	$userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);

	$tabletBrowserList = array('ipad');
	if(strpos_array($userAgent, $tabletBrowserList)) {
		return $name ? 'tablet' : 1; //tablet
	}

	$mobileBrowserList = array('iphone', 'android', 'phone', 'mobile', 'wap', 'netfront', 'java', 'opera mobi', 'opera mini', 'ucweb',
		'windows ce', 'symbian', 'series', 'webos', 'sony', 'blackberry', 'dopod', 'nokia', 'samsung', 'palmsource', 'xda', 'pieplus',
		'meizu', 'midp', 'cldc', 'motorola', 'foma', 'docomo', 'up.browser', 'up.link', 'blazer', 'helio', 'hosin', 'huawei', 'novarra',
		'coolpad', 'webos', 'techfaith', 'palmsource', 'alcatel', 'amoi', 'ktouch', 'nexian', 'ericsson', 'philips', 'sagem', 'wellcom',
		'bunjalloo', 'maui', 'smartphone', 'iemobile', 'spice', 'bird', 'zte-', 'longcos', 'pantech', 'gionee', 'portalmmm', 'jig browser',
		'hiptop', 'benq', 'haier', '^lct', '320x320', '240x320', '176x220', 'windows phone');
	if(($v = strpos_array($userAgent, $mobileBrowserList))) {
		return $name ? 'mobile' : 2; //mobile
	}

	$wmlBrowserList = array('cect', 'compal', 'ctl', 'lg', 'nec', 'tcl', 'alcatel', 'ericsson', 'bird', 'daxian', 'dbtel', 'eastcom',
		'pantech', 'dopod', 'philips', 'haier', 'konka', 'kejian', 'lenovo', 'benq', 'mot', 'soutec', 'nokia', 'sagem', 'sgh', 'sed',
		'capitel', 'panasonic', 'sonyericsson', 'sharp', 'amoi', 'panda', 'zte');
	if(($v = strpos_array($userAgent, $wmlBrowserList))) {
		return $name ? 'wml' : 3; //wml
	}

	$brower = array('mozilla', 'chrome', 'safari', 'opera', 'm3gate', 'winwap', 'openwave', 'myop');
	if(strpos_array($userAgent, $brower)) {
		return $name ? 'desktop' : 0; //desktop
	}

	return $name ? '' : -1;
}

/* detect os */
function detect_os() {
	$os = array('name' => '', 'version' => '');

	$agent = $_SERVER['HTTP_USER_AGENT'];
	if(empty($agent)) {
		return $os;
	}

	$osList = array();
	$osList['/windows nt 10/i'] = array('name' => 'Windows', 'version' => '10');
	$osList['/windows nt 6.3/i'] = array('name' => 'Windows', 'version' => '8.1');
	$osList['/windows nt 6.2/i'] = array('name' => 'Windows', 'version' => '8');
	$osList['/windows nt 6.1/i'] = array('name' => 'Windows', 'version' => '7');
	$osList['/windows nt 6.0/i'] = array('name' => 'Windows', 'version' => 'Vista');
	$osList['/windows nt 5.2/i'] = array('name' => 'Windows Server', 'version' => '2003/XP x64');
	$osList['/windows nt 5.1/i'] = array('name' => 'Windows', 'version' => 'XP');
	$osList['/windows xp/i'] = array('name' => 'Windows', 'version' => 'XP');
	$osList['/windows nt 5.0/i'] = array('name' => 'Windows', 'version' => '2000');
	$osList['/windows me/i'] = array('name' => 'Windows', 'version' => 'ME');
	$osList['/win98/i'] = array('name' => 'Windows', 'version' => '98');
	$osList['/win95/i'] = array('name' => 'Windows', 'version' => '95');
	$osList['/win16/i'] = array('name' => 'Windows', 'version' => '3.11');
	$osList['/macintosh|mac os x/i'] = array('name' => 'Mac OS', 'version' => 'X');
	$osList['/mac_powerpc/i'] = array('name' => 'Mac OS', 'version' => '9');
	$osList['/ipod/i'] = array('name' => 'iPod', 'version' => '');
	$osList['/ipad/i'] = array('name' => 'iPad', 'version' => '');
	$osList['/iphone/i'] = array('name' => 'iPhone', 'version' => '');
	$osList['/android/i'] = array('name' => 'Android', 'version' => '');
	$osList['/blackberry/i'] = array('name' => 'BlackBerry', 'version' => '');
	$osList['/webos/i'] = array('name' => 'Mobile', 'version' => '');
	$osList['/ubuntu/i'] = array('name' => 'Ubuntu', 'version' => '');
	$osList['/linux/i'] = array('name' => 'Linux', 'version' => '');

	foreach ($osList as $regex => $_os) { 
		if(preg_match($regex, $agent)) {
			return $_os;
		}
	}

	return $os;
}

/* detect browser */
function detect_browser() {
	$browser = array('name' => '', 'version' => '');

	$agent = $_SERVER['HTTP_USER_AGENT'];
	if(empty($agent)) {
		return $browser;
	}

	/* Chrome should checked before safari.*/
	if(strpos($agent, 'Firefox') !== false) {
		$browser['name'] = 'Firefox';
	}
	if(strpos($agent, 'Opera') !== false) {
		$browser['name'] = 'Opera';
	}
	if(strpos($agent, 'Safari') !== false) {
		$browser['name'] = 'Safari';
	}
	if(strpos($agent, 'Chrome') !== false) {
		$browser['name'] = 'Chrome';
	}
	if(strpos($agent, 'MSIE') !== false || strpos($agent, 'rv:11.0')) {
		$browser['name'] = 'IE';
	}
	if(strpos($agent, 'Edge') !== false) {
		$browser['name'] = 'Edge';
	}

	// Check the version of browser
	if(preg_match('/MSIE\s(\d+)\..*/i', $agent, $regs)) {
		$browser['version'] = $regs[1];
	}
	if(preg_match('/FireFox\/(\d+)\..*/i', $agent, $regs)) {
		$browser['version'] = $regs[1];
	}
	if(preg_match('/Opera[\s|\/](\d+)\..*/i', $agent, $regs)) {
		$browser['version'] = $regs[1];
	}
	if(preg_match('/Chrome\/(\d+)\..*/i', $agent, $regs)) {
		$browser['version'] = $regs[1];
	}
	if((strpos($agent, 'Chrome') == false) && preg_match('/Safari\/(\d+)\..*$/i', $agent, $regs)) {
		$browser['version'] = $regs[1];
	}
	if(preg_match('/rv:(\d+)\..*/i', $agent, $regs)) {
		$browser['version'] = $regs[1];
	}
	if(preg_match('/Edge\/(\d+)\..*/i', $agent, $regs)) {
		$browser['version'] = $regs[1];
	}

	return $browser;
}

/* Generate a unique identification number from each type variable */
function get_guidString($mix) {
	if(is_object($mix) && function_exists('spl_object_hash')) {
		return spl_object_hash($mix);
	}
	elseif(is_resource($mix)) {
		$mix = get_resource_type($mix).strval($mix);
	}
	else {
		$mix = serialize($mix);
	}
	return md5($mix);
}

/* name style conversion 0:AaaBbb -> aaa_bbb, 1:aaa_bbb -> AaaBbb */
function parse_name($name, $type = 0) {
	if($type) {
		return ucfirst(preg_replace_callback("/_([a-zA-Z])/", '_parse_name', $name));
	}
	else {
		return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
	}
}
function _parse_name($matches) {
	return strtoupper($matches[1]);
}

/* remove white space and comments in the code */
function strip_whitespace($content) {
	$stripStr = '';

	/* Analysis php code */
	$tokens = token_get_all($content);
	$last_space = false;
	for($i = 0, $j = count($tokens); $i < $j; $i++) {
		if(is_string($tokens[$i])) {
			$last_space = false;
			$stripStr .= $tokens[$i];
		}
		else {
			switch($tokens[$i][0]) {
					/* remove comment */
				case T_COMMENT:
				case T_DOC_COMMENT:
					break;
					/* remove surplus whitespace */
				case T_WHITESPACE:
					if(!$last_space) {
						$stripStr .= ' ';
						$last_space = true;
					}
					break;
				case T_START_HEREDOC:
					$stripStr .= "<<<PFA\r\n";
					break;
				case T_END_HEREDOC:
					$stripStr .= "PFA;\r\n";
					for($k = $i + 1; $k < $j; $k++) {
						if(is_string($tokens[$k]) && $tokens[$k] == ';') {
							$i = $k;
							break;
						}
						else {
							if($tokens[$k][0] == T_CLOSE_TAG) {
								break;
							}
						}
					}
					break;
				default:
					$last_space = false;
					$stripStr .= $tokens[$i][1];
			}
		}
	}
	return $stripStr;
}

/* format byte to B KB MB GB TB */
function byte_format($size, $dec = 2) {
	$a = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
	$pos = 0;
	while($size >= 1024) {
		$size /= 1024;
		$pos++;
	}
	return round($size, $dec).' '.$a[$pos];
}

/* humane time format */
function get_dateStr($dateline) {
	$timeDif = intval(time() - $dateline);
	$now = getdate();
	$todayPassTime = $now['seconds'] + $now['minutes'] * 60 + $now['hours'] * 60 * 60;

	if($timeDif < 0) {
		return L('_IN_THE_FUTURE_');
	}
	elseif($timeDif < 60) {
		$timeDif = $timeDif == 0 ? 1 : $timeDif;
		return L('_SECOND_AGO_', null, array('time' => $timeDif));
	}
	elseif($timeDif < 3600) {
		$timeDif = intval($timeDif / 60);
		return L('_MINUTE_AGO_', null, array('time' => $timeDif));
	}
	elseif($timeDif < $todayPassTime) {
		$timeDif = intval($timeDif / 3600);
		return L('_HOUR_AGO_', null, array('time' => $timeDif));
	}
	elseif($timeDif < $todayPassTime + 3600 * 24) {
		return L('_YESTERDAY_').date(' H:i:s', $dateline);
	}
	elseif($timeDif < 3600 * 24 * 7) {
		$timeDif = intval($timeDif / 3600 / 24);
		return L('_DAY_AGO_', null, array('time' => $timeDif));
	}
	return date(C('APP.TIME_FORMAT'), $dateline);
}

/* second format */
function second_format($second) {
	$years = floor($second / (3600*24*365));

	$second = $second % (3600*24*365);
	$months = floor($second / (3600*24*30));

	$second = $second % (3600*24*30);
	$weeks = floor($second / (3600*24*7));

	$second = $second % (3600*24*7);
	$days = floor($second / (3600*24));

	$second = $second % (3600*24);
	$hours = floor($second / 3600);

	$second = $second % 3600;
	$minutes = floor($second / 60);
	$seconds = ($second % 60);

	return ($years > 0 ? $years.L('_YEARS_') : '')
		. ($months > 0 ? $months.L('_MONTHS_') : '')
		. ($weeks > 0 ? $weeks.L('_WEEKS_') : '')
		. ($days > 0 ? $days.L('_DAYS_') : '')
		. ($hours > 0 ? $hours.L('_HOURS_') : '')
		. ($minutes > 0 ? $minutes.L('_MINUTES_') : '')
		. ($seconds > 0 ? $seconds.L('_SECONDS_') : '');
}

/* hide ip */
function hide_ip($ip, $startNum = 2) {
	$pattern = "/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/i";
	preg_match($pattern, $ip, $ipArr);
	if(!empty($ipArr)) {
		$ip = array_slice($ipArr, 1, $startNum);
		for($i = $startNum; $i < 4; $i++) {
			$ip[] = '*';
		}
		$ip = implode('.', $ip);
	}
	return $ip;
}

/* remove string from array */
function trim_array($array, $charList = '') {
	if(0 == strlen($charList)) {
		foreach($array as $k => $v) {
			$array[$k] = trim($v);
		}
	}
	else {
		foreach($array as $k => $v) {
			$array[$k] = trim($v, $charList);
		}
	}
	return $array;
}

/* array multi dimension unique */
function marray_unique($marray, $sort = true) {
	if($sort) {
		foreach($marray as $key => $item) {
			ksort($marray[$key]);
		}
	}
	return array_map('unserialize', array_unique(array_map('serialize', $marray)));
}

/* array multi merge */
function marray_merge($array1, $array2) {
	if(is_array($array2) && count($array2)) {
		foreach($array2 as $k => $v) {
			if(is_array($v) && count($v)) {
				$array1[$k] = marray_merge($array1[$k], $v);
			}
			else {
				$array1[$k] = $v;
			}
		}
	}
	else {
		$array1 = $array2;
	}
	return $array1;
}

/* addslashes for array */
function addslashes_array($array) {
	if(is_array($array)) {
		foreach($array as $n => $v) {
			$b[$n] = addslashes_array($v);
		}
		return $b;
	}
	else {
		return addslashes($array);
	}
}

/* strip slashes for array */
function stripslashes_array($array) {
	$array = is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
	return $array;
}

/* array to string $level: parse level */
function array_to_string($array, $glue = ', ', $level = 1) {
	if(!is_array($array) || empty($array)) {
		return '';
	}
	$string = '';
	foreach($array as $k => $v) {
		if(0 != $level) {
			if(is_array($v)) {
				$string .= 'array(';
				$string .= array_to_string($v, $glue, $level - 1).$glue;
				$string = rtrim($string, $glue).')'.$glue;
			}
			else {
				$string .= $v.$glue;
			}
		}
	}
	$string = rtrim($string, $glue);
	return $string;
}

/* strpos array */
function strpos_array($string, $array = array(), $return = false) {
	if(empty($string)) {
		return false;
	}
	foreach($array as $v) {
		if(strpos($string, $v) !== false) {
			return $return ? $v : true;
		}
	}
	return false;
}

/* unserialize not object */
function deserialize($string, $default = '') {
	if('o:' == strtolower(substr($string, 0, 2))) {
		return $default;
	}
	$mixed = unserialize($string);
	return false !== $mixed ? $mixed : $default;
}

/* conversion base */
function conv_base($numberInput, $fromBaseInput = '0123456789', $toBaseInput = '0123456789abcdef') {
	if($fromBaseInput == $toBaseInput) {
		return $numberInput;
	}
	$fromBase = str_split($fromBaseInput, 1);
	$toBase = str_split($toBaseInput, 1);
	$number = str_split($numberInput, 1);
	$fromLen = strlen($fromBaseInput);
	$toLen = strlen($toBaseInput);
	$numberLen = strlen($numberInput);
	$retval = '';
	if($toBaseInput == '0123456789') {
		$retval = 0;
		for($i = 1;$i <= $numberLen; $i++) {
			$retval = bcadd($retval, bcmul(array_search($number[$i-1], $fromBase),bcpow($fromLen, $numberLen-$i)));
		}
		return $retval;
	}
	if($fromBaseInput != '0123456789') {
		$base10 = conv_base($numberInput, $fromBaseInput, '0123456789');
	}
	else {
		$base10 = $numberInput;
	}
	if($base10 < strlen($toBaseInput)) {
		return $toBase[$base10];
	}
	while($base10 != '0') {
		$retval = $toBase[bcmod($base10,$toLen)].$retval;
		$base10 = bcdiv($base10,$toLen,0);
	}
	return $retval;
}

/* define gzdecode */
if(!function_exists('gzdecode')) {
	function gzdecode ($data) {
		$flags = ord(substr($data, 3, 1));
		$headerlen = 10;
		$extralen = 0;
		$filenamelen = 0;
		if($flags & 4) {
			$extralen = unpack('v' ,substr($data, 10, 2));
			$extralen = $extralen[1];
			$headerlen += 2 + $extralen;
		}
		if($flags & 8) { // Filename
			$headerlen = strpos($data, chr(0), $headerlen) + 1;
		}
		if($flags & 16) { // Comment
			$headerlen = strpos($data, chr(0), $headerlen) + 1;
		}
		if($flags & 2) { // CRC at end of file
			$headerlen += 2;
		}
		$unpacked = @gzinflate(substr($data, $headerlen));
		if($unpacked === false) {
			$unpacked = $data;
		}
		return $unpacked;
	}
}

//[RUNTIME]
/* compile file */
function compile($filename) {
	$content = file_get_contents($filename);
	/* replace pre-compile directive */
	$content = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);
	$content = substr(trim($content), 5);
	if('?>' == substr($content, -2)) {
		$content = substr($content, 0, -2);
	}
	return $content;
}

/* define constant form array */
function array_define($array) {
	$content = '';
	foreach($array as $key => $val) {
		$key = strtoupper($key);
		$content .= 'if(!defined(\''.$key.'\')) ';
		if(is_int($val) || is_float($val)) {
			$content .= "define('".$key."',".$val.");";
		}
		elseif(is_bool($val)) {
			$val = ($val) ? 'true' : 'false';
			$content .= "define('".$key."',".$val.");";
		}
		elseif(is_string($val)) {
			$content .= "define('".$key."','".addslashes($val)."');";
		}
	}
	return $content;
}
//[/RUNTIME]
?>