<?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;
	}