123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- <?php
- namespace App\DataApiNew\Helper;
- use App\DataApi\Helper\TencentCosHelper;
- use Illuminate\Support\Facades\Redis;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Http;
- use Illuminate\Support\Facades\Crypt;
- use Ramsey\Uuid\Uuid;
- use Carbon\Carbon;
- use Exception;
- /**
- * 方法工具类
- */
- class UtilsHelper
- {
- //生成订单号 date('ymdHis').rand(1000,9999).rand(1000,9999)
- public static function order_id()
- {
- return date('YmdHis') . mt_rand(100000, 999999);
- }
- // 生成user_id
- public static function user_id()
- {
- return date('YmdHis') . mt_rand(100000, 999999);
- }
- /**
- * 发送 HTTP 请求
- *
- * @param string $url 请求的 URL
- * @param bool $is_post 是否使用 POST 方法(默认为 true,即使用 POST 方法)
- * @param array $data 请求数据(默认为空数组)
- * @param array $headers 请求头
- * @param int $timeout 超时时间,单位:秒(默认为 300 秒)
- * @return string 响应内容
- * @throws Exception 当发生 Curl 错误时抛出异常
- */
- public static function sendRequest($url, $data = [], $is_post = true, $headers = [], $timeout = 300, $is_decode = true)
- {
- $ch = curl_init();
- // 处理 GET 和 POST 方法
- if ($is_post) {
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
- } elseif (!empty($data)) {
- $query = http_build_query($data);
- $url .= '?' . $query;
- }
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
- curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
- // 禁用 SSL 证书验证(谨慎使用)
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- // 执行请求
- $response = curl_exec($ch);
- if ($response === false) {
- $error = curl_error($ch);
- curl_close($ch);
- throw new Exception("Curl 错误: $error");
- }
- curl_close($ch);
- if ($is_decode) {
- return json_decode($response, true);
- } else {
- return $response;
- }
- }
- //检测文件夹是否存在,不存在则创建
- public static function ensureDirectoryExists($directoryPath)
- {
- if (!is_dir($directoryPath)) {
- // 如果文件夹不存在,尝试创建它
- if (!mkdir($directoryPath, 0777, true)) {
- // 创建失败,可以根据需要进行错误处理
- return false;
- }
- }
- return true;
- }
- // 计算数组差异
- public static function diffArrays($oldArray, $newArray)
- {
- // 计算需要增加的元素
- $elementsToAdd = array_diff($newArray, $oldArray);
- // 计算需要删除的元素
- $elementsToDelete = array_diff($oldArray, $newArray);
- return array(
- 'add' => $elementsToAdd,
- 'delete' => $elementsToDelete
- );
- }
- /**
- * 取多维数组中的一列作为键,另外一列作为值(如省略,则将整行作为值),转换为键值数组
- * @param array $result 多维数组
- * @param string $kk 要作为键名的列名
- * @param string $vk 要作为键值的列名
- * @return array 键值数组
- */
- public static function array_point($result, $kk = 'id', $vk = NULL)
- {
- $array = array();
- foreach ($result as $row) {
- if ($vk) {
- $array[$row[$kk]] = $row[$vk];
- } else {
- $array[$row[$kk]] = $row;
- }
- }
- return $array;
- }
- // 检查是否大于四位汉字
- public static function checkChineseChars($str)
- {
- // 使用 mb_strlen 函数获取字符串长度(考虑到多字节字符)
- $length = mb_strlen($str, 'utf-8');
- // 使用正则表达式匹配汉字,并计算匹配到的数量
- preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $str, $matches);
- $chineseCharsCount = count($matches[0]);
- // 返回汉字数量是否大于四
- return $chineseCharsCount < 4;
- }
- //检测表情
- public static function haveEmojiChar($str)
- {
- $mbLen = mb_strlen($str);
- $strArr = [];
- for ($i = 0; $i < $mbLen; $i++) {
- $strArr[] = mb_substr($str, $i, 1, 'utf-8');
- if (strlen($strArr[$i]) >= 4) {
- return true;
- }
- }
- return false;
- }
- //移除表情
- public static function removeEmojiChar($str)
- {
- $mbLen = mb_strlen($str);
- $strArr = [];
- for ($i = 0; $i < $mbLen; $i++) {
- $mbSubstr = mb_substr($str, $i, 1, 'utf-8');
- if (strlen($mbSubstr) >= 4) {
- continue;
- }
- $strArr[] = $mbSubstr;
- }
- return implode('', $strArr);
- }
- //匹配除标准ASCII字符之外的字符
- public static function containsSpecialCharacters($str)
- {
- return preg_match('/[^\x20-\x7E]/', $str);
- }
- // 图片压缩
- function compressImage($file, $destPath = '', $maxWidth = 800, $maxHeight = 600, $maxFileSize = 2 * 1024 * 1024)
- {
- // 获取图片文件信息
- $fileSize = $file->getSize();
- $fileType = $file->getMimeType();
- $tmpFilePath = $file->getPathname();
- // 如果文件大小小于最大文件大小,直接保存
- if ($fileSize <= $maxFileSize) {
- return 0;
- }
- // 创建图像对象
- $sourceImage = null;
- // 根据图像类型创建图像对象
- if ($fileType == 'image/jpeg' || $fileType == 'image/pjpeg') {
- $sourceImage = imagecreatefromjpeg($tmpFilePath);
- } elseif ($fileType == 'image/png') {
- $sourceImage = imagecreatefrompng($tmpFilePath);
- } elseif ($fileType == 'image/gif') {
- $sourceImage = imagecreatefromgif($tmpFilePath);
- }
- if ($sourceImage === null) {
- return 2;
- }
- // 获取源图片的宽度和高度
- $sourceWidth = imagesx($sourceImage);
- $sourceHeight = imagesy($sourceImage);
- // 计算等比例压缩后的宽度和高度
- $aspectRatio = $sourceWidth / $sourceHeight;
- if ($maxWidth / $maxHeight > $aspectRatio) {
- $destHeight = $maxHeight;
- $destWidth = $maxHeight * $aspectRatio;
- } else {
- $destWidth = $maxWidth;
- $destHeight = $maxWidth / $aspectRatio;
- }
- // 创建目标图片对象
- $destImage = imagecreatetruecolor($destWidth, $destHeight);
- // 保持 PNG 和 GIF 的透明度
- if ($fileType == 'image/png' || $fileType == 'image/gif') {
- imagecolortransparent($destImage, imagecolorallocatealpha($destImage, 0, 0, 0, 127));
- imagealphablending($destImage, false);
- imagesavealpha($destImage, true);
- }
- // 进行图片压缩和重采样
- imagecopyresampled($destImage, $sourceImage, 0, 0, 0, 0, $destWidth, $destHeight, $sourceWidth, $sourceHeight);
- // 尝试不同的压缩质量,直到图片大小小于 2MB
- $quality = 90;
- do {
- ob_start(); // 开启输出缓冲区
- imagejpeg($destImage, null, $quality);
- $compressedImageData = ob_get_contents();
- ob_end_clean(); // 清空输出缓冲区
- $compressedFileSize = strlen($compressedImageData);
- $quality -= 10;
- } while ($compressedFileSize > $maxFileSize && $quality > 10);
- // 保存最终压缩的图片
- file_put_contents(public_path() . '/' . $destPath, $compressedImageData);
- // 释放内存
- imagedestroy($sourceImage);
- imagedestroy($destImage);
- // return [
- // 'message' => '图片压缩成功',
- // 'size' => round($compressedFileSize / 1024, 2) . ' KB',
- // 'path' => $destPath
- // ];
- return 1;
- }
- // 数据加密
- public static function encryptData($data)
- {
- return Crypt::encrypt($data);
- }
- // 数据解密
- public static function decryptData($data)
- {
- return Crypt::decrypt($data);
- }
- // 自然流 合伙人id
- public static function natureId()
- {
- return 1;
- // return 832;
- }
- // 生成32位随机字符串
- public static function uuid4()
- {
- return str_replace('-', '', Uuid::uuid4()->toString()); //唯一随机值
- }
- // 生成随机码
- public static function generateRandomString($length = 6)
- {
- $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
- $charactersLength = strlen($characters);
- $randomString = '';
- for ($i = 0; $i < $length; $i++) {
- $randomString .= $characters[rand(0, $charactersLength - 1)];
- }
- return $randomString;
- }
- // 生成RSA密钥对
- public static function generateRSAKeys()
- {
- // 设置密钥配置
- $config = [
- "private_key_bits" => 2048, // RSA-2048 密钥长度
- "private_key_type" => OPENSSL_KEYTYPE_RSA,
- ];
- // 生成密钥对
- $res = openssl_pkey_new($config);
- // 从密钥对中提取私钥
- openssl_pkey_export($res, $privateKey);
- // 从密钥对中提取公钥
- $details = openssl_pkey_get_details($res);
- $publicKey = $details["key"];
- // 去除私钥中的标识符
- $privateKey = preg_replace('/-----BEGIN (.*)-----(.*)-----END (.*)-----/s', '$2', $privateKey);
- $privateKey = str_replace(["\r", "\n"], '', $privateKey);
- // 去除公钥中的标识符
- $publicKey = preg_replace('/-----BEGIN (.*)-----(.*)-----END (.*)-----/s', '$2', $publicKey);
- $publicKey = str_replace(["\r", "\n"], '', $publicKey);
- // 返回公钥和私钥
- return [
- "privateKey" => $privateKey,
- "publicKey" => $publicKey,
- ];
- }
- // RSA解密
- public static function rsaDecrypt($encryptedData = null)
- {
- if (empty($encryptedData)) {
- return false;
- }
- $private = env('RSA_PRIVATE_KEY');
- // 解密数据
- openssl_private_decrypt(base64_decode($encryptedData), $decryptedData, $private);
- return json_decode($decryptedData, true);
- }
- // 数据aes rsa解密
- public static function aesRsaDecrypt($encryptedData, $encryptedKey, $iv)
- {
- if (empty($encryptedData) || empty($encryptedKey) || empty($iv)) {
- return false;
- }
- // 1. 获取私钥
- $privateKey = env('RSA_PRIVATE_KEY');
- $res = openssl_private_decrypt(base64_decode($encryptedKey), $symmetricKey, $privateKey);
- // 2. 用 RSA 私钥解密对称密钥
- if ($res) {
- // 3. 使用对称密钥解密数据
- $decryptedData = openssl_decrypt($encryptedData, 'AES-128-CBC', base64_decode($symmetricKey), 0, $iv);
- $arrData = json_decode($decryptedData, true); // 返回解密后的数据
- if (!$arrData) {
- Log::error("解密失败密文:" . $decryptedData);
- }
- return $arrData;
- } else {
- return false;
- }
- }
- //腾讯云获取用户ip信息
- public static function getIpInfo($ip = null)
- {
- $url = "https://apis.map.qq.com/ws/location/v1/ip";
- $data = [
- 'key' => "",
- 'ip' => $ip
- ];
- $res = self::sendRequest($url, $data, false);
- Log::info('腾讯地图ip信息:' . json_encode($res, JSON_UNESCAPED_UNICODE));
- if ($res['status'] == 0) {
- return $res['result'];
- } else {
- return false;
- }
- }
- // 判断base64是否合法
- public static function isValidBase64($base64, $maxSizeInMB = 3)
- {
- // 检查Base64编码字符串的长度是否为4的倍数
- if (strlen($base64) % 4 !== 0) {
- Log::info("Base64异常:检查Base64编码字符串的长度是否为4的倍数");
- return false;
- }
- // 尝试解码Base64字符串
- $decodedData = base64_decode($base64, true);
- // 检查解码是否成功并且验证是否是有效的Base64字符串
- if ($decodedData === false || base64_encode($decodedData) !== $base64) {
- Log::info("Base64异常:检查解码是否成功并且验证是否是有效的Base64字符串");
- return false;
- }
- // 计算解码后的数据大小
- $imageSizeInBytes = strlen($decodedData);
- // 将大小转换为MB
- $imageSizeInMB = $imageSizeInBytes / (1024 * 1024);
- // 检查图片大小是否超过指定的最大值
- if ($imageSizeInMB > $maxSizeInMB) {
- Log::info("Base64异常:图片尺寸 ".$imageSizeInMB);
- return false;
- }
- // 如果需要获取图片信息,例如尺寸,可以在这里获取
- $imageInfo = getimagesizefromstring($decodedData);
- if ($imageInfo === false) {
- Log::info("Base64异常:获取图片信息失败");
- return false;
- }
- // 返回解码后的图片数据
- return $decodedData;
- }
- // 获取每月一号的日期
- public static function generateMonthlyDates($months)
- {
- $dates = [];
- // 获取当前时间
- $currentDate = Carbon::now();
- // 从下个月的1号开始
- $currentDate->addMonth()->startOfMonth()->setTime(0, 0);
- // 生成每个月1号的日期
- for ($i = 0; $i < $months; $i++) {
- $dates[] = $currentDate->format('Y-m-d H:i:s');
- // 移动到下个月的1号
- $currentDate->addMonth()->startOfMonth();
- }
- return $dates;
- }
- // 下载图片
- public static function downloadImage($url, $savePath)
- {
- try {
- // 使用 Guzzle 通过 HTTP 请求下载图片
- $response = Http::timeout(10)->get($url); // 设置超时为10秒
- // 检查请求是否成功
- if ($response->successful()) {
- // 保存图片到本地
- file_put_contents($savePath, $response->body());
- return true;
- } else {
- return false;
- }
- } catch (\Exception $e) {
- // 捕获错误
- Log::info("下载图片失败:" . $e);
- return false;
- }
- }
- // 打印请求信息
- public static function printRequestInfo($request, $msg = "")
- {
- Log::info("{$msg}【" . $request->ip() . "】:" . json_encode($request->all()));
- }
- /*
- 函数:remoteFileExists
- 功能:判断远程文件是否存在
- 参数: $url_file -远程文件URL
- 返回:存在返回true,不存在或者其他原因返回false
- */
- public static function remoteFileExists($url)
- {
- $curl = curl_init($url);
- curl_setopt($curl, CURLOPT_NOBODY, true); // 不取回数据
- curl_setopt($curl, CURLOPT_TIMEOUT, 10); // 设置超时为10秒
- curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); // 连接超时5秒
- // 发送请求并检查响应码
- $result = curl_exec($curl);
- if ($result !== false) {
- $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- curl_close($curl);
- return $statusCode == 200;
- }
- curl_close($curl);
- return false;
- }
- // 邀请码------------------------------------------
- // 检查是否为镜像号
- private function isPalindrome($number) {
- return $number == strrev($number);
- }
- // 检查数字是否包含重复次数的字符
- private function isRepeating($number, $repeatCount) {
- $number_str = (string) $number;
- for ($i = 0; $i <= 10 - $repeatCount; $i++) {
- if (substr_count($number_str, str_repeat(strval($i), $repeatCount)) > 0) {
- return true;
- }
- }
- return false;
- }
- // 检查是否为顺序号
- private function isSequential($number) {
- $sequences = ['012345', '123456', '234567', '345678', '456789', '567890', '678901', '789012', '890123', '901234'];
- return in_array($number, $sequences) || in_array(strrev($number), $sequences);
- }
- // 检查是否为循环号
- private function isCircular($number) {
- $segments = str_split($number, 2);
- return count($segments) == 2 && $segments[0] == $segments[1];
- }
- // 检查是否为斜角号
- private function isGradient($number) {
- $diff = (int) $number[1] - (int) $number[0];
- for ($i = 1; $i < strlen($number) - 1; $i++) {
- if ((int)$number[$i + 1] - (int)$number[$i] != $diff) {
- return false;
- }
- }
- return true;
- }
- // 检查是否为好数字
- private function isGoodNumber($number) {
- return $this->isPalindrome($number) ||
- $this->isRepeating($number, 5) ||
- $this->isRepeating($number, 4) ||
- $this->isRepeating($number, 3) ||
- $this->isSequential($number) ||
- $this->isCircular($number) ||
- $this->isGradient($number);
- }
- // 获取下一个有效编号
- private function getNextCode($current) {
- do {
- $currentNumber = (int)substr($current, 1);
- $currentLetter = $current[0];
- $currentNumber++;
- if ($currentNumber > 99999) {
- $currentNumber = 0;
- $currentLetter++;
- }
- $numbers = sprintf('%05d', $currentNumber);
- $current = $currentLetter . $numbers;
- } while ($this->isGoodNumber($numbers));
- return $current;
- }
- // 生成并返回下一个有效编号
- public function generateNextCode() {
- $current = Redis::get('current_code') ? Redis::get('current_code') : 'B00000';
- $newCode = $this->getNextCode($current);
- Redis::set('current_code', $newCode);
- return $newCode;
- }
- // 图片圆角
- public static function z_image2circle($src, $dst)
- {
- //获取原图尺寸,并设置新图片的宽度和高度
- list($w, $h) = getimagesize($src);
- if ($w > $h) {
- $w = $h;
- } else {
- $h = $w;
- }
- $oimgSrc = imagecreatefromstring(file_get_contents($src));
- $oimgDst = imagecreatetruecolor($w, $h);
- imagealphablending($oimgDst, false);
- $transparent = imagecolorallocatealpha($oimgDst, 0, 0, 0, 127);
- $r = $w / 2;
- for ($x = 0; $x < $w; $x++) {
- for ($y = 0; $y < $h; $y++) {
- $c = imagecolorat($oimgSrc, $x, $y);
- $_x = $x - $w / 2;
- $_y = $y - $h / 2;
- if ((($_x * $_x) + ($_y * $_y)) < ($r * $r)) {
- imagesetpixel($oimgDst, $x, $y, $c);
- } else {
- imagesetpixel($oimgDst, $x, $y, $transparent);
- }
- }
- }
- imagesavealpha($oimgDst, true);
- imagepng($oimgDst, $dst);
- imagedestroy($oimgDst);
- imagedestroy($oimgSrc);
- }
- // 字符串省略
- public static function truncateString($string, $length = 30, $ellipsis = '...')
- {
- if (mb_strlen($string, 'UTF-8') > $length) {
- return mb_substr($string, 0, $length, 'UTF-8') . $ellipsis;
- } else {
- return $string;
- }
- }
- }
|