<?php


use think\cache\driver\Redis;
use app\common\lib\Storage;
use app\common\lib\Convert;
use think\Loader;

use think\Response;
use think\exception\HttpResponseException;

function encode($id = 0){
	$obj = new convert(32);
	$res = $obj->idToString($id);
	return $res;
}

function decode($string = ''){
    
    if(is_numeric($string)){
        return $string;
    }
	$obj = new convert(32);
	$res = $obj->stringToId($string);
	return $res;
}


function returnJson($data = '',array $header = [],$type = 'json'){
        $result = $data;
        $header['Access-Control-Allow-Origin']  = '*';
        $header['Access-Control-Allow-Headers'] = 'X-Requested-With,Content-Type,XX-Device-Type,XX-Token';
        $header['Access-Control-Allow-Methods'] = 'GET,POST,PATCH,PUT,DELETE,OPTIONS';
        
        $response   = Response::create($result, $type)->header($header);
        throw new HttpResponseException($response);
}        

/**
 * 解密用strDecode加密的字符串
 * @param        $string    要解密的字符串
 * @param string $key       加密时salt
 * @param int    $expiry    多少秒后过期
 * @param string $operation 操作,默认为DECODE
 * @return bool|string
 */
function strDecode($string, $key = '', $expiry = 0, $operation = 'DECODE')
{
    $ckey_length = 4;

    $key  = md5($key ? $key : config("database.authcode"));
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';

    $cryptkey   = $keya . md5($keya . $keyc);
    $key_length = strlen($cryptkey);

    $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 = [];
    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 {
        return $keyc . str_replace('=', '', base64_encode($result));
    }

}

/**
 * 加密字符串
 * @param        $string 要加密的字符串
 * @param string $key    salt
 * @param int    $expiry 多少秒后过期
 * @return bool|string
 */
function strEncode($string, $key = '', $expiry = 0)
{
    return strDecode($string, $key, $expiry, "ENCODE");
}


function getOrgId()
{
    return session('org_id');
}



function getUserId()
{
    return session('userId');
}

function getStudentId()
{
    return session('studentId');
}

/**
 * 设置 token 到缓存
 * @param $userId
 * @param $deviceType
 * @return string 用户 token

 */
function setToken($userId,$deviceType)
{

    $time = 24 * 3600 * 1 ;

    $currentTime    = time();
    $expireTime     = $currentTime + $time;
    $token          = md5(uniqid()) . md5(uniqid());

    $tokenData = [
                    'token'       => $token,
                    'user_id'     => $userId,
                    'expire_time' => $expireTime,
                    'create_time' => $currentTime,
                    'device_type' => $deviceType
                ];


    cache('token_' . $token,$tokenData, $time ,'token');

    $tokenUserData = cache('token_user_' . $userId );

    $tokenUserData[] = $tokenData;
    cache('token_user_' . $userId,$tokenUserData ,null ,'token_user' );
    removeToken($userId);

    return $token;
}

/**
 * 生成用户 token
 * @param $userId
 * @param $deviceType
 * @return string 用户 token
 * @throws \think\Exception
 * @throws \think\db\exception\DataNotFoundException
 * @throws \think\db\exception\ModelNotFoundException
 * @throws \think\exception\DbException
 * @throws \think\exception\PDOException
 */
function generateUserToken($userId, $deviceType)
{
    $userTokenQuery = Db::name("user_token")
        ->where('user_id', $userId)
        ->where('device_type', $deviceType);
    $findUserToken  = $userTokenQuery->find();
    $currentTime    = time();
    $expireTime     = $currentTime + 24 * 3600 * 180;
    $token          = md5(uniqid()) . md5(uniqid());
    if (empty($findUserToken)) {
        Db::name("user_token")->insert([
            'token'       => $token,
            'user_id'     => $userId,
            'expire_time' => $expireTime,
            'create_time' => $currentTime,
            'device_type' => $deviceType
        ]);
    } else {
        if ($findUserToken['expire_time'] > time() && !empty($findUserToken['token'])) {
            $token = $findUserToken['token'];
        } else {
            Db::name("user_token")
                ->where('user_id', $userId)
                ->where('device_type', $deviceType)
                ->update([
                    'token'       => $token,
                    'expire_time' => $expireTime,
                    'create_time' => $currentTime
                ]);
        }

    }

    return $token;
}


/**
 * 检查手机格式，中国手机不带国家代码，国际手机号格式为：国家代码-手机号
 * @param $mobile
 * @return bool
 */
function checkMobile($mobile)
{
    if (preg_match('/(^(13\d|14\d|15\d|16\d|17\d|18\d|19\d)\d{8})$/', $mobile)) {
        return true;
    } else {
        if (preg_match('/^\d{1,4}-\d{5,11}$/', $mobile)) {
            if (preg_match('/^\d{1,4}-0+/', $mobile)) {
                //不能以0开头
                return false;
            }

            return true;
        }

        return false;
    }
}

/**
 * 区分大小写的文件存在判断
 * @param string $filename 文件地址
 * @return boolean
 */
function fileExistsCase($filename)
{
    if (is_file($filename)) {
        if (APP_DEBUG) {
            if (basename(realpath($filename)) != basename($filename))
                return false;
        }
        return true;
    }
    return false;
}

/**
 * 字符串命名风格转换
 * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
 * @param string  $name    字符串
 * @param integer $type    转换类型
 * @param bool    $ucfirst 首字母是否大写（驼峰规则）
 * @return string
 */
function parseName($name, $type = 0, $ucfirst = true)
{
    return Loader::parseName($name, $type, $ucfirst);
}

/**
 * 获取当前主题名
 * @return string
 */
function getCurrentTheme()
{
    if (PHP_SAPI != 'cli') {
        static $_currentTheme;

        if (!empty($_currentTheme)) {
            return $_currentTheme;
        }
    }

    $t     = 't';
    $theme = config('template.default_theme');

    $cmfDetectTheme = config('template.detect_theme');
    if ($cmfDetectTheme) {
        if (isset($_GET[$t])) {
            $theme = $_GET[$t];
            cookie('template', $theme, 864000);
        } elseif (cookie('template')) {
            $theme = cookie('template');
        }
    }


    $designT = '_design_theme';
    if (isset($_GET[$designT])) {
        $theme = $_GET[$designT];
        cookie('design_theme', $theme, 4);
    } elseif (cookie('design_theme')) {
        $theme = cookie('design_theme');
    }

    $_currentTheme = $theme;

    return $theme;
}

/**
 * 密码加密方法
 * @param string $pw       要加密的原始密码
 * @param string $authCode 加密字符串
 * @return string
 */


function password($pw, $authCode = '')
{
    if (empty($authCode)) {
        $authCode = config('database.authcode');
    }
    $result = md5(md5($authCode . $pw));
    return $result;
}

function passwordOld($pw, $authCode = '')
{
    if (empty($authCode)) {
        $authCode = 'pCNIJBbyEvnPxgJxbO';
    }
    $result = "###" . md5(md5($authCode . $pw));
    return $result;
}


/**
 * 密码比较方法,所有涉及密码比较的地方都用这个方法
 * @param string $password     要比较的密码
 * @param string $passwordInDb 数据库保存的已经加密过的密码
 * @return boolean 密码相同，返回true
 */
function comparePassword($password, $passwordInDb)
{
    if (strpos($passwordInDb, "###") === 0) {
        return passwordOld($password) == $passwordInDb;
    } else {
        return password($password) == $passwordInDb;
    }
    return password($password) == $passwordInDb;
}


/**
 * 返回带协议的域名
 */
function getDomain()
{
    return request()->domain();
}

/**
 * 获取网站根目录
 * @return string 网站根目录
 */
function getRoot()
{
    $root = request()->root();
    $root = str_replace("//", '/', $root);
    $root = str_replace('/index.php', '', $root);
    if (defined('APP_NAMESPACE') && APP_NAMESPACE == 'api') {
        $root = preg_replace('/\/api(.php)$/', '', $root);
    }

    $root = rtrim($root, '/');

    return $root;
}

/**
 * 转化数据库保存文件的文件路径，为可以访问的url
 * @param string $file  文件路径，数据存储的文件相对路径
 * @param string $style 文件样式,支持各大云存储
 * @return string 文件链接
 */
function getAssetUrl($file, $style = 'watermark')
{
    if (empty($file)) {
        return '';
    }

    if (strpos($file, "http") === 0) {
        return $file;
    } else if (strpos($file, "/") === 0) {
        return getDomain() . $file;
    } else {
        $storage = Storage::instance();
        return $storage->getImageUrl($file, $style);
    }
}

/**
 * 随机字符串生成
 * @param int $len 生成的字符串长度
 * @return string
 */
function getRandomString($len = 6)
{
    $chars    = [
        "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", "0", "1", "2",
        "3", "4", "5", "6", "7", "8", "9"
    ];
    $charsLen = count($chars) - 1;
    shuffle($chars);    // 将数组打乱
    $output = "";
    for ($i = 0; $i < $len; $i++) {
        $output .= $chars[mt_rand(0, $charsLen)];
    }
    return $output;
}


/**
 * 获取文件扩展名
 * @param string $filename 文件名
 * @return string 文件扩展名
 */
function getFileExtension($filename)
{
    $pathinfo = pathinfo($filename);
    return strtolower($pathinfo['extension']);
}

/**
 * 获取上传配置
 */
function getUploadSetting()
{
    $uploadSetting = getOption('upload_setting','overall');
    if (empty($uploadSetting) || empty($uploadSetting['file_types'])) {
        $uploadSetting = [
            'file_types' => [
                'image' => [
                    'upload_max_filesize' => '10240',//单位KB
                    'extensions'          => 'jpg,jpeg,png,gif,bmp4'
                ],
                'video' => [
                    'upload_max_filesize' => '204800',
                    'extensions'          => 'mp4,avi,wmv,rm,rmvb,mkv,mov'
                ],
                'audio' => [
                    'upload_max_filesize' => '10240',
                    'extensions'          => 'mp3,wma,wav'
                ],
                'library' => [
                    'upload_max_filesize' => '10240',
                    'extensions'          => 'jpg,jpeg,png,gif,bmp4,mp3,wma,wav'
                ],
                'file'  => [
                    'upload_max_filesize' => '10240',
                    'extensions'          => 'txt,pdf,doc,docx,xls,xlsx,ppt,pptx,zip,rar'
                ]
            ],
            'chunk_size' => 512,//单位KB
            'max_files'  => 20 //最大同时上传文件数
        ];
    }

    if (empty($uploadSetting['upload_max_filesize'])) {
        $uploadMaxFileSizeSetting = [];
        foreach ($uploadSetting['file_types'] as $setting) {
            $extensions = explode(',', trim($setting['extensions']));
            if (!empty($extensions)) {
                $uploadMaxFileSize = intval($setting['upload_max_filesize']) * 1024;//转化成B
                foreach ($extensions as $ext) {
                    if (!isset($uploadMaxFileSizeSetting[$ext]) || $uploadMaxFileSize > $uploadMaxFileSizeSetting[$ext]) {
                        $uploadMaxFileSizeSetting[$ext] = $uploadMaxFileSize;
                    }
                }
            }
        }

        $uploadSetting['upload_max_filesize'] = $uploadMaxFileSizeSetting;
    }

    return $uploadSetting;
}



// 获取网站信息
function getSiteInfo()
{
    return getOption('site_info','overall');
}


/**
 * 设置系统配置，通用
 * @param string $key     配置键值,都小写
 * @param array  $data    配置值，数组
 * @param string   $range 配置范围 personal,org,overall
 * @param bigint   $objId 对象id
 * @param bool   $replace 是否完全替换
 * @return bool 是否成功

 */
function setOption($key, $data, $range = 'overall', $objId = 0, $replace = false)
{
    if ($range != 'overall' && $range != 'org' && $range != 'personal') {
        return false;
    }

    if (!is_array($data) || empty($data) || !is_string($key) || empty($key)) {
        return false;
    }

    $key        = strtolower($key);
    $option     = [];
    $findOption = Db::name('config')->where('config_range', $range)->where('obj_id', $objId)->where('config_name', $key)->find();
    if ($findOption) {
        if (!$replace) {
            $oldOptionValue = json_decode($findOption['config_value'], true);
            if (!empty($oldOptionValue)) {
                $data = array_merge($oldOptionValue, $data);
            }
        }

        $option['config_value'] = json_encode($data);
        $option['config_range'] = $range;
        $option['obj_id'] = $objId;

        Db::name('config')->where('config_range', $range)->where('obj_id', $objId)->where('config_name', $key)->update($option);
    } else {
        $option['config_name']  = $key;
        $option['config_value'] = json_encode($data);
        $option['config_range'] = $range;
        $option['obj_id'] = $objId;
        Db::name('config')->insert($option);
    }

    cache('config_' . $range . '_' . $objId . '_' . $key, null , null , 'config');//删除缓存

    return true;
}

/**
 * 获取系统配置，通用
 * @param string $key 配置键值,都小写
 * @param string   $range 配置范围 personal,org,overall
 * @param bigint   $objId 对象id
 * @return array
 */
function getOption($key, $range = 'overall', $objId = 0)
{
    if ($range != 'overall' && $range != 'org' && $range != 'personal') {
        return false;
    }

    if (!is_string($key) || empty($key)) {
        return [];
    }

    if (PHP_SAPI != 'cli') {
        static $cmfGetOption;

        if (empty($cmfGetOption)) {
            $cmfGetOption = [];
        } else {
            if (!empty($cmfGetOption[$key])) {
                return $cmfGetOption[$key];
            }
        }
    }

    $optionValue = cache('config_' . $range . '_' . $objId . '_' . $key);

    if (empty($optionValue)) {
        $optionValue = Db::name('config')->where('config_range', $range)->where('obj_id', $objId)->where('config_name', $key)->value('config_value');
        if (!empty($optionValue)) {
            $optionValue = json_decode($optionValue, true);

            cache('config_' . $range . '_' . $objId . '_' . $key, $optionValue, null , 'config');
        }
    }

    $cmfGetOption[$key] = $optionValue;

    return $optionValue;
}



/*
    打印数组函数
*/
function p($data){
    // 定义样式
    $str='<pre style="display: block;padding: 9.5px;margin: 44px 0 0 0;font-size: 13px;line-height: 1.42857;color: #333;word-break: break-all;word-wrap: break-word;background-color: #F5F5F5;border: 1px solid #CCC;border-radius: 4px;">';
    // 如果是boolean或者null直接显示文字；否则print
    if (is_bool($data)) {
        $show_data=$data ? 'true' : 'false';
    }elseif (is_null($data)) {
        $show_data='null';
    }else{
        $show_data=print_r($data,true);
    }
    $str.=$show_data;
    $str.='</pre>';
    echo $str;
}