<?php
include 'lib/vendor/autoload.php';
use Overtrue\Pinyin\Pinyin;
/**
  * @method 公共函数类
  * @author soul
  * @copyright 2017/4/13
  */
class LibFc
{
	/*
	<method>
		<name>Escape(编码特殊字符)</name>
		<remark>编码特殊字符</remark>
		<exp.>Escape("a'b")</exp.>
		<Parameter>
			<para name="Data" type="string">需要处理的字符串</para>
			<para name="Filter" type="string">是否过来敏感词语</para>
		</Parameter>
		<return>编码后的字符串</return>
		<author>Soul 2013-3-18</author>
	</method>
	*/
	static function Escape($Data, $Filter = false)
	{
		if($Filter)
		{//敏感词语
			$FilterArr = include('lib/Filter.php');
			$Data = str_replace($FilterArr, '***', $Data);
		}

		$TrimHtmlTag = 'script|i?frame|style|html|body|title|link|meta';
		$FindArr = array(
			sprintf("/<(%s)([^>]*?)>/isU", $TrimHtmlTag),
			sprintf("/<\/(%s)>/isU", $TrimHtmlTag)
		);
		$ToArr = array('&lt;$1$2&gt;', '&lt;/$1&gt;');
		$Data = preg_replace($FindArr, $ToArr, $Data);

		$ReplaceArr = array('\\'=>'\\\\', "'"=>"''", ' '=>' ');
		return trim(strtr($Data, $ReplaceArr));
	}

	/*
	<method>
		<name>Int(数据是否为整型)</name>
		<remark>数据是否为整型</remark>
		<exp.>Int("123")</exp.>
		<Parameter>
			<para name="Data" type="string">需要处理的字符串</para>
		</Parameter>
		<return>
			是整形：整数
			非整形：false
		</return>
		<author>Soul 2013-3-26</author>
	</method>
	*/
	static function Int($Data)
	{
		$Data = trim($Data);
		if($Data != '' && preg_match('/^[-+]?\d+$/', $Data, $Matches))
		{
			return $Matches[0];
		}
		return false;
	}


	/*
	<method>
		<name>Float(数据是否为浮点型)</name>
		<remark>数据是否为浮点型</remark>
		<exp.>Float("123.2312")</exp.>
		<Parameter>
			<para name="data" type="string">需要处理的字符串</para>
			<para name="Precision" type="int">十进制小数点后数字的数目-进行四舍五入的结果</para>
		</Parameter>
		<return>
			是整形：浮点数
			非整形：false
		</return>
		<author>Soul 2013-3-26</author>
	</method>
	*/
	static function Float($Data, $Precision=2)
	{
		$Precision = self::Int($Precision);
		if($Precision >= 0)
		{
			if(preg_match('/^([-+]?\d+)\.?\d*$/', trim($Data), $Matches))
			{
				return round($Matches[0], $Precision);
			}
		}
		return false;
	}

	/**
     * 字符串截取，支持中文和其他编码
     * @static
     * @access public
     * @param string $str 需要转换的字符串
     * @param string $start 开始位置
     * @param string $length 截取长度
     * @param string $charset 编码格式
     * @param string $suffix 截断显示字符
     * @return string
     */
    static public function msubstr($str, $start, $length, $charset="utf-8", $suffix=true) {
        if(function_exists("mb_substr"))
            $slice = mb_substr($str, $start, $length, $charset);
        elseif(function_exists('iconv_substr')) {
            $slice = iconv_substr($str,$start,$length,$charset);
        }else{
            $re['utf-8']   = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
            $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
            $re['gbk']    = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
            $re['big5']   = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
            preg_match_all($re[$charset], $str, $match);
            $slice = join("",array_slice($match[0], $start, $length));
        }
        return $suffix && $str != $slice? $slice.'...' : $slice;
    }

	static public function slen($str, $charset="utf-8")
	{
		 return function_exists("mb_substr")? mb_strlen($str, $charset): strlen($str);
	}


	/*
	<method>
		<name>ReturnData(接口返回数据)</name>
		<remark>接口返回数据</remark>
		<exp.>
			ReturnData() 返回false、错误代码0、无错误信息
			ReturnData(true, array(1,2,3)) 返回true、数据为array(1,2,3)
		</exp.>
		<Parameter>
			<para name="Status" type="bool">true| 默认false [可选]</para>
			<para name="Data" type="all">所有类型 默认空 [可选]</para>
			<para name="Code" type="int">错误代码，默认0:无错误代码 [可选]</para>
		</Parameter>
		<return>
			返回值：array('status'=>false, 'data'=>'错误信息', 'code'=>0);
					array('status'=>true, 'data'=>array(1,2,3,4), 'code'=>0);
		</return>
		<author>Soul 2013-3-30</author>
	</method>
	*/
	static function ReturnData($Status=false, $Data='', $Code=0)
	{
		$Status = $Status == true? true:false;
		$Arr = ['status'=>$Status, 'data'=>$Data, 'code'=>$Code];
		if(!$Status)
			self::EchoJson($Arr);
		return $Arr;
	}


	/*
	<method>
		<name>ReturnJson(返回数据)</name>
		<remark>返回数据</remark>
		<exp.></exp.>
		<Parameter>
			<para name="Status" type="int"> [可选]</para>
			<para name="Data" type="all">所有类型 默认空 [可选]</para>
		</Parameter>
		<return>
			返回值：array('status'=>false, 'data'=>'错误信息', 'code'=>0);
					array('status'=>true, 'data'=>array(1,2,3,4), 'code'=>0);
		</return>
		<author>Soul 2013-3-30</author>
	</method>
	*/
	static function ReturnJson($Status=false, $Data='', $Code='')
	{
		$Status = $Status == true? true:false;
		self::EchoJson(['status'=>$Status, 'data'=>$Data, 'code'=>$Code]);
	}


	/**
	  * @method 返回json结果并终止
	  * @http  post
	  * @param  data   array  ['status'=>bool, 'data'=>任意格式的数据, 'code'=>错误代码]
	  * @return {"status":bool,"data": 任意格式的数据,"code":错误代码}
	  */
	static function EchoJson($dataArr)
	{
		if(mvc::$cfg['runtimeb'])
			$dataArr['runtime'] = ceil((microtime(true) - mvc::$cfg['runtimeb'])*1000);
		if(isset($_GET['callback']))
		{
			echo $_GET['callback'].'('.json_encode($dataArr, JSON_UNESCAPED_UNICODE).')';
		}
		else
		{
			echo json_encode($dataArr, JSON_UNESCAPED_UNICODE);
		}
		exit;
	}
	

	/*
	<method>
		<name>RandNum(生成指定范围的随机数)</name>
		<remark>生成指定范围的随机数</remark>
		<exp.>
			RandNum(100, 200) 返回 100 到 200 之间的随机数
		</exp.>
		<Parameter>
			<para name="Min" type="int">最小值</para>
			<para name="Max" type="int">最大值</para>
		</Parameter>
		<return>
			指定范围的随机数
		</return>
		<author>Soul 2013-3-30</author>
	</method>
	*/
	static function RandNum($Min, $Max)
	{	
		$Min = (int) $Min;
		$Max = (int) $Max;
		return mt_rand($Min, $Max);
	}


	/*
	<method>
		<name>GetCrc32(获取十六进制非负数的CRC32)</name>
		<remark>获取十六进制的CRC32</remark>
		<exp.>
			GetCrc32(123);
		</exp.>
		<Parameter>
			<para name="Data" type="string">数据</para>
		</Parameter>
		<return>
			十六进制的CRC32
		</return>
		<author>Soul 2013-6-17</author>
	</method>
	*/
	static function GetCrc32($Data)
	{
		return strtoupper(dechex(crc32($Data)));
	}
	
	/**
	  * @name GetFileType
	  * @remark  获取文件的类型，需要开启extension=php_fileinfo.dll
	  * @exp  GetFileType('我的文件a.jpg');
	  * @param  $FileDir    string  文件路径
	  * @author Soul
	  * @copyright 2013/7/8
	  * @return image/jpeg...
	  */
	static function GetFileType($FileDir)
	{
		$Finfo = finfo_open(FILEINFO_MIME_TYPE);
		$Type = finfo_file($Finfo, $FileDir);
		finfo_close($Finfo);
		return $Type;
	}

	
	/*
	<method>
		<name>Format Number(格式化号码)</name>
		<remark>格式化号码</remark>
		<exp.>LibFc::FormatNum("a'b")//ab</exp.>
		<Parameter>
			<para name="string" type="string">需要处理的字符串</para>
		</Parameter>
		<return>过滤后的字符串</return>
		<author>Cell 2013-3-18</author>
	</method>
	*/
	static function FormatNum($string, $b = '')
	{
		$string = self::GetSemiangle($string);
		$strTemp = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ". $b;
		$restr = '';
		for ($i=0; $i<strlen($string); $i++)
		{
			$c = substr($string,$i,1);
			if (strpos($strTemp, $c) !== false)
				$restr .= $c;
		}
		return strtoupper($restr);
	}


	/**
	  * @method 获取搜索号码，返回数组
	  * @param  $number string  号码
	  * @author soul
	  * @copyright 2017/6/5
	  * @return 过滤后的字符串
	  */
	static function FormatEng($string, $b = '')
	{
		$string = self::GetSemiangle($string);
		$onlychar = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZβγδⅦⅥⅤⅣⅢⅡⅠ'.$b;
		$len = mb_strlen($string, 'utf-8');
		$newstr = '';
		for ($i=0; $i<$len; $i++)  
		{
			$char = mb_substr($string, $i, 1, 'utf-8');
			if(stripos($onlychar, $char) !== false)
				$newstr .= $char;
		}
		return strtoupper($newstr);
	}
	

	/**
	  * @method 获取搜索号码，返回数组
	  * @param  $number string  号码
	  * @author soul
	  * @copyright 2017/6/5
	  * @return  ['A000...'...]
	  */
	static function SearchNum($number)
	{
		$formatNum = LibFc::FormatNum($number);
		$reNum = ['I'=>'1', 'O'=>'0', 'i'=>'1', 'o'=>'0'];
		$reFormatNum = strtr($formatNum, $reNum);
		$formatNumArr = [$formatNum, $reFormatNum];
		foreach([$formatNum, $reFormatNum] as $num){
			//奔驰系列L
			if(preg_match('/^A[0-9]{10}$/', $num)){
				$formatNumArr[] = substr($num, 1);
			}else if(preg_match('/^[0-9]{10}$/', $num)){
				$formatNumArr[] = 'A'.$num;
			}else if(preg_match('/^L[a-zA-Z0-9]{7}/', $num)){
				//大众去L
				$formatNumArr[] = substr($num, 1);
			}
		}
		return array_unique($formatNumArr);
	}


	/*
    <method>
        <name>全角转半角</name>
        <Parameter>
            <para name="$str" type="string"> 待转换的字符串 </para>
        </Parameter>
        <return>
            @return string
        </return>
        <author>强哥 2013-06-18</author>
    </method>
    */
    static function GetSemiangle($str)
    {
        $arr = array('０' => '0', '１' => '1', '２' => '2', '３' => '3', '４' => '4','５' => '5', '６' => '6', '７' => '7', '８' => '8', '９' => '9',
        'Ａ' => 'A', 'Ｂ' => 'B', 'Ｃ' => 'C', 'Ｄ' => 'D', 'Ｅ' => 'E','Ｆ' => 'F', 'Ｇ' => 'G', 'Ｈ' => 'H', 'Ｉ' => 'I', 'Ｊ' => 'J', 'Ｋ' => 'K',
        'Ｌ' => 'L', 'Ｍ' => 'M', 'Ｎ' => 'N', 'Ｏ' => 'O','Ｐ' => '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','ｏ' => 'o', 'ｐ' => 'p', 'ｑ' => 'q', 'ｒ' => 'r',
        'ｓ' => 's', 'ｔ' => 't', 'ｕ' => 'u', 'ｖ' => 'v', 'ｗ' => 'w', 'ｘ' => 'x', 'ｙ' => 'y', 'ｚ' => 'z', '～'=>'~', '·'=>'`', '！'=>'!',
        '＠'=>'@', '＃'=>'#', '￥'=>'$', '％'=>'%', '……'=>'^', '＆'=>'&', '×'=>'*', '（'=>'(', '）'=>')', '——'=>'_', '－'=>'-', '＋'=>'+', '＝'=>'=',
        '｛'=>'{', '｝'=>'}', '【'=>'[', '】'=>']', '｜'=>'|', '＼'=>'\\', '：'=>':', '；'=>';', '”'=>'"', '’'=>'\'', '《'=>'<', '，'=>',', '》'=>'>',
        '。'=>'.', '？'=>'?', '、'=>'/', 'γ'=>'y', 'δ'=>'d');
        return strtr($str, $arr);
    }


	/*
    *转换特殊的字母 现在只有厂商使用
    */
    static function ToEnFac($Str)
    {
        $Str = self::ToEmglishCase($Str);
        $Arr = array('`'=>'', '\''=>'', 'FMSI-VERBAND'=>'FMSI');
        return strtr($Str, $Arr);
    }

	static function ToEmglishCase($Str)
    {
        $Str = self::GetSemiangle($Str);
        //生成需要转换的数组
        $Arr = require 'libs/ToEmglishCase.php';
        return strtr($Str, $Arr);
    }
	
	
	/*
	<method>
		<name>array_save(保存数组文件)</name>
		<remark>格式化号码</remark>
		<exp.>LibFc::ArraySave("a'b")//ab</exp.>
		<Parameter>
			<para name="array" type="array">数组</para>
			<para name="file" type="string">文件名</para>
			<para name="arrayname" type="string">数组名</para>
		</Parameter>
		<return>生成数组文件</return>
		<author>Cell 2013-3-18</author>
	</method>
	*/
	static function ArraySave($array, $file, $arrayname = false)
	{ 
		$data = var_export($array, TRUE);
		if (!$arrayname) {
		   $data = "<?php\n return " .$data.";\n?>";
		} else {
		   $data = "<?php\n " .$arrayname . "=\n" .$data . ";\n?>";
		}
		return file_put_contents($file,$data);
	}

    /**
     * 获取客户端IP地址
     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @return mixed
     */
    static function GetClientIp($type = 0){
		$type = $type ? 1 : 0;
		$ip = '';

		if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
			$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
			$ips = array_map('trim', $ips);

			// 从后往前找第一个合法IP
			foreach (array_reverse($ips) as $tip) {
				if (
					$tip !== '' &&
					strcasecmp($tip, 'unknown') !== 0 &&
					filter_var($tip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)
				) {
					$ip = $tip;
					break;
				}
			}
		}

		if (!$ip && !empty($_SERVER['HTTP_CLIENT_IP'])) {
			$tip = trim($_SERVER['HTTP_CLIENT_IP']);
			if (filter_var($tip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
				$ip = $tip;
			}
		}

		if (!$ip && !empty($_SERVER['REMOTE_ADDR'])) {
			$tip = trim($_SERVER['REMOTE_ADDR']);
			if (filter_var($tip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
				$ip = $tip;
			}
		}

		$long = ip2long($ip);
		$long = ($long !== false) ? sprintf('%u', $long) : 0;

		$arr = $long ? array($ip, $long) : array('0.0.0.0', 0);
		return $arr[$type];
	}

	/**
	*mysql enum 分拆
	*$String enum('普通','紧急','延时')
	*return ['普通','紧急','延时']
	*/
	static function GetEnum($String)
	{
		$Arr = [];
		if(preg_match_all('/\'([^\']+)\'/i', $String, $Match))
		{
			$Arr = $Match[1];
		}
		return $Arr;
	}


	/*
    <method>
        <name>FormatVin</name>
        <remark></remark>
        <exp.></exp.>
        <Parameter>
            <para name="Vin" type="string"></para>
        </Parameter>
        <return></return>
        <author>Soul 2015-09-03</author>
    </method>
    */
    static function FormatVin($Vin)
    {
        $Vin = strtoupper(str_replace(' ', '', $Vin));
		$ReArr = ['０' => '0', '１' => '1', '２' => '2', '３' => '3', '４' => '4','５' => '5', '６' => '6', '７' => '7', '８' => '8', '９' => '9',
        'Ａ' => 'A', 'Ｂ' => 'B', 'Ｃ' => 'C', 'Ｄ' => 'D', 'Ｅ' => 'E','Ｆ' => 'F', 'Ｇ' => 'G', 'Ｈ' => 'H', 'Ｉ' => '1', 'Ｊ' => 'J', 'Ｋ' => 'K',
        'Ｌ' => 'L', 'Ｍ' => 'M', 'Ｎ' => 'N', 'Ｏ' => '0','Ｐ' => 'P', 'Ｑ' => '0', 'Ｒ' => 'R', 'Ｓ' => 'S', 'Ｔ' => 'T','Ｕ' => 'U', 'Ｖ' => 'V',
        'Ｗ' => 'W', 'Ｘ' => 'X', 'Ｙ' => 'Y','Ｚ' => 'Z', 'ａ' => 'A', 'ｂ' => 'B', 'ｃ' => 'C', 'ｄ' => 'D','ｅ' => 'E', 'ｆ' => 'F', 'ｇ' => 'G',
        'ｈ' => 'H', 'ｉ' => '1','ｊ' => 'J', 'ｋ' => 'K', 'ｌ' => 'L', 'ｍ' => 'M', 'ｎ' => 'N','ｏ' => '0', 'ｐ' => 'P', 'ｑ' => '0', 'ｒ' => 'R',
        'ｓ' => 'S', 'ｔ' => 'T', 'ｕ' => 'U', 'ｖ' => 'V', 'ｗ' => 'W', 'ｘ' => 'X', 'ｙ' => 'Y', 'ｚ' => 'Z', 'I'=>'1', 'O'=>'0', 'Q'=>'0'];
        $Vin = trim(strtr($Vin, $ReArr));
		$Vin = preg_replace('/[^0-9a-zA-Z]/', '', $Vin);
		if(strlen($Vin) > 17) $Vin = substr($Vin, 0, 17);
        return $Vin;
    }

	static function matchVin($str)
	{
		$str = strtoupper($str);
		$str = str_replace(' ', '', $str);
		if(preg_match('/[0-9a-zA-Z]{17}/', $str, $matchArr))
		{
			return $matchArr;
		}
        return [];
	
	}

    /*
    <method>
        <name>GetMakeNo</name>
        <remark>行驶证 品牌型号</remark>
        <exp.></exp.>
        <Parameter>
            <para name="str" type="string"></para>
        </Parameter>
        <return></return>
        <author>Soul 2015-09-03</author>
    </method>
    */
    static function FormatMakeNo($Str)
    {
        $Arr = ['make'=>'', 'makeno'=>''];
        $Arr['makeno'] = stripos($Str, '牌') !== false ? substr($Str, stripos($Str, '牌')+3): $Str;
        $Arr['makeno'] = strtoupper($Arr['makeno']);
        $Arr['make'] = str_replace($Arr['makeno'], '', $Str);
        return $Arr;
    }


	 /*
    <method>
        <name></name>
        <remark>VIN的校验码</remark>
        <exp.></exp.>
        <Parameter>
            <para name="$Vin" type="string"></para>
        </Parameter>
        <return>array('real'=>'0', 'ok'=>0/1, 'v9'=>'1')</return>
        <author>Soul 2015-09-03</author>
    </method>
    */
    static function VinCheckCode($Vin)
    {
        $Arr = ['real'=>'', 'ok'=>0, 'v9'=>''];
        $Vin = self::FormatVin($Vin);
        if(strlen($Vin) == 17 && strpos($Vin, '*') === false){
            $Arr['v9'] = substr($Vin, 8, 1);
            $ValueArr =[
				'1'=>1,'2'=>2,'3'=>3,'4'=>4,'5'=>5,'6'=>6,'7'=>7,'8'=>8,'9'=>9,
                'A'=>1,'B'=>2,'C'=>3,'D'=>4,'E'=>5,'F'=>6,'G'=>7,'H'=>8,
                'J'=>1,'K'=>2,'L'=>3,'M'=>4,'N'=>5,       'P'=>7,'R'=>9,
                'S'=>2,'T'=>3,'U'=>4,'V'=>5,'W'=>6,'X'=>7,'Y'=>8,'Z'=>9
            ];
            $Weight = [1=>8,2=>7,3=>6,4=>5,5=>4,6=>3,7=>2,8=>10,9=>0,10=>9,11=>8,12=>7,13=>6,14=>5,15=>4,16=>3,17=>2];
            $Sum = 0;
            foreach($Weight as $P=>$W) {
				$char = substr($Vin, ($P-1), 1);
				if(isset($ValueArr[$char])) $Sum += $ValueArr[$char]*$W;
            }
            $Arr['real'] = $Sum%11;
            $Arr['real'] = $Arr['real'] == 10 ? 'X': (string) $Arr['real'];
            $Arr['ok'] = $Arr['real'] === $Arr['v9']? 1: 0;
        }
        return $Arr;
    }



    /*
    <method>
        <name>VinYear</name>
        <remark>获取VIN的年份</remark>
        <exp.></exp.>
        <Parameter>
            <para name="Letter" type="string">单独传一个字符</para>
        </Parameter>
        <return></return>
        <author>Soul 2015-09-03</author>
    </method>
    */
    static function VinYear($Letter)
    {
        $Year = 0;
		$Letter = strlen($Letter) == 17 ? substr(trim($Letter), 9, 1): $Letter;
        $Letter = substr(trim($Letter), 0, 1);
        $LetterArr = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', '1', '2', '3', '4', '5', '6', '7', '8', '9');
        if(($Key = array_search($Letter, $LetterArr)) !== false)
        {
            $Begin = 1980;
            $NowYear = date('Y');
            for($I=0; $I < 5; $I++)
            {
                $TYear = $Begin+$Key+count($LetterArr)*$I;
                if(($TYear - $NowYear) > 1) break;
                $Year = $TYear;
            }
        }
        return $Year;
    }
	
	/**
     * @method 获取工信部型号的首数字【标识是什么车】
     * @param $gxb string [必填] BHQ6361B
	 * @return 空或者数字
     */
	static function getGxbCarType($gxb)
	{
		$num = '';
		if(preg_match('/\d/U', $gxb, $match)) $num = $match[0];
		return $num;
	}


	/*
    <method>
        <name>FormatTcdPic</name>
        <remark>格式化图片地址</remark>
        <exp.>
        </exp.>
        <Parameter>
            <para name="Data" type="string">数据(2_3433_4,2_3434_4,)</para>
        </Parameter>
        <return>
            二维维数组 array(array('small'=>'', 'big'=>''))
        </return>
        <author>Soul 2013/7/6</author>
    </method>
    */
	static function FormatTcdPic($picStr, $baseUrl = '')
    {
        $PicArr = array();
		if(stripos($picStr, 'CR') === 0)
		{
			$tempArr = explode('_', $picStr);
			$path = $tempArr[0];
			unset($tempArr[0]);
			foreach($tempArr as $img)
			{
				$PicArr[] = [
					'small'=>sprintf("%s%s/small/%s.jpg", $baseUrl, $path, $img),
					'big'=>sprintf("%s%s/%s.jpg", $baseUrl, $path, $img)
				];
			}
		}
		else if(stripos($picStr, 'S') === 0)
		{
			$tempArr = explode('_', $picStr);
			for($i = 1; $i <= $tempArr[2]; $i++)
			{
				$p2 = sprintf("%02d", $tempArr[1] >= 10 ? substr($tempArr[1], -2) : $tempArr[1]);
				$PicArr[] = [
					'small'=>sprintf("%s%s/%s/small/%s_%d.jpg", $baseUrl, $tempArr[0], $p2, $tempArr[1], $i),
					'big'=>sprintf("%s%s/%s/%s_%d.jpg", $baseUrl, $tempArr[0], $p2, $tempArr[1], $i)
				];
			}
		}
		else if(stripos($picStr, 'OTH') === 0)
		{
			$TempPicArr = explode(',', $picStr);
			foreach($TempPicArr as $Pic)
			{
				if(!empty($Pic))
				{
					$PicArr[] = [
						'small'=> sprintf("%s%s", $baseUrl, $Pic),
						'big'=>sprintf("%s%s", $baseUrl, $Pic)
					];
				}
			}
		}
		else
		{
			$TempPicArr = explode(',', $picStr);
			foreach($TempPicArr as $Pic)
			{
				$Pic = trim($Pic);
				if(!empty($Pic))
				{
					$TempOneArr = explode('_', $Pic);
					$PicArr[] = [
						'small'=> sprintf("%s%s/%s/small/%s.jpg", $baseUrl, $TempOneArr[0], substr($TempOneArr[1], 0, 2), $TempOneArr[1]),
						'big'=>sprintf("%s%s/%s/%s.jpg", $baseUrl, $TempOneArr[0], substr($TempOneArr[1], 0, 2), $TempOneArr[1])
					];
				}
			}
		}
        return $PicArr;
    }
	

	/**
     * 分词
     * @param word  现代瑞纳瑞奕悦动朗动领动名图索纳塔双铱金火花塞DH7RTII
     * @return ['现代', '火花塞', ....]
	 * @copyright soul 2017/9/20
     */
	static function fenCi($word)
	{
		//$time = microtime(true);
		if(empty($GLOBALS['PhpAnalysis']))
		{
			require_once(mvc::$cfg['ROOT_MVC'].'lib/lib/PHPAnalysis/WordAnalysis/phpanalysis.class.php');
			$pa = new PhpAnalysis('utf-8', 'utf-8', false);
			$pa->LoadDict ();
			$GLOBALS['PhpAnalysis'] = $pa;
		}
		else
		{
			$pa = $GLOBALS['PhpAnalysis'];
		}
		$pa->SetSource ($word);
		$pa->StartAnalysis ( true );
		$words = $pa->GetFinallyKeywords (1000);
		//echo ceil((microtime(true) - $time)*1000), 'ms=>', $word, '=>', $words, '<br>';
		return array_unique(explode(',', $words));
	}

	
	/**
     * 生成关键字
     * @param word  现代瑞纳瑞奕悦动朗动领动名图索纳塔双铱金火花塞DH7RTII
     * @param paramArr  ['fenci'=>true]
     * @return ['现代', '火花塞', ....]
	 * @copyright soul 2017/9/20
     */
    static function keyword($word, $paramArr = ['fenci'=>true])
    {
		//特殊字符转换
        $arr = array('&NBSP;', '~', '!', '@', '#', '$', '%', '&', '*', '(', ')', '+', '=', '{', '[', '}', ']', '|', '\\', ':', ';', '"', '\'', '<',',', '>', '?', '/', '-', '_');
        $word = str_replace($arr, ' ', $word);
        $arr = array('`', '\'', '´', '^', '·');
        $word = str_replace($arr, '', $word);
		$allKeywordArr = self::fenCi($word);
		$endArr = [];
		foreach($allKeywordArr as $k=>$v)
		{
			$v = trim(strtoupper($v));
			if($v != '' && !in_array($v, $endArr)) $endArr[] = $v;
		}
		return $endArr;
    }


	/**
     * 格式化关键字
     * @param word  现代[,|;:]火花塞
     * @return 现代,火花塞
	 * @copyright soul 2017/9/20
     */
	static function fromatKeyword($word)
	{
		$arr = array('&nbsp;', ' ', ',', '，', '。', '、', '/', '|', ';', '；', '\\');
        $wordArr = explode(',', str_ireplace($arr, ',', $word));
		$wordArr = array_unique($wordArr);
		foreach($wordArr as $k=>$v)
		{
			if($v == '') unset($wordArr[$k]);
		}
		return implode(',', $wordArr);
	}

	/**
	  * @method 格式字符串
	  * @param  $string 字符串
	  * @param  $type  0:英文+数字  1:英文+数字+中文
	  * @author soul
	  * @copyright 2017/6/5
	  * @return [["status"]=> bool(true) ["data"]=>  ["code"]=> int(0) ]
	  */
	static function formatStr($string, $type = 0)
	{
		$regArr = [
			0=>'/[^a-zA-Z0-9]/',
			1=>'/[^a-zA-Z0-9\x{4e00}-\x{9fa5}]/u',
		];
		return  preg_replace($regArr[$type], '', $string);
	}

	/**
     * 生成全球唯一guid
	 * @param type  0数字型 [默认]| 1 字符型
	 * @copyright soul 2017/11/1
	 * @return 32位字符  2017-11-01 18 28 20    069186096191406248  || CCF1D138D0262E2DBD1A01F187C4965F
     */
    static function guid($type = 0)
    {
		$guid = date('YmdHis');
		list($usec, $sec) = explode(" ", microtime());
		$usec = sprintf("%d", $usec*10000000);
		$guid .= $usec.rand(1000, 9999);
		$randLen = 32 - strlen($guid);
		$guid .= rand(pow(10,($randLen-1)), pow(10,$randLen)-1);
		$guid = empty($type)? $guid: strtoupper(md5($guid));
		return $guid;
	}

	/**
     * 格式化年份
     * @param startYear 2016|201601...
     * @param endYear  2017|201701....
     * @param type  1|2
     * @param style 1:[]
     * @return 1:1988/02-1989/12  2: 1988-1989
     */
	static function formatViewYear($startYear, $endYear, $type=1, $style= null)
	{
		$out = '';
		switch($type)
		{
			case 1: 
				$startYear = strlen($startYear) == 6? substr($startYear, 0, 4).'/'.substr($startYear, 4, 2): '';
				$endYear = strlen($endYear) == 6? substr($endYear, 0, 4).'/'.substr($endYear, 4, 2): '';
				if(!empty($startYear) || !empty($endYear))
				{
					$out = $startYear == $endYear? $startYear : $startYear.'-'.$endYear;
				}
			break;
			case 2:
				$startYear = strlen($startYear) >= 4? substr($startYear, 0, 4): '';
				$endYear = strlen($endYear) >= 4? substr($endYear, 0, 4): '';
				if(!empty($startYear) || !empty($endYear))
				{
					$out = empty($endYear)? $startYear.'-': $startYear.'-'.$endYear;
				}
			break;
		}
		if($out != ''){
			if($style == 1) $out = '【'.$out.'】';
			else if($style == 2) $out = '('.$out.')';
		}
		return $out;
	}

	/**
     * @method 某方法是否可以运行【方法加锁】
     * @param $keyName string [必填] 锁名称 唯一键(作为文件名)
     * @param $time int [选填] 锁的时间 默认600秒
	 * @return true|false
     */
	static function hasFunLock($keyName, $time = 600)
	{
		$time = (int) $time;
		$lockFile = mvc::$cfg['LOGS'].'Lock_'.$keyName.'.txt';
        if(file_exists($lockFile) && (time() - filemtime($lockFile)) < $time) return false;
        file_put_contents($lockFile, 'lock');
		return true;
	}


	/**
     * @method 删除方法锁
     * @param $keyName string [必填] 锁名称 唯一键(作为文件名)
	 * @return true|false
     */
	static function delFunLock($keyName)
	{
		@unlink(mvc::$cfg['LOGS'].'Lock_'.$keyName.'.txt');
		return true;
	}
	
	/**
     * @method 使用读写分离的主数据库
	 * @return 
     */
	static function useMainDb()
	{
		if(!empty(mvc::$cfg['MAINDB']))
		{
			foreach(mvc::$cfg['DB'] as $k=>$v)
			{
				if(isset(mvc::$cfg['DB'][$k]['db_host']))
					mvc::$cfg['DB'][$k]['db_host'] = strtr($v['db_host'], mvc::$cfg['MAINDB']);
			}
		}
		return true;
	}

	/**
     * @method 过滤掉emoji表情
	 * @return 
     */
	static function filterEmoji($str)
	{
		$mbLen = mb_strlen($str);
		$strArr = [];
		for ($i = 0; $i < $mbLen; $i++) {
			$mbSubstr = mb_substr($str, $i, 1, 'utf-8');
			if (strlen($mbSubstr) >= 4) {
				continue;
			}
			$strArr[] = $mbSubstr;
		}
		return implode('', $strArr);
	}

	/**
     * @method 写文件
	 * @return 
     */
	static function write($file, $msg)
    {
		$handle = fopen($file, 'a');
		fwrite($handle, $msg);
		fclose($handle);
    }
	
	/**
     * @method python str 的数据转json
	 * @return 
     */
	static function jsonstr($str)
	{
		$str = self::filterEmoji($str);
		$str = str_replace('"', "'", $str);
		//[' {' ]' }'
		$str = preg_replace('/([\{\}\[\]])\'/iUs', '$1"', $str);
		//'[ '{ '} ']
		$str = preg_replace('/\'([\{\}\[\]])/iUs', '"$1', $str);
		//' , ' | ' : '
		$str = preg_replace('/\' *([,:]) *\'/iUs', '"$1"', $str);
		//':xx  ',xx
		$str = preg_replace('/\' *([\:\,]) *([\d\{\[\}\]])/iUs', '"$1$2', $str);
		//xx:' xx,'
		$str = preg_replace('/([\d\{\[\}\]]) *([\:\,]) *\'/iUs', '$1$2"', $str);
		//0, 2 }, {
		$str = preg_replace('/([\d\}\]]) *([\:\,]) *([\d\{\[])/iUs', '$1$2$3', $str);
		//': "
		$str = preg_replace('/\' *([\:\,]) *\"/iUs', '"$1"', $str);
		$str = strtr($str, ['"[", \''=>'"[","', '", \''=>'","']);
		return $str;
	}
	
	/**
     * @method 随机取N位长度的字符
	 * @return 
     */
	static function randChars($len)
	{
		$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
		return substr(str_shuffle($chars), 0, $len);
	}

	/**
	  * @name 汉字转换拼音原始类
	  * @remark
        	汉字转换拼音 Pinyin('汉字转换拼音', 'utf-8') 得到 'hanzizhuanhuanpinyin'
        	原始的拼音函数只能适应大小写类, 又已经在在项目中使用, 为了不造成项目的问题，抽出其中的公共部分,重写 2013/11/18 Cell
	  * @param  $_String     string 待转换的汉字
	  * @param  $_Code       string 需要转换的编码，如果该参数不传则默认要转换的汉字为'utf-8'编码,如需转换成'gb2312'可以将该参数设为除'utf-8'或'UTF-8'的任何字符
	  * @author Cell
	  * @copyright 2013/11/18
	  * @return array
	  */
	static function GetPinYin( $_String, $_Code = 'utf-8' )
	{
        $oPinyin = new Pinyin();
        $_String = mb_convert_encoding($_String, 'utf-8', 'auto');
        return $oPinyin->name($_String);
	}


	/**
	  * @name PinYin() 汉字转换拼音
	  * @remark  汉字转换拼音 Pinyin('汉字转换拼音', true, 'utf-8') 得到 'hanzizhuanhuanpinyin'
	  * @param  $_String  string 待转换的汉字
	  * @param  $_Lower  bool  拼音是否需要小写，默认返回的为汉字的小写字母，如果需要拼音大写，将该参数设为false 
	  * @param  $_Code   string 需要转换的编码，如果该参数不传则默认要转换的汉字为'utf-8'编码,如需转换成'gb2312'可以将该参数设为除'utf-8'或'UTF-8'的任何字符 
	  * @author jian
	  * @copyright 2013/7/24
	  * @return string
	  */
    static function PinYin($_String, $_Lower = true, $_Code='utf-8')
    {
    	$_Res = self::GetPinYin( $_String, $_Code );
        $_R = preg_replace("/[^a-z0-9]*/", '', implode( '', $_Res ) );
        if($_Lower) {
            return $_R;
        } else {
			return strtoupper($_R);
        }
    }

	/**
	  * @name GetInitial
	  * @remark  获取首字母
	  * @param  $Str  string
	  * @author Soul
	  * @copyright 2015-08-15
	  * @return 大写首字母
	  */
	static function GetInitial($Str, $Charest = 'utf-8')
	{
		$Arr = array('・', ' ', '~', '!', '@', '#', '$', '%', '&', '*', '(', ')', '-', '——', '_', '+', '=', '{', '[', '}', ']', '|', '\\', ':', ';', '"', '\'', '<',',', '>', '?', '/');
		$Str = str_replace($Arr, '', $Str);
		$PinYin = self::GetPinYin( $Str, $Charest );
		$Result = '';
		if(!empty($PinYin))
		{
			foreach($PinYin as $V)
			{
				$T = substr($V, 0, 1);
				if(preg_match('/[a-zA-Z]/', $T, $M))
				{
					$Result .= substr($V, 0, 1);
				}
			}
		}
		return strtoupper($Result);
	}

	static function iscnlang($string) {
		return preg_match('/[\x{4e00}-\x{9fa5}]/u', $string);
	}

	/**
	  * @name 图片旋转 （需要装扩展Imagick）
	  * @param  $angle  int 90,180,270  负数表示逆时针旋转
	  * @param  $type  string file(本地路径) | blob(二进制) | base64  默认base64
	  * @param  $data  string $type对应的内容
	  * @param  $backType  string 返回的数据类型 blob(二进制) | base64  默认base64
	  * @param  $by  string Imagick GD  默认Imagick
	  * @param  $quality  int 质量默认90
	  * @return base64
	  */
	static function rotateImg($angle, $data , $type = 'base64', $backType = 'base64', $by = 'Imagick', $quality = 90)
	{
		if(empty($angle)) return ['status'=>false, 'data'=>'angle参数不正确'];
		if($type == 'blob'){
			$imageData = $data;
			unset($data);
		}else if($type == 'file'){
			if(file_exists($data)){
				$imageData = file_get_contents($data);
			}else{
				return ['status'=>false, 'data'=>'图片不存在'];
			}
		}else{
			$imageData = base64_decode($data);
		}
		try{
			if($by == 'GD'){
				$image = imagecreatefromstring($imageData);
				$rotatedImage = imagerotate($image, -$angle, 0);
				$imageInfo = getimagesizefromstring($imageData);
				$originalFormat = $imageInfo[2]; // 获取图像类型
				ob_start();
				switch ($originalFormat) {
					case IMAGETYPE_JPEG:
						imagejpeg($rotatedImage, null, $quality);
						break;
					case IMAGETYPE_PNG:
						imagesavealpha($rotatedImage, true);  // 保留PNG透明度
						imagepng($rotatedImage, null, 1);
						break;
					case IMAGETYPE_GIF:
						imagegif($rotatedImage); 
						break;
					case IMAGETYPE_BMP:
						imagebmp($rotatedImage);
						break;
					case IMAGETYPE_WEBP:
						imagewebp($rotatedImage, null, $quality);
						break;
					default:
						throw new Exception("不支持的图像格式");
				}
				$imageContent = ob_get_contents();
				ob_end_clean();
				imagedestroy($image);
				imagedestroy($rotatedImage);
			}else{
				//同等质量 GD库会慢点，图片会大点
				$Imagick = new Imagick();
				$Imagick->readImageBlob($imageData);
				//获取原图的压缩质量
				//$originalQuality = $Imagick->getImageCompressionQuality();
				$Imagick->rotateImage(new ImagickPixel('none'), $angle);
				// 移除不必要的元数据（如EXIF信息）
				$Imagick->stripImage();
				// 设置原有压缩质量
				$Imagick->setImageCompressionQuality($quality);
				$Imagick->setImageFormat($Imagick->getImageFormat());
				$imageContent = $Imagick->getImageBlob();
				$Imagick->destroy();
			}
			if($backType != 'blob') $imageContent = base64_encode($imageContent);
			return ['status'=>true, 'data'=>$imageContent];
		} catch (Exception $e) {
			return ['status'=>false, 'data'=>'图片旋转失败：'.$e->getMessage()];
		}
	}


	/**
     * 根据坐标裁剪图片
      * @param  $type  string file(本地路径) | blob(二进制) | base64  默认base64
	  * @param  $data  string $type对应的内容
	  * @param  $backType  string 返回的数据类型 blob(二进制) | base64  默认base64
	  * @param  $quality  int 质量默认90
     * @param $points [[164,159],[511,159],[511,1092],[164,1092]]}]
     */
	static function cropImage($data, $points, $type = 'base64', $backType = 'base64', $quality = 90)
	{
		if($type == 'blob'){
			$imageData = $data;
			unset($data);
		}else if($type == 'file'){
			if(file_exists($data)){
				$imageData = file_get_contents($data);
			}else{
				return ['status'=>false, 'data'=>'图片不存在'];
			}
		}else{
			$imageData = base64_decode($data);
		}
		$x1 = $points[0][0];
		$y1 = $points[0][1];
		$x2 = $points[1][0];
		$y3 = $points[2][1];
		$cropX = min($x1, $x2);
		$cropY = min($y1, $y3);
		$cropW = abs($x2 - $x1);
		$cropH = abs($y3 - $y1);
		[$w, $h, $imgtype] = getimagesizefromstring($imageData);
		$src = imagecreatefromstring($imageData);
		$dst = imagecreatetruecolor($cropW, $cropH);
		if ($imgtype == IMAGETYPE_PNG || $imgtype == IMAGETYPE_WEBP) {
			imagealphablending($dst, false);
			imagesavealpha($dst, true);
		}
		imagecopy(
			$dst, $src,
			0, 0,
			$cropX, $cropY,
			$cropW, $cropH
		);
		ob_start();
		switch ($imgtype) {
			case IMAGETYPE_JPEG:
				imagejpeg($dst, null, $quality);
				break;
			case IMAGETYPE_PNG:
				imagesavealpha($dst, true);  // 保留PNG透明度
				imagepng($dst, null, 1);
				break;
			case IMAGETYPE_GIF:
				imagegif($dst); 
				break;
			case IMAGETYPE_BMP:
				imagebmp($dst);
				break;
			case IMAGETYPE_WEBP:
				imagewebp($dst, null, $quality);
				break;
			default:
				return ['status'=>false, 'data'=>'不支持的图像格式'];
		}
		$imageContent = ob_get_contents();
		ob_end_clean();
		imagedestroy($src);
		imagedestroy($dst);
		if($backType != 'blob') $imageContent = base64_encode($imageContent);
		return ['status'=>true, 'data'=>$imageContent];
	}

	/**
     * @method 日志
     * @param $msg  [必填]  内容
     * @param $file [选填] 指定文件
     */
	static function logs($msg, $file = '')
    {
		if(empty($file)) $file = mvc::$cfg['LOGS'].date('Y-m-d').'.log';
		if(is_array($msg))
		{
			$msg = var_export($msg,TRUE);
		}
		if(mvc::$URL_METHOD) $msg = mvc::$URL_CLASS.'/'.mvc::$URL_METHOD.' '.$msg;
		$handle = fopen($file, 'a');
		fwrite($handle, sprintf("%s  %s\r\n", date('Y-m-d H:i:s'), $msg));
		fclose($handle);
    }


	static function runBegin($Mark)
	{
		
		if(TIMEDEBUG && !empty($Mark)){
			$_SESSION[$Mark] = microtime(true);
		}
	}

	/*
	<method>
		<name>Point</name>
		<remark>开始计时</remark>
		<exp.>
			Point('A', '查询SQL')
		</exp.>
		<Parameter>
			<para name="Mark" type="string">标记符</para>
			<para name="Des" type="string">描述</para>
		</Parameter>
		<return>
			返回值：查询SQL执行时间：100ms
		</return>
		<author>Soul 2013-3-30</author>
	</method>
	*/
	static function runPoint($Mark, $Des='')
	{
		if(TIMEDEBUG && !empty($_SESSION[$Mark]))
		{
			$Begin = $_SESSION[$Mark];
			echo $Des.'<br>'.$Mark.'执行时间：'.ceil((microtime(true)-$Begin)*1000).'ms<hr>';
		}
	}
	

	/**
     * @method 通过车架号时间过滤车型备注有时间的车型
     * @param $modArr  [必填]  [['mod_remark'=>'老款小片(201204-201712)']]
     * @param $date [必填] 2013-12  2013
     */
	static function filterModVinYear($modArr, $date)
	{
		if(preg_match('/([12]\d{3})[\-\/]?(\d{1,2})?/', $date, $match)){
			$y = $match[1];
			$ym = $match[2]? $match[1].str_pad($match[2], 2, '0', STR_PAD_LEFT): '';
			$nowym = date('Ym');
			foreach($modArr as $k=>$v){
				if(!empty($v['mod_remark'])) continue;
				$remark = strtr($v['mod_remark'], ['-至今'=>'-'.$nowym]);
				if(preg_match('/([12]\d{3})(\d{1,2})\-([12]\d{3})(\d{1,2})/', $remark, $match)){
					$mym = [
						'by'=>$match[1],
						'bym'=>$match[1].str_pad($match[2], 2, '0', STR_PAD_LEFT),
						'ey'=>$match[3],
						'eym'=>$match[3].str_pad($match[2], 2, '0', STR_PAD_LEFT),
					];
					if(($ym && ($ym >= $mym['bym'] && $ym <= $mym['eym'])) || ($y >= $mym['by'] && $ym <= $mym['ey'])){
					}else{
						unset($modArr[$k]);
						continue;
					}
				}
			}
		}
		return $modArr;
	}

	/**
     * @method 获取两个字符串不同之处
     */
	static function diffByPos($s1, $s2) {
		$a1 = preg_split('//u', $s1, -1, PREG_SPLIT_NO_EMPTY);
		$a2 = preg_split('//u', $s2, -1, PREG_SPLIT_NO_EMPTY);
		$max = max(count($a1), count($a2));
		$diff = [];

		for ($i = 0; $i < $max; $i++) {
			$c1 = $a1[$i] ?? null;
			$c2 = $a2[$i] ?? null;
			if ($c1 !== $c2) {
				$diff[$i] = ['a' => $c1, 'b' => $c2];
			}
		}
		return $diff;
	}


	/**
	 * 获取图片 dHash 感知哈希
	 *
	 * 不抛异常，统一返回状态。
	 *
	 * @param string $img  图片数据
	 * @param string $type 数据类型：base64 / dataurl / binary / path
	 * @return array
	 */
	static function imgDHash($img, $type = 'base64')
	{
		$ret = [
			'ok'    => false,
			'hash'  => '',
			'error' => '',
		];

		// 1. 根据指定类型获取图片二进制
		if ($type === 'path') {
			if (!is_file($img)) {
				$ret['error'] = '本地图片不存在';
				return $ret;
			}

			$data = @file_get_contents($img);
			if ($data === false || $data === '') {
				$ret['error'] = '本地图片读取失败';
				return $ret;
			}

		} elseif ($type === 'dataurl') {
			$img = preg_replace('/^data:image\/\w+;base64,/i', '', $img);
			$img = preg_replace('/\s+/', '', $img);

			$data = base64_decode($img, true);
			if ($data === false || $data === '') {
				$ret['error'] = 'dataurl base64 解码失败';
				return $ret;
			}

		} elseif ($type === 'base64') {
			$img = preg_replace('/\s+/', '', $img);

			$data = base64_decode($img, true);
			if ($data === false || $data === '') {
				$ret['error'] = 'base64 解码失败';
				return $ret;
			}

		} elseif ($type === 'binary') {
			$data = $img;

			if ($data === '') {
				$ret['error'] = '图片二进制数据为空';
				return $ret;
			}

		} else {
			$ret['error'] = '不支持的图片数据类型';
			return $ret;
		}

		// 2. 创建图片资源
		$src = @imagecreatefromstring($data);
		if (!$src) {
			$ret['error'] = '图片格式不支持或图片损坏';
			return $ret;
		}

		// 3. 缩放成 9x8
		$width = 9;
		$height = 8;

		$small = imagecreatetruecolor($width, $height);
		if (!$small) {
			imagedestroy($src);

			$ret['error'] = '创建缩略图失败';
			return $ret;
		}

		$res = imagecopyresampled(
			$small,
			$src,
			0,
			0,
			0,
			0,
			$width,
			$height,
			imagesx($src),
			imagesy($src)
		);

		if (!$res) {
			imagedestroy($src);
			imagedestroy($small);

			$ret['error'] = '图片缩放失败';
			return $ret;
		}

		// 4. 计算 dHash
		$bits = '';

		for ($y = 0; $y < $height; $y++) {
			for ($x = 0; $x < $width - 1; $x++) {
				$rgb1 = imagecolorat($small, $x, $y);
				$rgb2 = imagecolorat($small, $x + 1, $y);

				$r1 = ($rgb1 >> 16) & 0xFF;
				$g1 = ($rgb1 >> 8) & 0xFF;
				$b1 = $rgb1 & 0xFF;

				$r2 = ($rgb2 >> 16) & 0xFF;
				$g2 = ($rgb2 >> 8) & 0xFF;
				$b2 = $rgb2 & 0xFF;

				$gray1 = (int)($r1 * 0.299 + $g1 * 0.587 + $b1 * 0.114);
				$gray2 = (int)($r2 * 0.299 + $g2 * 0.587 + $b2 * 0.114);

				$bits .= ($gray1 > $gray2) ? '1' : '0';
			}
		}

		imagedestroy($src);
		imagedestroy($small);

		// 5. 64位二进制转 16位十六进制
		$hash = '';

		for ($i = 0; $i < 64; $i += 4) {
			$hash .= dechex(bindec(substr($bits, $i, 4)));
		}

		$ret['ok'] = true;
		$ret['hash'] = $hash;
		$ret['error'] = '';

		return $ret;
	}

	/**
	 * 计算两个 16位 hex hash 的汉明距离
	 *
	 * @param string $hash1
	 * @param string $hash2
	 * @return int
	 * @throws Exception
	 */
	static function distanceDhash($hash1, $hash2)
	{
		if (strlen($hash1) !== strlen($hash2)) {
			return 1000;
		}
		$distance = 0;

		for ($i = 0; $i < strlen($hash1); $i++) {
			$xor = hexdec($hash1[$i]) ^ hexdec($hash2[$i]);
			$distance += substr_count(decbin($xor), '1');
		}

		return $distance;
	}

	static function jsonEncode($infoArr)
	{
		return json_encode($infoArr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR);
	}

	static function waitRand($min, $max = '', $echo = ''){
		$min = (int) $min;
		if(empty($max) || $max < $min) $max = $min;
		$sleep = rand($min, $max);
		if($echo) echo "sleep {$sleep}s {$echo} \n";
		sleep($sleep);
	}

	/**
	 * 判断 图片是否完整、可正常解码 二进制内容
	 */
	static function isValidImageContent($content)
	{
		if (!$content || @getimagesizefromstring($content) === false) {
			return false;
		}
		$image = @imagecreatefromstring($content);
		if ($image === false) {
			return false;
		}
		imagedestroy($image);
		return true;
	}

	/**
	 * @method 获取兼容 Base64 和 multipart 文件的图片数据
	 * @param  string $field Base64 或上传文件字段名
	 * @return string
	 */
	static function getImageBase64($field)
	{
		if(isset($_FILES[$field])){
			if($_FILES[$field]['error'] !== UPLOAD_ERR_OK) LibFc::ReturnJson(false, '图片上传失败', 'imgerr');
			$tmpName = $_FILES[$field]['tmp_name'];
			$fileSize = is_uploaded_file($tmpName) ? filesize($tmpName) : false;
			if($fileSize === false || $fileSize <= 0) LibFc::ReturnJson(false, '图片文件无效', 'imgerr');
			if($fileSize > 10 * 1024 * 1024) LibFc::ReturnJson(false, '图片不能超过10MB', 'imgerr');
			if(@getimagesize($tmpName) === false) LibFc::ReturnJson(false, '请上传有效的图片文件', 'imgerr');
			$image = file_get_contents($tmpName);
			if($image === false) LibFc::ReturnJson(false, '图片文件无效', 'imgerr');
			return base64_encode($image);
		}
		if(isset($_POST[$field]) && is_string($_POST[$field]) && $_POST[$field] !== ''){
			$image = $_POST[$field];
			$commaPos = strpos($image, ',');
			if($commaPos !== false) $image = substr($image, $commaPos + 1);
			return str_replace(["\r", "\n"], '', $image);
		}
		LibFc::ReturnJson(false, '图片获取失败', 'imgerr');
	}
}