key = 'odsniK8Xk0tMuJbwyztEPjRLLo'; $this->sk = '9936be1a0451712e0f58866ac6be7a4f'; } public function opensd($post = []) { $API_URL = 'https://api.wike.cc/api/painting/opensd'; $post['key'] = $this->key; $res = $this->send($API_URL, $post, 'POST', true, $this->sk); return $res; } public function opensdDetail($id) { $API_URL = 'https://api.wike.cc/api/painting/result'; $post['key'] = $this->key; $post['id'] = $id; $res = $this->send($API_URL, $post, 'GET', true, $this->sk); return $res; } /** * 获取框架 root 路径. * * @return bool */ public static function frameRootPath() { return DIRECTORY_SEPARATOR === '\\' ? 'E:\TP6_V4' : '/Users/wangdakun/Desktop/wangdakun/TP6_V4'; } public static function send($API_URL, $get_post_data, $type, $ifsign, $sk) { $get_post_data = http_build_query($get_post_data); if ($ifsign) { $sign = md5($get_post_data . $sk); $res = self::send_curl($API_URL, $type, $get_post_data, $sign); } else { $res = self::send_curl($API_URL, $type, $get_post_data, null); } return $res; } public static function send_curl($API_URL, $type, $get_post_data, $sign) { $ch = curl_init(); if ('POST' == $type) { curl_setopt($ch, CURLOPT_URL, $API_URL); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $get_post_data); } elseif ('GET' == $type) { curl_setopt($ch, CURLOPT_URL, $API_URL . '?' . $get_post_data); } if ($sign) { curl_setopt($ch, CURLOPT_HTTPHEADER, ['sign:' . $sign]); } curl_setopt($ch, CURLOPT_REFERER, $API_URL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 300); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $resdata = curl_exec($ch); curl_close($ch); return $resdata; } public static function getAccessToken() { $curl = curl_init(); $postData = [ 'grant_type' => getenv('BAIDU_GRANT_TYPE'), 'client_id' => getenv('BAIDU_CLIENT_ID'), 'client_secret' => getenv('BAIDU_CLIENT_SECRET'), ]; curl_setopt_array($curl, [ CURLOPT_URL => 'https://aip.baidubce.com/oauth/2.0/token', CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_POSTFIELDS => http_build_query($postData), ]); $response = curl_exec($curl); curl_close($curl); $rtn = json_decode($response); return $rtn->access_token; } /** * @desc 过滤emoji表情 * * @return string|string[]|null */ public static function filterEmoji($str) { return preg_replace_callback('/./u', static fn (array $match) => \strlen($match[0]) >= 4 ? '' : $match[0], $str); } /** * @desc 字节转换 * * @return string */ public static function sizeConvert(int $numSize) { if ($numSize >= 1073741824) { $charSize = round($numSize / 1024 ** 3 * 100) / 100 . ' GB'; } elseif ($numSize >= 1048576) { // 转成MB $charSize = round($numSize / 1024 ** 2 * 100) / 100 . ' MB'; } elseif ($numSize >= 1024) { // 转成KB $charSize = round($numSize / 1024 * 100) / 100 . ' KB'; } else { // 不转换直接输出 $charSize = $numSize . ' B'; } return $charSize; } /** * @desc 数字单位转换 * * @return string */ public static function numberConvert(int $number) { if ($number >= 1000 && $number < 10000) { $number = sprintf('%.1f', $number / 1000) . ' K'; } elseif ($number >= 10000) { $number = sprintf('%.1f', $number / 10000) . ' W'; } elseif ($number >= 1000000) { $number = sprintf('%.1f', $number / 10000) . ' M'; } return $number; } /** * @desc 生成 hash token */ public static function hashToken(string $value) { $hash = hash_hmac('sha1', $value . mt_rand() . time(), mt_rand(), true); return str_replace('=', '', strtr(base64_encode($hash), '+/', '-_')); } /** * @desc 是否微信环境 * * @return bool|mixed */ public static function isWeixin() { return str_contains($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') ? true : false; } /** * @desc ssl 加密 * * @param $str 待加密字符 * @param string $key 加密key * @param string $iv 偏移iv * * @return string */ public static function encrypt($str, $key = 'cdlchdwxcdh5', $iv = 'cdlchd0123456789') { return bin2hex(openssl_encrypt($str, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv)); } /** * @desc ssl 解密 * * @param string $str 待解密字符 * @param string $key 加密key * @param string $iv 偏移iv * * @return string */ public static function decrypt($str, $key = 'cdlchdwxcdh5', $iv = 'cdlchd0123456789') { return openssl_decrypt(hex2bin($str), 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv); } /** * @desc 记录日志 */ public static function apiLogs(array $data, string $remarks = ''): void { $request = request(); $data = [ 'token' => $request->header('token', null), 'uid' => Auth::$userId, 'url' => $request->url(), 'controller' => $request->controller(), 'func' => $request->action(), 'method' => $request->method(), 'ip' => $request->ip(), 'params' => json_encode($data, 256), 'remarks' => $remarks, 'day' => strtotime('today'), 'create' => time(), ]; $rdsConf = Config::get('lc.redis'); if ($rdsConf['log_open']) { $redis = Redis::instance(); $redis->select($rdsConf['db']); $redis->rPush(env('id') . '_apilogs', json_encode($data, 256)); } else { Db::name('api_logs')->insert($data); } } /** * @desc 将xml转为array * * @return array * * @throws \Exception */ public static function xmlToArray($xml) { if (!$xml) { throw new \Exception('xml数据异常!'); } // 禁止引用外部xml实体 libxml_disable_entity_loader(true); return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); } /** * @desc 输出xml字符 * * @param array $data * * @return string * * @throws \Exception */ public static function arrayToXml($data) { if (!\is_array($data) || \count($data) <= 0) { throw new \Exception('数组数据异常!'); } $xml = ''; foreach ($data as $key => $val) { if (is_numeric($val)) { $xml .= '<' . $key . '>' . $val . ''; } else { $xml .= '<' . $key . '>'; } } $xml .= ''; return $xml; } /** * @desc 按字典序生成签名 * * @param array $data 签名数据 * @param string $key 前面key * * @return string */ public static function makeSign(array $data, string $key) { // 1. 按字典序排序参数 ksort($data); $string = self::signUrlParams($data); // 2. 在string后加入KEY $string = $string . '&key=' . $key; // 3. MD5加密 $string = md5($string); // 4. 所有字符转为大写 return strtoupper($string); } /** * @desc 获取毫秒级别的时间戳 */ public static function millisecond() { // 获取毫秒的时间戳 $time = explode(' ', microtime()); $time = $time[1] . ($time[0] * 1000); $time2 = explode('.', $time); return $time2[0]; } /** * @desc 产生随机字符串,不长于32位 * * @param int $length * * @return string 产生的随机字符串 */ public static function generateNonceStr($length = 32) { $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; $str = ''; for ($i = 0; $i < $length; ++$i) { $str .= substr($chars, mt_rand(0, \strlen($chars) - 1), 1); } return $str; } /** * @desc 对emoji表情转义 * * @return string */ public static function emojiEncode($str) { $strEncode = ''; $length = mb_strlen($str, 'utf-8'); for ($i = 0; $i < $length; ++$i) { $tmpStr = mb_substr($str, $i, 1, 'utf-8'); if (\strlen($tmpStr) >= 4) { $strEncode .= '[[EMOJI:' . rawurlencode($tmpStr) . ']]'; } else { $strEncode .= $tmpStr; } } return $strEncode; } /** * @desc 对emoji表情转反义 * * @return string|string[]|null */ public static function emojiDecode($str) { return preg_replace_callback('|\[\[EMOJI:(.*?)\]\]|', static fn ($matches) => rawurldecode($matches[1]), $str); } /** * @desc 判断请求机型 * * @return string */ public static function deviceType() { $agent = strtolower($_SERVER['HTTP_USER_AGENT']); $type = 'other'; // 分别进行判断 if (strpos($agent, 'iphone') || strpos($agent, 'ipad')) { $type = 'ios'; } if (strpos($agent, 'android')) { $type = 'android'; } return $type; } /** * @desc 记录日志 * * @param string $filename 文件名 * @param string $log 日志内容 * @param float|int $fileSize 文件日志大小,默认最大2M,超过则重命名 */ public static function log(string $filename, string $log, $fileSize = 2 * 1024 * 1024): void { $path = \dirname($filename); if (!is_dir($path)) { mkdir($path, 0755, true); } if (is_file($filename) && floor($fileSize) <= filesize($filename)) { try { rename($filename, \dirname($filename) . \DIRECTORY_SEPARATOR . time() . '-' . basename($filename)); } catch (\Exception $e) { } } error_log($log, 3, $filename); } /** * 求两点之间的距离. * * @param $thisLongitude 当前经度 * @param $thisLatitude 当前纬度 * @param $stayLongitude 待计算经度 * @param $stayLatitude 待计算纬度 * @param int $unit 单位,1米,2千米 * @param int $decimals 保留小数点几位 * * @return string */ public static function calculateDistance($thisLongitude, $thisLatitude, $stayLongitude, $stayLatitude, $unit = 1, $decimals = 0) { // 原始坐标纬度弧度 deg2rad()函数将角度转换为弧度 $oriLatRad = deg2rad($thisLatitude); // 新坐标纬度弧度 $newLatRad = deg2rad($stayLatitude); // 坐标纬度弧度差 $diffLatRad = deg2rad($thisLatitude) - deg2rad($stayLatitude); // 经度弧度差 $diffLngRad = deg2rad($thisLongitude) - deg2rad($stayLongitude); // sin 求正弦值 参数单位为弧度 sin(2) => 0.90929742682568 // cos 求余弦值 参数单位为弧度 cos(0.2) => 0.98006657784124 // sqrt 求平方根 sqrt(2) => 1.4142135623731 // asin 求反正弦 参数单位为弧度 asin(2) => 1.4142135623731 // pow 求幂 pow(2, 2) => 4 $distance = 2 * asin(sqrt(sin($diffLatRad / 2) ** 2 + cos($oriLatRad) * cos($newLatRad) * sin($diffLngRad / 2) ** 2)) * 6378.137 * 1000; if (2 === $unit) { $distance = $distance / 1000; } return number_format($distance, $decimals); } /** * 导出csv数据. * * @param $title 表名 * @param $cell 表头 * @param $data 数据 * @param null $closure */ public static function exportCsv($title, $cell, $data, $closure = null): void { set_time_limit(0); ini_set('memory_limit', '1024M'); $output = fopen('php://output', 'w') || exit("can't open php://output"); if (ob_get_contents()) { ob_clean(); } header('Content-Type: application/force-download'); header('Content-type: text/csv;charset=utf-8'); header('Content-Disposition: attachment; filename=' . $title . '.csv'); echo \chr(0xEF) . \chr(0xBB) . \chr(0xBF); fputcsv($output, $cell); foreach ($data as $v) { if ($closure instanceof \Closure) { $v = $closure($v); } fputcsv($output, array_values($v)); } fclose($output) || exit("can't close php://output"); exit; } /** * @desc 签名格式化成url参数 * * @param array $params 格式化参数 * * @return string */ private static function signUrlParams(array $params) { $buff = ''; foreach ($params as $k => $v) { if ('sign' !== $k && '' !== $v && !\is_array($v)) { $buff .= $k . '=' . $v . '&'; } } return trim($buff, '&'); } }