<?php
/**
 * Notes:通用方法
 * User: wsc
 * Time: 2020/3/11 19:43
 * Class funs
 */

class funs extends CI_Model
{
    public function __construct()
    {
        parent::__construct();

    }

    /**
     * Notes:获取概率id
     * User: wsc
     * Time: 2020/3/12 11:28
     * @param $proArr ["id"=>"权重",...]
     * @return int|string
     */
    static function get_randByProp($proArr)
    {
        $result = '';
        foreach ($proArr as $k => $v) {
            $proArr[$k] = $v * 100;
        }
        //概率数组的总概率精度
        $proSum = array_sum($proArr);
        //概率数组循环
        foreach ($proArr as $key => $proCur) {
            $randNum = mt_rand(1, $proSum);
            if ($randNum <= $proCur) {
                $result = $key;
                break;
            } else {
                $proSum -= $proCur;
            }
        }
        unset ($proArr);
        return $result;
    }

    /**
     * Notes:单位换算(不支持浮点带单位输出)
     * User: wsc
     * Time: 2020/3/12 12:06
     * @param $str int|string  要换算的，数组字串
     * @param string $units 单位
     * @return bool|int|string （浮点带单位输出false）
     */
    static function units_conversion($str, $units = 'int')
    {
        if (empty($str) || 0 == $str) return false;
        $u_arr = ['k' => 1000, 'w' => 10000, 'm' => 1000000];
        $uk_arr = array_keys($u_arr);
        $str_unit = substr($str, -1);//传入字串单位
        $num = in_array($str_unit, $uk_arr) ? intval($u_arr[$str_unit] * intval($str)) : intval($str);
        $res = $units != 'int' && in_array($units, $uk_arr) ? ($num % $u_arr[$units] === 0 ? intval($num / $u_arr[$units]) . $units : false) : intval($num);
        return $res;
    }

    /**
     * Notes:数组键是json的解析
     * User: wsc
     * Time: 2020/3/25 16:19
     * @param $arr
     * @return array
     */
    static function getArrFromJsonArr($arr)
    {
        if (empty($arr) || !is_array($arr)) return [];
        foreach ($arr as $k => $v) {
            $data[$k] = json_decode($v, true);
        }
        return $data;
    }

    static function getArrayFromOne($arr)
    {
        if (is_string($arr)) {
            $arr = self::analyJson($arr);
        }
        if (empty($arr) || !is_array($arr)) return [];
        foreach ($arr as $k => $v) {
            $data[$k] = self::analyJson($v);
        }
        return $data;
    }

    static function analyJson($json_str)
    {
//方法一
        $ret = json_decode($json_str, true);
        if (json_last_error() === JSON_ERROR_NONE) {
            return $ret;
        }
        return $json_str;
//方法二
//        $result = $json_str;
//        $json_str = str_replace('\\', '', $json_str);
//        $out_arr = array();
//        preg_match('/{.*}/', $json_str, $out_arr);
//        if (!empty($out_arr)) {
//            $result = json_decode($out_arr[0], TRUE);
//            if(!is_array($result)){
//                $result = $json_str;
//            }
//        }
//        return $result;
    }

    /**
     * Notes:设置并发锁
     * User: wsc
     * Time: 2020/4/21 12:30
     * @param $uid
     * @param $type
     * @param $time
     * @return bool 成功返回true,并发重复返回false
     */
    static function concurrentLock($uid, $type, $time = 2)
    {
        $key = okeys::concurrentLock($uid, $type);
        $res = oo::commonOprRedis('common')->setnx($key, 1);
        if ($res) {
            oo::commonOprRedis('common')->expire($key, $time);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Notes:解锁
     * User: wsc
     * Time: 2020/4/21 12:30
     * @param $uid
     * @param $type
     */
    static function delConcurrentLock($uid, $type)
    {
        $key = okeys::concurrentLock($uid, $type);
        oo::commonOprRedis('common')->delete($key);
    }

    /**
     * 检测倒计时锁
     * @param $uid
     * @param $type
     * @return mixed
     * Created by: Owen
     * Created on: 2020/6/17 9:51
     */
    static function checkCountdownLock($uid, $type)
    {
        $res = oo::commonOprRedis('common')->ttl(okeys::countdownLock($uid, $type));
        if ($res > 0) {
            return $res;
        } else {
            return false;
        }
    }

    /**
     * 检测倒计时锁
     * @param $uid
     * @param $type
     * @param $value
     * @param $time
     * @return mixed
     * Created by: Owen
     * Created on: 2020/6/17 9:51
     */
    static function setCountdownLock($uid, $type, $value = 1, $time = 84600)
    {
        $key = okeys::countdownLock($uid, $type);
        return oo::commonOprRedis('common')->setex($key, $value, $time);
    }


    public static function get($s, $def = '')
    {
        $s = isset($_GET[$s]) ? $_GET[$s] : $_POST[$s];
        $s = isset($s) && $s != '' ? $s : $def;
        if ($s && is_string($s)) $s = htmlspecialchars($s);
        return self::magic_quote($s);
    }

    public static function getPayload()
    {
        return json_decode(file_get_contents("php://input"), true);
    }

    /**
     * 根据magic_quote判断是否为变量添加斜杠
     * @param string $mixVar
     * @return string
     */
    public static function magic_quote($mixVar)
    {
        if (!get_magic_quotes_gpc()) {
            return self::add_slashes($mixVar);
        } else {
            return $mixVar;
        }
    }

    /**
     * 使用反斜线引用字符串
     * @param string $mixVar
     * @return string
     */
    public static function add_slashes($mixVar)
    {
        $temp = '';
        if (is_array($mixVar)) {
            foreach ($mixVar as $key => $value) {
                $temp[$key] = self::add_slashes($value);
            }
        } else {
            $temp = addslashes($mixVar);
        }
        return $temp;
    }

    /**
     * Notes:批量写入
     * @param string $tb
     * @param array $dataArr 二维数组中key必须完全一致
     * @return string
     */
    static function db_intsertArrSQL(string $tb, array $dataArr): string
    {
        $keyStr = array_keys($dataArr[0]);
        $fields = '(`' . implode('`,`', $keyStr) . '`)';

        $formatData = [];
        foreach ($dataArr as $data) {
            $curKeyStr = array_keys($data);
            if ($keyStr != $curKeyStr) {
                return 'not match';
            }

            $keyStr = array_keys($data);

            foreach ($data as &$val) {
                if (is_array($val)) {
                    $val = json_encode($val);
                }

                $val = str_replace("'", "\'", $val);
            }

            $formatData[] = '(\'' . implode('\',\'', array_values($data)) . '\')';
        }

        $values = implode(',', $formatData);

        return "INSERT INTO {$tb} {$fields} VALUES {$values};";
    }

    /**
     * Notes:批量写入
     * @param string $tb
     * @param array $dataArr 二维数组中key必须完全一致
     * @return string
     */
    static function db_replaceArrSQL(string $tb, array $dataArr): string
    {
        $keyStr = array_keys($dataArr[0]);
        $fields = '(`' . implode('`,`', $keyStr) . '`)';

        $formatData = [];
        foreach ($dataArr as $data) {
            $curKeyStr = array_keys($data);
            if ($keyStr != $curKeyStr) {
                return 'not match';
            }

            foreach ($data as &$val) {
                if (is_array($val)) {
                    $val = json_encode($val);
                }

                $val = str_replace("'", "\'", $val);
            }

            $formatData[] = '(\'' . implode('\',\'', array_values($data)) . '\')';
        }

        $values = implode(',', $formatData);

        return "REPLACE INTO {$tb} {$fields} VALUES {$values};";
    }

    /**
     * Notes:格式化 更新sql语句
     * @param $tb
     * @param $data
     * @param $w
     * @return string
     */
    public static function db_updateSQL($tb, $data, $w): string
    {
        $sql = "UPDATE {$tb} SET ";

        self::db_serialization($data);

        $arr = self::db_fieldAllow($data);
        foreach ($arr as $k => $v) {
            $sql .= "`$k`=$v,";
        }
        $sql = trim($sql, ',');
        $sql .= " WHERE {$w}";
        return $sql;
    }

    /**
     * Notes:格式化 插入sql语句
     * @param $tb
     * @param $data
     * @return string
     */
    public static function db_insertSQL($tb, $data): string
    {
        self::db_serialization($data);

        $arr = self::db_fieldAllow($data);

        $keys = array_keys($arr);
        $fields = '`' . implode('`, `', $keys) . '`';
        $values = implode(",", array_values($arr));
        return "INSERT INTO " . $tb . " ({$fields}) VALUES({$values})";
    }

    /**
     * Notes:格式化 插入sql语句
     * @param $tb
     * @param $data
     * @return string
     */
    public static function db_upsertSQL($tb, $data): string
    {
        self::db_serialization($data);

        $arr = self::db_fieldAllow($data);

        $fields = [];
        $values = [];
        $duplicates = [];
        foreach ($arr as $key => $val) {
            $fields[] = "`{$key}`";
            $values[] = $val;
            $duplicates[] = "`{$key}` = $val";
        }

        $fields = implode(",", $fields);
        $values = implode(",", $values);
        $duplicates = implode(",", $duplicates);
        return "INSERT INTO " . $tb . " ({$fields}) VALUES({$values}) ON DUPLICATE KEY UPDATE {$duplicates}";
    }

    public static function db_serialization(&$data)
    {
        foreach ($data as &$item) {
            if (is_array($item)) {
                $item = json_encode($item, JSON_NUMERIC_CHECK);
            }
        }
    }

    /**
     * Notes:过滤非法字符
     * @param $data
     * @return array
     */
    public static function db_fieldAllow($data): array
    {
        $ret = [];
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $val = floatval($val);
            } elseif (preg_match('/^\(\w*(\+|\-|\*|\/)?\w*\)$/i', $val)) {
                // 支持在字段的值里面直接使用其它字段 ,例如 (score+1) (name) 必须包含括号
                $val = $val;
            } elseif (is_string($val)) {
                //将字符串中的单引号（'）、双引号（"）、反斜线（\）与 NUL（NULL 字符转义
                $val = "'" . addslashes($val) . "'";

            }
            $ret[$key] = $val;
        }
        return $ret;
    }

    /**
     * Notes:写库字段过滤验证
     * User: wsc
     * Time: 2020/5/15 16:03
     * @param $string
     * @return bool
     */
    public static function sqlFormat($string)
    {
        if (empty($string)) return false;
        $sensitive = "insert|update|delete|..\/|.\/|union|into|load_file|outfile";
        $sen = explode('|', $sensitive);
        $ret = false;
        foreach ($sen as $v) {
            $pattern = '/' . $v . '/';
            preg_match($pattern, $string, $ret);
            if (!empty($ret)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取IP
     * @return mixed|null
     * Created by: Owen
     * Created on: 2019/9/23 20:15
     */
    public static function getIp()
    {
        $ip = '';
        if ($_SERVER['HTTP_CLIENT_IP'] && strcasecmp($_SERVER['HTTP_CLIENT_IP'], 'unknown')) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif ($_SERVER['HTTP_X_FORWARDED_FOR'] && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown')) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (isset($_SERVER['REMOTE_ADDR']) && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
            $ip = $_SERVER['REMOTE_ADDR'];
        } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $ip;
        }
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            oo::logs()->debug3(['ip' => $ip], 'IPV6.log');
        }
        return null;
    }

    /**
     * Notes:获取用户国家信息合集
     * User: wsc
     * Time: 2020/5/21 18:31
     * @param $ip
     * @param int $type
     * @return array|string|null
     * @throws Exception
     */
    static function ip_info($ip, $type = 1)
    {
        $data = [];
        if (empty($ip)) return $data;
        switch ($type) {
            case 1://本地IP库先查
                $info = oo::ipAlg()->memorySearch($ip);
                if (!empty($info) && is_string($info['region'])) {//本地IP库先查
                    $country = oo::cfg('country');
                    $addressInfo = explode('|', $info['region']);
                    $data['country_code'] = $country[$addressInfo[0]];
                    if (empty($data['country_code'])) {
                        oo::logs()->debug3(["type" => 1, "ip" => $ip, "res" => $info], 'getIp');
                    }
                } else {
                    $data = self::ip_info2($ip);
                }
                break;
            case 2://www.geoplugin.net获取国家信息，频率每分钟120内
                $data = self::ip_info2($ip);
                break;
            case 3://887d.com获取国家信息，频率未知
                $data = self::ip_info3($ip);
                break;
            default:
                break;
        }
        return $data;
    }

    /**
     * 通过第三方获取Ip所在国家信息
     * @param null $ip
     * @param string $purpose
     * @param bool $deep_detect
     * @return array|null|string
     * @link https://www.geoplugin.com/examples
     */
    static function ip_info2($ip = NULL, $purpose = "location", $deep_detect = TRUE)
    {
        $output = NULL;
        if (empty($ip) || $ip == '') return [];
        if (filter_var($ip, FILTER_VALIDATE_IP) === FALSE) {
            $ip = $_SERVER["REMOTE_ADDR"];
            if ($deep_detect) {
                if (filter_var(@$_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP))
                    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
                if (filter_var(@$_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP))
                    $ip = $_SERVER['HTTP_CLIENT_IP'];
            }
        }
        $purpose = str_replace(array("name", "\n", "\t", " ", "-", "_"), NULL, strtolower(trim($purpose)));
        $support = array("country", "countrycode", "state", "region", "city", "location", "address");
        $continents = array(
            "AF" => "Africa",
            "AN" => "Antarctica",
            "AS" => "Asia",
            "EU" => "Europe",
            "OC" => "Australia (Oceania)",
            "NA" => "North America",
            "SA" => "South America"
        );
        if (filter_var($ip, FILTER_VALIDATE_IP) && in_array($purpose, $support)) {
            $res = file_get_contents("http://www.geoplugin.net/json.gp?ip=" . $ip);
            $ipdat = @json_decode($res);
            if (@strlen(trim($ipdat->geoplugin_countryCode)) == 2) {
                switch ($purpose) {
                    case "location":
                        $output = array(
                            "city" => @$ipdat->geoplugin_city,
                            "state" => @$ipdat->geoplugin_regionName,
                            "country" => @$ipdat->geoplugin_countryName,
                            "country_code" => @$ipdat->geoplugin_countryCode,
                            "continent" => @$continents[strtoupper($ipdat->geoplugin_continentCode)],
                            "continent_code" => @$ipdat->geoplugin_continentCode
                        );
                        break;
                    case "address":
                        $address = array($ipdat->geoplugin_countryName);
                        if (@strlen($ipdat->geoplugin_regionName) >= 1)
                            $address[] = $ipdat->geoplugin_regionName;
                        if (@strlen($ipdat->geoplugin_city) >= 1)
                            $address[] = $ipdat->geoplugin_city;
                        $output = implode(", ", array_reverse($address));
                        break;
                    case "city":
                        $output = @$ipdat->geoplugin_city;
                        break;
                    case "state":
                        $output = @$ipdat->geoplugin_regionName;
                        break;
                    case "region":
                        $output = @$ipdat->geoplugin_regionName;
                        break;
                    case "country":
                        $output = @$ipdat->geoplugin_countryName;
                        break;
                    case "countrycode":
                        $output = @$ipdat->geoplugin_countryCode;
                        break;
                }
            } else {
                oo::logs()->debug3(["type" => 2, "ip" => $ip, "res" => $res], 'getIp');
                $output = self::ip_info3($ip);
            }
        }
        return $output;
    }

    /**
     * Notes:获取国家简称（备用）
     * User: wsc
     * Time: 2020/5/19 16:12
     * @param $ip
     * @param int $limit 复用次数
     * @return array|null
     * @link https://887d.com
     */
    static function ip_info3($ip, $limit = 1)
    {
        $data = [];
        $url = "https://887d.com/api/ip?q={$ip}";
        $res = self::sendCurl($url);
        if (@strlen(trim($res)) == 2) {
            $data['country_code'] = $res;
        } else {
            oo::logs()->debug3(["type" => 3, "ip" => $ip, "res" => $res], 'getIp');
        }
        if (empty($data) && $limit < 2) {//再试一次
            $data = self::ip_info2($ip, 2);
        }
        return $data;
    }

    /**
     * 远程调用
     * @param $url
     * @param mixed $sendData
     * @param string $type
     * @return bool|string
     * Created by: Owen
     * Created on: 2020/5/22 16:36
     */
    static function sendCurlPastThird($url, $sendData = [], $type = "get")
    {
        if (IS_DEBUF) {
            if (empty($sendData)) {
                $sendData = ['sid' => 1, 'lid' => 1, 'mod' => "Test", 'act' => "sendCurl", 'url' => $url, 'service' => 1];
            } else {
                $sendData['sid'] = 1;
                $sendData['lid'] = 1;
                $sendData['service'] = 1;
            }
            $url = "https://god.superant.vip/api/gateway.php";
            $type = "post";
        }
        return self::sendCurl($url, $sendData, $type);
    }

    /**
     * Notes:通用curl请求
     * User: wsc
     * Time: 2020/6/12 17:10
     * @param $url
     * @param string $sendData
     * @param string $type
     * @return bool|string
     */
    static function sendCurl($url, $sendData = '', $type = "get")
    {
        //初始化
        $curl = curl_init();
        //设置
        curl_setopt($curl, CURLOPT_URL, $url);
        //设置头文件的信息作为数据流输出
        curl_setopt($curl, CURLOPT_HEADER, false);
        //设置获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        //设置连接超时时间
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 20);
        //设置1秒超时
        curl_setopt($curl, CURLOPT_TIMEOUT, 30);
        //https 设置
        if (strpos($url, 'https') !== false) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        }
        if ($type == 'post') {
            //设置post方式提交
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $sendData);
        }
        //执行命令
        $data = curl_exec($curl);
        //关闭URL请求
        curl_close($curl);
        return $data;
    }

    /**
     * MAC 地址转换 SiteUid
     * @param $macAddr
     * @return int|string
     * Created by: Owen
     * Created on: 2020/5/22 16:38
     */
    static function macToSiteUid($macAddr)
    {
        $macAddr = trim($macAddr);
        if (strlen($macAddr) > 30) {
            return 0;
        }
        $match = array();
        if (!preg_match("/^[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f][:-]" . "[0-9a-f][0-9a-f]/i", $macAddr, $match)) {
            return 0;
        }
        return base_convert('0x' . strtr($macAddr, [':' => '']), 16, 10);
    }

    /**
     * 取整
     * @param $num
     * @param int $rounding
     * @return int|mixed
     * Created by: Owen
     * Created on: 2020/5/29 16:48
     */
    static function Rounding($num, $rounding = 1000)
    {
        $num = max(0, intval($num));
        if ($num < $rounding) {
            return $num;
        }
        $new_num = ($num / $rounding);
        return intval(floor($new_num) * $rounding);
    }

    /**
     * Notes:创建表
     * User: wsc
     * Time: 2020/6/12 17:17
     * @param $tbName "crazyGod_log.assetslog_20200612"
     * @return bool
     */
    static function createTable($tbName, $sql)
    {
        $res = true;
        $dbInfo = explode('.', $tbName);

        $database = $dbInfo[0];
        $table = $dbInfo[1];
        $query = "select count(*) as count from information_schema.TABLES t where t.TABLE_SCHEMA ='{$database}' and t.TABLE_NAME ='{$table}'";

        $tbInfo = oo::commonOprDb($dbInfo[0])->getOne($query, 1);

        if (empty($tbInfo['count'])) {
            $res = oo::commonOprDb($dbInfo[0])->query($sql);
        } else {
            $res = false;
        }
        return $res;
    }


    /**
     * 判断email
     * @param $email
     * @return bool
     * Created by: Owen
     * Created on: 2020/6/28 15:27
     */
    static function isEmail($email)
    {
        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return true;
        } else {
            return false;
        }
    }

    //判断否为UTF-8编码
    static function is_utf8($str)
    {
        $len = strlen($str);
        for ($i = 0; $i < $len; $i++) {
            $c = ord($str[$i]);
            if ($c > 128) {
                if (($c > 247)) {
                    return false;
                } elseif ($c > 239) {
                    $bytes = 4;
                } elseif ($c > 223) {
                    $bytes = 3;
                } elseif ($c > 191) {
                    $bytes = 2;
                } else {
                    return false;
                }
                if (($i + $bytes) > $len) {
                    return false;
                }
                while ($bytes > 1) {
                    $i++;
                    $b = ord($str[$i]);
                    if ($b < 128 || $b > 191) {
                        return false;
                    }
                    $bytes--;
                }
            }
        }
        return true;
    }

    //判断是否base64加密
    static function is_base64($str)
    {
        //这里多了个纯字母和纯数字的正则判断
        if (@preg_match('/^[0-9]*$/', $str) || @preg_match('/^[a-zA-Z]*$/', $str)) {
            return false;
        } elseif (is_utf8(base64_decode($str)) && base64_decode($str) != '') {
            return true;
        }
        return false;
    }

    /**
     * 今日剩余时间
     * @return false|int
     * Created by: Owen
     * Created on: 2019/11/29 20:09
     */
    public static function todayDeadline()
    {
        return strtotime('23:59:59') - time();
    }

    /**
     * 返回表结构的所有字段
     */
    static function getTableColumns(string $tableName): array
    {
        $tableNameArr = explode('.', $tableName);
        $fieldsInfo = oo::commonOprDb('games')->getAll("select COLUMN_NAME from information_schema.COLUMNS
                    where table_name = '{$tableNameArr[1]}' and table_schema = '{$tableNameArr[0]}'");

        return array_column($fieldsInfo, 'COLUMN_NAME');
    }

    # 解析奖励
    public static function ParseRewards(array $rewards, $line = 0): array
    {
        $prize = oo::commonOprModel("ActBase")->parseLineRewards($rewards, $line);

        $reward = [];
        foreach ($prize as $item) {
            $reward[] = [
                "propsId" => $item['type'],
                "num" => $item['num'],
                "rtype" => $item['rtype'],
                "skin" => $item['skin']
            ];
        }

        return $reward;
    }
}