$code, 'image' => 'data:image/png;base64,' . $base64Image, 'size' => strlen($imageData), ]; } /** * 根据经纬度获取详细地址(高德地图逆地理编码) * @param float $lon 经度 * @param float $lat 纬度 * @return array 地址信息或错误信息 */ function getAddressByLatLng($lon, $lat) { // 校验经纬度格式 if (!is_numeric($lat) || !is_numeric($lon)) { return ''; } // 高德地图 API 密钥,需替换为你自己的密钥 $apiKey = 'eff1cbbaf5dd3c1cdcad2c1ed97b85e5'; // 构造请求参数 $params = [ 'key' => $apiKey, 'location' => "{$lon},{$lat}", 'extensions' => 'all', // 返回详细信息 'output' => 'json' ]; // 构建请求URL $requestUrl = "https://restapi.amap.com/v3/geocode/regeo?" . http_build_query($params); $data = http_request($requestUrl, [], []); // 检查 API 调用是否成功 if ($data['status'] === '1') { // 获取经纬度 $address = $data['regeocode']['formatted_address']; return $address; } else { return ''; } } /** * 根据地址获取经纬度 */ function get_address_lat_lng($address) { // 高德地图 API 密钥,需替换为你自己的密钥 $apiKey = 'eff1cbbaf5dd3c1cdcad2c1ed97b85e5'; // // 构建 API 请求 URL(地理编码接口:通过地址获取经纬度,目前是经常出错) // $apiUrl = 'https://restapi.amap.com/v3/geocode/geo?'; // $params = [ // 'address' => $address, // 'key' => $apiKey // ]; // 构建 API 请求 URL(关键字搜索接口) $apiUrl = 'https://restapi.amap.com/v3/place/text?'; $params = [ 'keywords' => $address, 'key' => $apiKey, 'offset' => 2, 'page' => 1, // 页码,从1开始 ]; $requestUrl = $apiUrl . http_build_query($params); $data = http_request($requestUrl, [], []); // 检查 API 调用是否成功 if ($data['status'] === '1' && $data['count'] > 0 && !empty($data['pois'])) { // 获取经纬度 // $location = $data['geocodes'][0]['location']; // list($lon, $lat) = explode(',', $location); $pois = current($data['pois']); $location = explode(",",$pois['location']); return [ 'lon' => $location[0], 'lat' => $location[1], ]; } else { return []; } } /** * 计算两点之间的距离 */ function haversineDistance($lat1, $lon1, $lat2, $lon2) { // 地球平均半径,单位:千米 $R = 6371; // 将角度转换为弧度 $lat1 = deg2rad($lat1); $lon1 = deg2rad($lon1); $lat2 = deg2rad($lat2); $lon2 = deg2rad($lon2); // 计算纬度和经度的差值 $dLat = $lat2 - $lat1; $dLon = $lon2 - $lon1; // Haversine 公式的计算步骤 $a = sin($dLat / 2) * sin($dLat / 2) + cos($lat1) * cos($lat2) * sin($dLon / 2) * sin($dLon / 2); $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); // 计算距离 $distance = $R * $c; return $distance; } /** * @notes 生成密码加密密钥 * @param string $plaintext * @param string $salt * @return string * @author 段誉 * @date 2021/12/28 18:24 */ function create_password(string $plaintext, string $salt) : string { return md5($salt . md5($plaintext . $salt)); } /** * @notes 随机生成token值 * @param string $extra * @return string * @author 段誉 * @date 2021/12/28 18:24 */ function create_token(string $extra = '') : string { $salt = env('project.unique_identification', 'likeadmin'); $encryptSalt = md5( $salt . uniqid()); return md5($salt . $extra . time() . $encryptSalt); } /** * @notes 截取某字符字符串 * @param $str * @param string $symbol * @return string * @author 段誉 * @date 2021/12/28 18:24 */ function substr_symbol_behind($str, $symbol = '.') : string { $result = strripos($str, $symbol); if ($result === false) { return $str; } return substr($str, $result + 1); } /** * @notes 对比php版本 * @param string $version * @return bool * @author 段誉 * @date 2021/12/28 18:27 */ function compare_php(string $version) : bool { return version_compare(PHP_VERSION, $version) >= 0 ? true : false; } /** * @notes 检查文件是否可写 * @param string $dir * @return bool * @author 段誉 * @date 2021/12/28 18:27 */ function check_dir_write(string $dir = '') : bool { $route = root_path() . '/' . $dir; return is_writable($route); } /** * 多级线性结构排序 * 转换前: * [{"id":1,"pid":0,"name":"a"},{"id":2,"pid":0,"name":"b"},{"id":3,"pid":1,"name":"c"}, * {"id":4,"pid":2,"name":"d"},{"id":5,"pid":4,"name":"e"},{"id":6,"pid":5,"name":"f"}, * {"id":7,"pid":3,"name":"g"}] * 转换后: * [{"id":1,"pid":0,"name":"a","level":1},{"id":3,"pid":1,"name":"c","level":2},{"id":7,"pid":3,"name":"g","level":3}, * {"id":2,"pid":0,"name":"b","level":1},{"id":4,"pid":2,"name":"d","level":2},{"id":5,"pid":4,"name":"e","level":3}, * {"id":6,"pid":5,"name":"f","level":4}] * @param array $data 线性结构数组 * @param string $symbol 名称前面加符号 * @param string $name 名称 * @param string $id_name 数组id名 * @param string $parent_id_name 数组祖先id名 * @param int $level 此值请勿给参数 * @param int $parent_id 此值请勿给参数 * @return array */ function linear_to_tree($data, $sub_key_name = 'sub', $id_name = 'id', $parent_id_name = 'pid', $parent_id = 0) { $tree = []; foreach ($data as $row) { if ($row[$parent_id_name] == $parent_id) { $temp = $row; $child = linear_to_tree($data, $sub_key_name, $id_name, $parent_id_name, $row[$id_name]); if ($child) { $temp[$sub_key_name] = $child; } $tree[] = $temp; } } return $tree; } /** * 根据父级ID获取所有子集的值 * @param $data * @param $pid * @param $idField * @param $pidField * @return array */ function get_tree_ids($data,$pid = 0, $idField = 'id',$pidField = 'pid') { $child = []; foreach($data as $val){ if ($val[$pidField] == $pid) { $children = get_tree_ids($data, $val[$idField],$idField,$pidField,); if ( count($children) > 0) { $child = array_merge($child,$children); } $child[] = $val['id']; } } return $child; } function get_top_parent_info($data, $id, $idField = 'id', $pidField = 'pid' , $parentLevel = 0) { foreach ($data as $item) { if ($item[$idField] == $id) { if ($item[$pidField] == $parentLevel) { return $item; } else { return get_top_parent_info($data, $item[$pidField], $idField, $pidField); } } } return null; } /** * 根据子集的值获取所有最高父级信息 * @param $data * @param $pid * @param $idField * @param $pidField * @return array */ function get_parent_info($data,$ids = []) { $res = []; foreach ($ids as $item) { $topParentInfo = get_top_parent_info($data, $item); if ($topParentInfo !== null) { $res[$topParentInfo['id']] = $topParentInfo; } } return $res; } /** * @notes 删除目标目录 * @param $path * @param $delDir * @return bool|void * @author 段誉 * @date 2022/4/8 16:30 */ function del_target_dir($path, $delDir) { //没找到,不处理 if (!file_exists($path)) { return false; } //打开目录句柄 $handle = opendir($path); if ($handle) { while (false !== ($item = readdir($handle))) { if ($item != "." && $item != "..") { if (is_dir("$path/$item")) { del_target_dir("$path/$item", $delDir); } else { unlink("$path/$item"); } } } closedir($handle); if ($delDir) { return rmdir($path); } } else { if (file_exists($path)) { return unlink($path); } return false; } } /** * @notes 下载文件 * @param $url * @param $saveDir * @param $fileName * @return string * @author 段誉 * @date 2022/9/16 9:53 */ function download_file($url, $saveDir, $fileName) { if (!file_exists($saveDir)) { mkdir($saveDir, 0775, true); } $fileSrc = $saveDir . $fileName; file_exists($fileSrc) && unlink($fileSrc); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); $file = curl_exec($ch); curl_close($ch); $resource = fopen($fileSrc, 'a'); fwrite($resource, $file); fclose($resource); if (filesize($fileSrc) == 0) { unlink($fileSrc); return ''; } return $fileSrc; } /** * @notes 去除内容图片域名 * @param $content * @return array|string|string[] * @author 段誉 * @date 2022/9/26 10:43 */ function clear_file_domain($content) { $fileUrl = FileService::getFileUrl(); $pattern = '/]*\bsrc=["\']'.preg_quote($fileUrl, '/').'([^"\']+)["\']/i'; return preg_replace($pattern, 'make($table)->where($field, $sn)->find()) { return generate_sn($table, $field, $prefix, $randSuffixLength, $pool); } return $sn; } /** * @notes 格式化金额 * @param $float * @return int|mixed|string * @author 段誉 * @date 2023/2/24 11:20 */ function format_amount($float) { if ($float == intval($float)) { return intval($float); } elseif ($float == sprintf('%.1f', $float)) { return sprintf('%.1f', $float); } return $float; } /** * curl提交 * @param $str * @return string */ function http_request($url , $data = NULL ,$header = NULL) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); if (!empty($data)){ curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } if(!empty($header)){ curl_setopt($ch, CURLOPT_HTTPHEADER, $header); } curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); // 检查是否有错误发生 if(curl_errno($ch)) { echo 'CURL ERROR CODE: '. curl_errno($ch) . ' , reason : ' . curl_error($ch); } curl_close($ch); $jsoninfo = json_decode($output , true); return $jsoninfo; } /** * sql语句打印 * 需要打印sql时将record_sql()方法放到sql语句之前,或 config.database.trigger_sql设置为true */ function record_sql() { if(!config("database.connections.mysql.trigger_sql")){ $config = config('database'); $config['connections']['mysql']['trigger_sql'] = true; app()->config->set($config,'database'); } \think\facade\Db::listen(function ($sql,$time,$connection) { if(strpos($sql,'CONNECT') !== false){ return; } if(strpos($sql,'SHOW FULL') !== false){ return; } \think\facade\Log::debug( '打印sql: '.$sql. ' time:'.$time); }); } // 前三后四星号字符 function asteriskString($str) { if (strlen($str) > 7) { return substr($str, 0, 3) . '****' . substr($str, -4, 4); } else { return $str; } } // 详细地址裁剪省略 function addressOmit($address) { if (iconv_strlen($address)>15) { return (mb_substr($address,0,15,'UTF-8').'...'); } else { return $address; } } function getPostageRegion($ids = []) { $id_str = ''; if(!empty($ids)){ $id_str = implode(',',$ids); } $lists = cache('postageRegion'.$id_str); if(empty($lists)){ $lists = PostageRegion::field(['*']); if(!empty($id_str)){ $lists = $lists->whereIn('id',$ids); } $lists = $lists->select()->toArray(); cache('postageRegion'.$id_str,$lists); } return $lists; } // 通过市查询省id function getProvinceByCityId($city_id) { $postageRegion = array_column(getPostageRegion([$city_id]), null, 'id'); return $postageRegion[$city_id]['pid']; } // 获取随机字符串 function generateRandomString($length = 8,$basic_method = 4) { $characters = ''; $num = '0123456789'; $lowercase_letters = 'abcdefghijklmnopqrstuvwxyz'; $capital_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; switch ($basic_method){ case 1: $characters = $num; break; case 2: $characters = $lowercase_letters; break; case 3: $characters = $num.$lowercase_letters; break; case 4: $characters = $num.$lowercase_letters.$capital_letters; break; } $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; } /** * 判断点是否在多边形内 * @param $point * @param $polygon * @return bool */ function isPointInPolygon($point, $polygon) { $x = $point['lng']; $y = $point['lat']; $inside = false; $j = count($polygon) - 1; for ($i = 0; $i < count($polygon); $i++) { $xi = $polygon[$i][0]; $yi = $polygon[$i][1]; $xj = $polygon[$j][0]; $yj = $polygon[$j][1]; $intersect = (($yi > $y) != ($yj > $y)) && ($x < ($xj - $xi) * ($y - $yi) / ($yj - $yi) + $xi); if ($intersect) { $inside = !$inside; } $j = $i; } return $inside; } /** * 获取自己和上级id * @param $point * @param $polygon * @return bool */ function getSuperiorId($all_category,$id,&$all_category_ids) { $all_category_ids[] = $id; $tmp_pid = $all_category[$id]; if($tmp_pid > 0) { getSuperiorId($all_category,$tmp_pid,$all_category_ids); } return $all_category_ids; } /** * 获取子分类上级返回树 * @param $category_ids array 分类id数组 * @return array 分类树结构 */ function getSuperiorCategoryTree($category_ids) { $all_category = GoodsCategory::where('status', 1)->column('pid', 'id'); $all_category_ids = []; foreach ($category_ids as $v) { getSuperiorId($all_category,$v,$all_category_ids); } $tree_data = GoodsCategory::field('id,pid,name') ->where('status', 1) ->whereIn('id', array_unique($all_category_ids)) ->select() ->toArray(); return linear_to_tree($tree_data, 'children'); } // 获取选项数据 function getOptionDataByTable($table) { if (method_exists(TableDataLogic::class, $table)) { $lists = TableDataLogic::$table(); } return $lists??[]; } //加密函数 function encrypt($data, $key) { // 生成一个初始化向量(iv) $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); // 使用AES-256-CBC加密模式进行加密 $encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv); // 返回加密后的数据与IV的组合,方便解密时使用 return rtrim(strtr(base64_encode($encrypted . '::' . $iv), '+/', '-_'), '='); } //解密函数 function decrypt($data, $key) { try { // 将 URL 安全的 Base64 编码的数据解码 $decoded = base64_decode(strtr($data, '-_', '+/')); list($encrypted_data, $iv) = explode('::', $decoded, 2); // 检查 IV 长度是否正确 $expectedIvLength = openssl_cipher_iv_length('aes-256-cbc'); if (strlen($iv) !== $expectedIvLength) { throw new Exception("IV length is incorrect. Expected {$expectedIvLength} bytes, got " . strlen($iv)); } // 使用相同的密钥和 IV 来解密数据 $decrypted = openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv); if ($decrypted === false) { throw new Exception("Decryption failed."); } return $decrypted; } catch (Exception $e) { // 捕获并处理异常 throw new Exception('参数不合规: ' . $e->getMessage()); } } /** * 日志格式化 * @param $data * @return false|string|void * @author liugc <466014217@qq.com> */ function formatLogData($data){ if(is_array($data)) return json_encode($data); if(is_object($data)) return json_encode((array)$data); if(is_bool($data)) return $data?'true':'false'; if(is_string($data)) return $data; } function commonHttpClient(string $url, array $params, string $requestType='post', string $dataContentType = '',array $headers = [], int $timeout = 5) { try { $client = new Client(['verify' => false,'timeout' => $timeout]); Log::info(request()->secureKey().':http_rqs:'.formatLogData(['url' => $url,'params' => $params,'requestType' => $requestType,'dataContentType' => $dataContentType,'headers' => $headers,'timeout' => $timeout])); if($requestType === 'get'){ $response = $client->request('GET', $url.'?'.http_build_query($params)); }elseif ($requestType === 'post'){ $response = $client->request('POST', $url, [ $dataContentType => $params, 'headers' => $headers ]); }else{ return []; } if($response->getStatusCode() === 200){ $body = $response->getBody()->getContents(); $result = json_decode($body,true); }else{ Log::info(request()->secureKey().':http_response:'.formatLogData($response)); $result = []; } //Log::info(request()->secureKey().':http_result:'.formatLogData($result)); return $result; } catch (GuzzleException $e) { Log::info(request()->secureKey().':http_error:'.formatLogData($e->getMessage())); return []; } }