<?php

if(! defined('OT_ROOT')) {
	exit('Access Denied');
}


class OT{

	public static function ParaArr($str){
		switch ($str){
			case 'mudi':	return array('m','mudi');
			case 'id':		return array('id','dataID');
			case 'userID':	return array('uid','userID');
			default :		die('OT::ParaArr 参数错误');
		}
	}

	public static function Get($str,$defStr=''){
		if (isset($_GET[$str])){
			if ( is_null($_GET[$str]) ){
				return $defStr;
			}else{
				return $_GET[$str];
			}
		}else{
			return $defStr;
		}
	}

	public static function GetNum($str,$defNum=0){
		return self::ToNum(trim(self::Get($str)),$defNum);
	}

	public static function GetInt($str,$defNum=0){
		return self::ToInt(trim(self::Get($str)),$defNum);
	}

	public static function GetInt2($strArr,$def=0){
		foreach ($strArr as $val){
			$retStr = self::GetInt($val,$def);
			if ($retStr != $def){
				return $retStr;
			}
		}
		return $retStr;
	}

	public static function GetFloat($str){
		return floatval(self::Get($str));
	}

	public static function GetStr($str){
		return trim(self::Get($str));
	}

	public static function GetStr2($strArr,$def=''){
		foreach ($strArr as $val){
			$retStr = self::GetStr($val,$def);
			if ($retStr != $def){
				return $retStr;
			}
		}
		return $retStr;
	}

	public static function GetReplaceStr($str,$repType){
		return Str::MoreReplace(self::Get($str),$repType);
	}

	public static function GetRegExpStr($str,$repType){
		return Str::RegExp(self::Get($str),$repType);
	}


	public static function Post($str,$defStr=''){
		if (isset($_POST[$str])){
			if ( is_null($_POST[$str]) ){
				return $defStr;
			}else{
				return $_POST[$str];
			}
		}else{
			return $defStr;
		}
	}

	public static function PostNum($str,$defNum=0){
		return self::ToNum(trim(self::Post($str)),$defNum);
	}

	public static function PostInt($str,$defNum=0){
		return self::ToInt(trim(self::Post($str)),$defNum);
	}

	public static function PostInt2($strArr,$def=0){
		foreach ($strArr as $val){
			$retStr = self::PostInt($val,$def);
			if ($retStr != $def){
				return $retStr;
			}
		}
		return $retStr;
	}

	public static function PostFloat($str){
		return floatval(self::Post($str));
	}

	public static function PostStr($str){
		return trim(self::Post($str));
	}

	public static function PostStr2($strArr,$def=''){
		foreach ($strArr as $val){
			$retStr = self::PostStr($val,$def);
			if ($retStr != $def){
				return $retStr;
			}
		}
		return $retStr;
	}

	public static function PostRStr($str){
		return rtrim(self::Post($str));
	}

	public static function PostReplaceStr($str,$repType){
		return Str::MoreReplace(self::Post($str),$repType);
	}

	public static function PostRegExpStr($str,$repType){
		return Str::RegExp(self::Post($str),$repType);
	}

	public static function PostArrStr($str,$defStr=''){
		$postArr = self::Post($str);
		if (is_array($postArr)){ $postArr = implode($defStr,$postArr); }
		return $postArr;
	}


	// POST获取值
	public static function PostTypeVal($name,$type){
		switch ($type){
			case '多选': case 'checkbox':
				$value = OT::PostArrStr($name);
				break;
		
			case '整数': case 'int':
				$value = OT::PostInt($name);
				break;
		
			case '小数': case 'decimal':
				$value = OT::PostFloat($name);
				break;
		
			case '编辑器': case 'editor':
				$value = Adm::FilterEditor(OT::PostStr($name));
				break;
		
			default :
				$value = OT::PostStr($name);
				break;
		}
		return $value;
	}

	//***** 获取参数 END *****


	public static function ToNum($str,$deStr=0){
		if (is_numeric($str)==false){
			return $deStr;
		}else{
			return $str;
		}
	}

	public static function ToInt($str,$deStr=0){
		if (is_numeric($str)==false){
			return $deStr;
		}else{
			return intval($str);
		}
	}

	public static function ToFloat($num,$decNum=2){
		if (is_numeric($num)==false){
			return 0;
		}else{
			return floatval(number_format((double)$num,$decNum,'.',''));
		}
	}

	// float类型数值比较大小专用，浮点类型不能直接用==比较 $float1 > $float2 = 1
	public static function FloatCmp($float1,$float2,$decNum=2){
		$float1 = number_format((double)$float1,$decNum,'.','');
		$float2 = number_format((double)$float2,$decNum,'.','');
		if ($float1 == $float2){
			return 0;
		}elseif ($float1 > $float2){
			return 1;
		}else{
			return -1;
		}
	}

	// 数值格式化
	public static function NumFormat($num,$decNum=2){
		return number_format((double)$num,$decNum,'.','');
	}

	// 获取范围内的数字随机数
	public static function RndNumTo($minNum, $maxNum){
		if ($minNum > $maxNum){
			$temp = $minNum;
			$minNum = $maxNum;
			$maxNum = $temp;
		}
		@mt_srand();
		return mt_rand($minNum, $maxNum);
	}

	// 成功概率 小于等于$rate 为真，反之为假
	public static function SuccRate($rate){
		if ($rate == 100){
			return true;
		}elseif ($rate == 0){
			return false;
		}else{
			$num = self::RndNumTo(0,100);
			if ($num <= $rate){
				return true;
			}else{
				return false;
			}
		}
	}

	// 获取随机数
	// 33~47：!"#$%&'()*+,-./
	// 48~57：0123456789
	// 58~64：:;<=>?@
	// 65~90：ABCDEFGHIJKLOMNOPQRSTUVWXYZ
	// 91~96：[\]^_`
	// 97~122：abcdefghijklmnopqrstuvwxyz
	// 123~126：{|}~
	// 数值随机数
	public static function RndNum($length){
		$output='';
		for ($a=0; $a<$length; $a++){
			@mt_srand();
			$output .= chr(mt_rand(48, 57));    //生成php随机数
		}
		return $output;
	}

	// 字符随机数
	public static function RndChar($length,$type=''){
		$output = '';
		if ($type == 'num'){
			$charArr = array('1','2','3','4','5','6','7','8','9');
		}elseif ($type == 'abc'){
			$charArr = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','p','q','r','s','t','u','v','w','x','y','z');
		}elseif ($type == 'ABC'){
			$charArr = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z');
		}elseif ($type == 'abcABC'){
			$charArr = array(
				'A','B','C','D','E','F','G','H','I','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z',
				'a','b','c','d','e','f','g','h','i','j','k','l','m','n','p','q','r','s','t','u','v','w','x','y','z'
				);
		}else{
			$charArr = array(
				'1','2','3','4','5','6','7','8','9',
				'A','B','C','D','E','F','G','H','I','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z',
				'a','b','c','d','e','f','g','h','i','j','k','l','m','n','p','q','r','s','t','u','v','w','x','y','z'
				);
		}

		$charCount = count($charArr)-1;
		for ($a=0; $a<$length; $a++){
			@mt_srand();
			$output .= $charArr[mt_rand(0, $charCount)];
		}
		return $output;
	}

	// 字母随机数（废弃，后期删除）
	public static function RndABC($length){
		return self::RndChar($length, 'abcABC');
	}

	// html转换成js
	public static function HtmlToJs($contentStr){
		$contentStr = str_replace(array('\\','/','\'','"'), array('\\\\','\\/','\\\'','\\"'), $contentStr);
		$contentStr = implode("\");". PHP_EOL ."document.writeln(\"", explode(PHP_EOL, $contentStr));
		$contentStr = "document.writeln(\"". str_replace(array("\r","\n"),array('',''),$contentStr) ."\");";
		return $contentStr;
	}

	// js转换成html
	public static function JsToHtml($contentStr){
		$contentStr = str_replace(array('document.writeln(\"','");','\\"','\\\'','\\/','\\\\'), array('','','"','\'','/','\\'), $contentStr);
		return $contentStr;
	}

	// 获取xml某个元素
	public static function GetXmlItem($contentStr,$mark){
		$retStr = Str::Filter(Str::GetMark($contentStr, '<'. $mark .'>', '</'. $mark .'>'), 'xml');
		return $retStr;
	}

	// 对象数组转为普通数组
	public static function ObjToArr($objStr) {
		if(is_object($objStr)){ $objStr = get_object_vars($objStr); }
		if(is_array($objStr)){ foreach($objStr as $k=>$v) $objStr[$k] = self::ObjToArr($v); }
		return $objStr;
	}

	// XML转为数组
	public static function XmlToArr($xml) {
		if(! $xml){ return false; }
		// 将XML转为array
		// 禁止引用外部xml实体
		$disableLibxmlEntityLoader = libxml_disable_entity_loader(true); //改为这句
		$retArr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
		libxml_disable_entity_loader($disableLibxmlEntityLoader); //添加这句
		return $retArr;
	}

	// 数组转为XML
	public static function ArrToXml($arr){
		if(! is_array($arr) || count($arr) <= 0){ return false; }
    	
    	$xml = '<xml>';
    	foreach ($arr as $key=>$val)
    	{
    		if (is_numeric($val)){
    			$xml .= '<'. $key .'>'. $val .'</'. $key .'>';
    		}else{
    			$xml .= '<'. $key .'><![CDATA['. $val .']]></'. $key .'>';
    		}
        }
        $xml .= '</xml>';
        return $xml; 
	}

	// 数组转为网址参数
	public static function ArrToUrlParam($arr, $skipArr=array()){
		$retStr = '';
		foreach ($arr as $key => $val){
			if( (! in_array($key,$skipArr)) && $val != '' && (! is_array($val)) ){
				$retStr .= $key .'='. $val .'&';
			}
		}
		
		$retStr = trim(''. $retStr, '&');
		return $retStr;
	}

	// URL参数编码
	public static function UrlEn($str){
		$retStr = urlencode($str);
		$retStr = str_replace(array('+','_','.','-','~'), array('%20','%5F','%2E','%2D','%7E'), $retStr);
		return $retStr;
	}

	// GET请求参数
	public static function GetParam($skipArr=array(), $addArr=array(), $headUrl=''){
		$retStr = $headUrl;
		if (count($addArr) > 0){
			foreach($addArr as $key => $value){
				$skipArr[] = $key;
			}
		}
		foreach($_GET as $key => $value){
			if (in_array($key,$skipArr)==false && is_string($key) && is_string($value)){
				$retStr .= self::ParamSign($retStr) . urlencode(Str::RegExp($key,'sql2')) .'='. self::UrlEn($value);	// Str::RegExp(,'sql2')
			}
		}
		foreach($addArr as $key => $value){
			$retStr .= self::ParamSign($retStr) . urlencode(Str::RegExp($key,'sql2')) .'='. (in_array($value,array('[page]')) ? $value : self::UrlEn($value));	// Str::RegExp(,'sql2')
		}
		if (strlen($retStr) == 0 && $headUrl != 'no'){
			$retStr = basename(GetUrl::HttpSelf());
		}
		return $retStr;
	}

	// 判断网址参数连接符
	public static function ParamSign($url=''){
		if (strpos($url,'?') !== false){
			return '&amp;';
		}else{
			return '?';
		}
	}

	// 密码解密
	public static function DePwdData($str, $mode, $key){
		switch ($mode){
			case 'dz':	return base64_decode( str_replace( array('-','_'), array('+','/'), Encrypt::AuthCode($str, 'DECODE', $key .'otcms.com,idccms.com') ) );
			default :	return $str;
		}
	}

	// IP地址隐藏化
	public static function IpHidden($str){
		return substr($str,0,strrpos($str,'.')) .'.*';
	}

	public static function GetIpInfoArr($refIP='',$defNull='缺少IP库'){
		if ($refIP==''){ $refIP = Users::GetIp(); }

		if (in_array($refIP,array('127.0.0.1','::1'))){
			$infoArr = array(
				'res'		=> true,
				'ip'		=> $refIP,
				'city'		=> '本地',
				'address'	=> '本地',
				);
			return $infoArr;
		}

		global $systemArr;

		$datPath = OT_ROOT .'tools/ip.dat';
		$czdbPath = OT_ROOT .'tools/cz88_public_v4.czdb';

		if ($systemArr['SYS_ipFileMode'] == 1){
			if ( file_exists($datPath) ){
				$ipobj = new IpInfo();
				// if ($refIP==''){ $refIP = $ipobj->getIP(); }

				$addrArr = $ipobj->getaddress($refIP);
				$infoArr = array(
					'res'		=> true,
					'ip'		=> $refIP,
					'city'		=> $addrArr['area1'],
					'address'	=> $addrArr['area1'] .' '. $addrArr['area2'],
					);
			
			}else{
				$defNull .= 'dat';
				$infoArr = array(
					'res'		=> false,
					'ip'		=> $refIP,
					'city'		=> $defNull,
					'address'	=> $defNull,
					);

			}
		
		/*
		}elseif ($systemArr['SYS_ipFileMode'] == 2){
			if ( file_exists($czdbPath) ){
				$ipCzdb = new IpCzdb($czdbPath, "BTREE", $systemArr['SYS_ipFileKey']);

				$ipArr = $ipCzdb->search($refIP);

				echo "搜索结果：\n";
				print_r($ipArr);
				die();

				$ipCzdb->close();
			}else{
				$defNull .= 'czdb';
				$infoArr = array(
					'res'		=> false,
					'ip'		=> $refIP,
					'city'		=> $defNull,
					'address'	=> $defNull,
					);

			}
			*/

		}elseif ($systemArr['SYS_ipFileMode'] == 0){
			$defNull = 'IP库设置:关闭';
			$infoArr = array(
				'res'		=> false,
				'ip'		=> $refIP,
				'city'		=> $defNull,
				'address'	=> $defNull,
				);

		}else{
			$infoArr = array(
				'res'		=> false,
				'ip'		=> $refIP,
				'city'		=> $defNull,
				'address'	=> $defNull,
				);

		}

		return $infoArr;
	}


	// 兼容each函数，php 7.2弃用each
	public static function NewEach(&$array){
		$res = array();
		$key = key($array);
		if($key !== null){
			next($array); 
			$res[1] = $res['value'] = $array[$key];
			$res[0] = $res['key'] = $key;
		}else{
			$res = false;
		}
		return $res;
	}


	// 兼容count函数，php 7.2苛刻化
	public static function NewCount($array, $mode = COUNT_NORMAL){
		$res = 0;
		if(is_array($array) || is_object($array)){
			$res = count($array, $mode);
		}
		return $res;
	}


	// Unix时间戳转日期
	public static function NewToDatetime($unixtime, $timezone = 'PRC') {
		$datetime = new DateTime("@$unixtime");		// DateTime类的bug，加入@可以将Unix时间戳作为参数传入
		$datetime->setTimezone(new DateTimeZone($timezone));
		return $datetime->format("Y-m-d H:i:s");
	}
	 
	// 日期转Unix时间戳
	public static function NewStrtotime($date, $timezone = 'PRC') {
		$datetime= new DateTime($date, new DateTimeZone($timezone));
		return $datetime->format('U');
	}


	// 检查是否具目录可执行
	public static function TestPhpRun($pathDir, $siteUrl, $event = '') {
		$testStr = '<'. chr(0x3F) .'p'. chr(hexdec(68)) . chr(112) ."\r\n";
		$fileName = 'testOtcmsRun.php';	// md5($pathDir) .
		$rndStr = OT::RndChar(8);
		$testStr .= 'echo \'[\'. md5(\''. $rndStr .'\') .\']&ensp;&ensp;警告！该目录可以运行PHP文件，有执行权限\';'."\r\n";
		$testStr .= chr(0x3F).'>';

		$retArr = array('res'=>false, 'code'=>-1, 'note'=>'');
		if (is_writable($pathDir)) {
			if (! File::Write($pathDir . $fileName, $testStr, false, $errStr)){
				$retArr = array('res'=>false, 'code'=>2, 'note'=>'创建文件（'. $pathDir . $fileName .'）失败');
			}else{
				if (strpos($event,'|noCheck|') === false){
					$remoteUrl = $siteUrl . str_replace(OT_ROOT, '', str_replace("\\", '/',realpath($pathDir))) .'/'. $fileName;
					$tempStr = @ReqUrl::UseAuto(0,'get',$remoteUrl);
					if (strpos(trim(''. $tempStr), '['. md5($rndStr) .']') === false){
						$retArr = array('res'=>false, 'code'=>9, 'note'=>'内容不匹配，没有执行权限');
					}else{
						$retArr = array('res'=>true, 'code'=>0, 'note'=>'有执行权限');
					}
				}else{
					$retArr = array('res'=>true, 'code'=>0, 'note'=>'写入文件（'. $pathDir . $fileName .'）成功');
				}
				if (strpos($event,'|noDel|') === false){
					unlink($pathDir . $fileName);
				}
			}
		}else{
			$retArr = array('res'=>false, 'code'=>1, 'note'=>'该目录（'. $pathDir .'）没有写入权限');
		}
		return $retArr;
	}

	// 获取服务器外网IP
	public static function GetServIp(){
		/*
		$ch = curl_init('http://2019.ip138.com/ic.asp');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		$a = curl_exec($ch);
		*/
		$a = file_get_contents('http://2019.ip138.com/ic.asp');
		preg_match('/\[(.*)\]/', $a, $ip);
		return $ip[1];
	}

	// 获取最大天数
	public static function GetMaxTimeDay($startDate=''){
		if (empty($startDate) || (! strtotime($startDate))){
			$startDate = TimeDate::Get('date');
		}
		return TimeDate::Diff('d',$startDate,'2038-01-01');	// 2029-12-31
	}

	// 获取网站tools/字体绝对路径
	public static function GetSiteFontAbsPath(){
		$retStr = '';
		$extArr = array('otf','ttf','ttc');
		foreach ($extArr as $val){
			$path = OT_ROOT .'tools/simsun.'. $val;
			if (file_exists($path)){
				$retStr = $path;
				break;
			}
		}
		return $retStr;
	}

	// 获取网站字体绝对路径
	public static function GetFontAbsPath(){
		$retStr = self::GetSiteFontAbsPath();
		if (strlen($retStr) == 0){
			if (strpos(strtolower(PHP_OS), 'win') !== false){
				$path = 'C:\WINDOWS\Fonts\simsun.ttc';
			//}else{
				//$path = '/usr/share/fonts/simsun.ttc';
				if (file_exists($path)){ $retStr = $path; }
			}
		}
		// $retStr = '';
		return $retStr;
	}


	/**
	* 截断字符串，保持固定的暂用字节长度
	* @param string $sStr 源字符串
	* @param int $iMaxLen 保留字节长度
	* @param string $sRepStr 替换字符串
	* @return string
	*/
	static public function CutStrKeepByte($sStr, $iMaxLen, $sRepStr='...'){
		$iReplen = strlen($sRepStr);
		if (strlen($sStr) > $iMaxLen){ //字节数数超长，需要裁剪
			$iMaxLen -= $iReplen; //保留拖尾替换字符长度
			$aBuf = array();
			$iByteLen = 0;
			for ($i=0,$iLoop=mb_strlen($sStr); $i<$iLoop; $i++){
				$sChr = mb_substr($sStr, $i, 1); //每次取一个字
				if (($iByteLen + strlen($sChr)) <= $iMaxLen){ //未到执行长度，继续追加
					$aBuf[] = $sChr;
					$iByteLen += strlen($sChr); //长度计数
				}else{ //长度符合结束提取
					return implode($aBuf) . $sRepStr;
				}
			}
		}
		return $sStr; //原样返回
	}

	/**
	* 清理字符串内的utf8mb4字符集
	* @param string $sSrc 原始数据
	* @param string $sReplace 替换符
	* @return string
	*/
	static public function ClearUtf8mb4($sSrc, $sReplace='?'){
		return preg_replace(
			'%(?:
			\xF0[\x90-\xBF][\x80-\xBF]{2}        # planes 1-3
			| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
			| \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
			)%xs', $sReplace, $sSrc);
	}

	/**
	* 检查是否包含utf8mb4字符集
	* @param string $sSrc 原始数据
	* @return bool
	*/
	static public function IsExistUtf8mb4($sSrc){
		return preg_match(
			'%(?:
			\xF0[\x90-\xBF][\x80-\xBF]{2}        # planes 1-3
			| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
			| \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
			)%xs', $sSrc) > 0;
	}

	// 默认值
	public static function DefVal($str){
		switch ($str){
			case 'date':		return '2008-08-08';
			case 'datetime':	return '2008-08-08 08:08:08';
			default :		die('OT::DefVal 参数错误');
		}
	}

	// 不再列表值内，返回默认值
	public static function ListDefVal($str, $list, $def=''){
		if (strpos('|'. $list .'|','|'. $str .'|') === false){
			return $def;
		}else{
			return $str;
		}
	}

	// 版本比较 $ver要对比的版本号，$ver0原始版本号
	// 结果>0 则 $ver>$ver0，结果<0 则 $ver<$ver0
	public static function VerCompare($ver, $ver0 = PHP_VERSION){
		$verArr = explode('.', $ver);
		$ver0Arr = explode('.', $ver0);
		$verCount = count($verArr);
		if ($verCount == 1){
			$ver	= $verArr[0];
			$ver0	= $ver0Arr[0];
		}elseif ($verCount == 2){
			$ver	= $verArr[0] .'.'. $verArr[1];
			$ver0	= $ver0Arr[0] .'.'. $ver0Arr[1];
		}elseif ($verCount == 3){
			$ver	= $verArr[0] .'.'. $verArr[1] .'.'. $verArr[2];
			$ver0	= $ver0Arr[0] .'.'. $ver0Arr[1] .'.'. $ver0Arr[2];
		}
		return version_compare($ver0, $ver);
	}

	// 数字转中文数字 NumToCN(123456) 输出：十二万三千四百五十六
	public static function NumToCN($num){
		$numArr = array('零', '一', '二', '三', '四', '五', '六', '七', '八', '九');
		$unitArr = array('', '十', '百', '千', '万', '十', '百', '千', '亿');
		if ($num > 999999999) {
			return '数值太大，超出转换范围';
		}
		$str = '';
		$unitIndex = 0;
		while ($num > 0) {
			$part = $num % 10;	// 获取当前位的数字
			$num = intval($num / 10);	// 去掉当前位的数字
			if ($part != 0) {
				$str = $numArr[$part] . $unitArr[$unitIndex] . $str;
			}elseif ($str[0] != $numArr[0]) {	// 添加零，除非已经是开头
				$str = $numArr[0] . $str;
			}
			$unitIndex ++;
		}
		return $str;
	}

	// 数字转大写金额汉字（如财务用） NumToMoneyCN(123456.78); 输出：壹拾贰万叁仟肆佰伍拾陆元柒
	public static function NumToMoneyCN($num) {
		$unitArr = array('分', '角', '元', '拾', '佰', '佰佰', '佰佰佰', '万', '拾', '佰', '佰佰', '佰佰佰', '亿');
		$numArr = array('零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖');
		$num = sprintf("%.2f", $num);	// 保留两位小数
		$num = strrev($num);			// 反转字符串，便于从低位到高位处理
		$str = '';
		for ($i = 0; $i < strlen($num); $i++) {
			if ($num[$i] == '.') {		// 处理小数点后的部分
				$str .= "元（";
				continue;
			} elseif ($num[$i] == '0') {	// 处理零的情况，但不是开头的零或连续零只取一个零
				if ($str[strlen($str) - 1] != $numArr[0] && $i != strlen($num) - 1) {
					$str .= $numArr[0];
				}
				continue;
			} else {	// 处理非零数字和单位
				$str .= $numArr[$num[$i]] . $unitArr[$i];
			}
		}
		$str = strrev($str);		// 再次反转字符串，恢复原顺序
		return rtrim($str, '零');	// 移除末尾的零和单位，例如"零元"应变为"元"
	}
	 
	
}

?>