<?php
// +----------------------------------------------------------------------
// | Wendasns [ 开源问答社区系统 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2020~2021 http://wendasns.com All rights reserved.
// +----------------------------------------------------------------------	
namespace wendasns;


use wendasns\service\Xxtea;
use think\facade\Config;
use think\facade\View;
use think\facade\Db;
use think\facade\Cookie;
use think\facade\Request;
use app\ExceptionHandle;
use wendasns\facade\Addon;

class Wend
{
    /**
     * 用户密码加密存储.
     *
     * @param string $pwd
     *
     * @return string
     */
    public static function userpass($password, $salt)
    {
		return md5(md5($password).$salt);
    }
    
    /**
     * cookie密码加密存储.
     *
     * @param string $pwd
     *
     * @return string
     */
    public static function md5pwd($pwd)
    {
        return md5($pwd.configure('basis.pwdHash'));
    }

    /**
     * 加密方法.
     *
     * @param string $str
     * @param string $key
     *
     * @return string
     */
    public static function strEncrypt($str, $key = '')
    {
        $key || $key = configure('basis.pwdHash');

        $security = new Xxtea();
        
        return base64_encode($security->encrypt($str, $key));
    }

    /**
     * 解密方法.
     *
     * @param string $str
     * @param string $key
     *
     * @return string
     */
    public static function strDecrypt($str, $key = '')
    {
        $key || $key = configure('basis.pwdHash');
        
        $security = new Xxtea();
        $row = $security->decrypt(base64_decode($str), $key);
        return $row?$row:'';
    }
    
    /**
     * 获取矫正过的时间戳值
     *
     * @return int
     */
    public static function getTime()
    {
    	$timestamp = time();
        if ($cvtime = configure('basis.timeCv')) {
            $timestamp += $cvtime * 60;
        }
        return $timestamp;
    }
	
    /**
     * 获取系统配置信息
     *
     * @return array
     */
    public static function loadConfig()
    {
    	$dm = Db::name('config')->select();
    	$res = [];
    	foreach($dm as $v){
    		$namespace = $v['namespace'];
    		$name = $v['name'];
    		$res[$namespace][$name] = $v['value'];
    	}
    	
    	return $res;
    }
    
    /**
     * 数据加解密
     * @access protected
     * @param mixed $string     要加密的字符串
     * @param mixed $operation  模式[ENCODE=加密，DECODE=解密]
     * @param mixed $key        密钥
     * @param mixed $expiry     密文有效期
     * @return mixed
     */
    public static function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0)
    {
    	// 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
    	$ckey_length = 4;
    	
    	
    	// 密匙a会参与加解密     
    	$keya = md5(substr($key, 0, 16));     
    	// 密匙b会用来做数据完整性验证     
    	$keyb = md5(substr($key, 16, 16));     
    	// 密匙c用于变化生成的密文     
    	$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';     
    	// 参与运算的密匙     
    	$cryptkey = $keya.md5($keya.$keyc);     
    	$key_length = strlen($cryptkey);     
    	// 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，   
    	//解密时会通过这个密匙验证数据完整性     
    	// 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确     
    	$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :  sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;     
    	$string_length = strlen($string);     
    	$result = '';     
    	$box = range(0, 255);     
    	$rndkey = array();     
    	// 产生密匙簿     
    	for($i = 0; $i <= 255; $i++) {
    		$rndkey[$i] = ord($cryptkey[$i % $key_length]);     
    	}     
    	// 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度     
    	for($j = $i = 0; $i < 256; $i++) {
    		$j = ($j + $box[$i] + $rndkey[$i]) % 256;     
        	$tmp = $box[$i];     
        	$box[$i] = $box[$j];     
        	$box[$j] = $tmp;     
    	}     
    	// 核心加解密部分     
    	for($a = $j = $i = 0; $i < $string_length; $i++) {     
        	$a = ($a + 1) % 256;     
        	$j = ($j + $box[$a]) % 256;     
        	$tmp = $box[$a];     
        	$box[$a] = $box[$j];     
        	$box[$j] = $tmp;     
        	// 从密匙簿得出密匙进行异或，再转成字符     
        	$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));     
    	}
    	if($operation == 'DECODE') {
        	// 验证数据有效性，请看未加密明文的格式
        	if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&  substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
            	return substr($result, 26);
        	} else {
            	return '';
        	}
    	} else {
        	// 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
        	// 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
        	return $keyc.str_replace('=', '', base64_encode($result));
    	}
	}
	
    public static function curl($url, $post)
    {
    	$header = [
    		'Accept: application/json, text/javascript, */*; q=0.01'
    	];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        if($post){
        	curl_setopt($ch, CURLOPT_POST, 1);
        	curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        }
        $content = curl_exec($ch);
        curl_close($ch);//关闭一打开的会话
        return $content;
    }
    
    public static function getClient()
    {
    	$agent = Request::header('user-agent');
    	//$agent = strtolower($agent);
    	if(strpos($agent,'iPhone') !== false){
    		return 'iPhone';
    	}
    	if(strpos($agent,'Android') !== false){
    		return 'Android';
    	}
    	if(strpos($agent,'iPad') !== false){
    		return 'iPad';
    	}
    	if(strpos($agent,'Mac') !== false){
    		return 'Mac';
    	}
    	if(strpos($agent,'Windows') !== false){
    		return 'Windows';
    	}
        return '';
    }
}