UtilsHelper.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. <?php
  2. namespace App\DataApiNew\Helper;
  3. use App\DataApi\Helper\TencentCosHelper;
  4. use Illuminate\Support\Facades\Redis;
  5. use Illuminate\Support\Facades\Log;
  6. use Illuminate\Support\Facades\Http;
  7. use Illuminate\Support\Facades\Crypt;
  8. use Ramsey\Uuid\Uuid;
  9. use Carbon\Carbon;
  10. use Exception;
  11. /**
  12. * 方法工具类
  13. */
  14. class UtilsHelper
  15. {
  16. //生成订单号 date('ymdHis').rand(1000,9999).rand(1000,9999)
  17. public static function order_id()
  18. {
  19. return date('YmdHis') . mt_rand(100000, 999999);
  20. }
  21. // 生成user_id
  22. public static function user_id()
  23. {
  24. return date('YmdHis') . mt_rand(100000, 999999);
  25. }
  26. /**
  27. * 发送 HTTP 请求
  28. *
  29. * @param string $url 请求的 URL
  30. * @param bool $is_post 是否使用 POST 方法(默认为 true,即使用 POST 方法)
  31. * @param array $data 请求数据(默认为空数组)
  32. * @param array $headers 请求头
  33. * @param int $timeout 超时时间,单位:秒(默认为 300 秒)
  34. * @return string 响应内容
  35. * @throws Exception 当发生 Curl 错误时抛出异常
  36. */
  37. public static function sendRequest($url, $data = [], $is_post = true, $headers = [], $timeout = 300, $is_decode = true)
  38. {
  39. $ch = curl_init();
  40. // 处理 GET 和 POST 方法
  41. if ($is_post) {
  42. curl_setopt($ch, CURLOPT_POST, true);
  43. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  44. } elseif (!empty($data)) {
  45. $query = http_build_query($data);
  46. $url .= '?' . $query;
  47. }
  48. curl_setopt($ch, CURLOPT_URL, $url);
  49. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  50. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  51. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  52. // 禁用 SSL 证书验证(谨慎使用)
  53. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  54. // 执行请求
  55. $response = curl_exec($ch);
  56. if ($response === false) {
  57. $error = curl_error($ch);
  58. curl_close($ch);
  59. throw new Exception("Curl 错误: $error");
  60. }
  61. curl_close($ch);
  62. if ($is_decode) {
  63. return json_decode($response, true);
  64. } else {
  65. return $response;
  66. }
  67. }
  68. //检测文件夹是否存在,不存在则创建
  69. public static function ensureDirectoryExists($directoryPath)
  70. {
  71. if (!is_dir($directoryPath)) {
  72. // 如果文件夹不存在,尝试创建它
  73. if (!mkdir($directoryPath, 0777, true)) {
  74. // 创建失败,可以根据需要进行错误处理
  75. return false;
  76. }
  77. }
  78. return true;
  79. }
  80. // 计算数组差异
  81. public static function diffArrays($oldArray, $newArray)
  82. {
  83. // 计算需要增加的元素
  84. $elementsToAdd = array_diff($newArray, $oldArray);
  85. // 计算需要删除的元素
  86. $elementsToDelete = array_diff($oldArray, $newArray);
  87. return array(
  88. 'add' => $elementsToAdd,
  89. 'delete' => $elementsToDelete
  90. );
  91. }
  92. /**
  93. * 取多维数组中的一列作为键,另外一列作为值(如省略,则将整行作为值),转换为键值数组
  94. * @param array $result 多维数组
  95. * @param string $kk 要作为键名的列名
  96. * @param string $vk 要作为键值的列名
  97. * @return array 键值数组
  98. */
  99. public static function array_point($result, $kk = 'id', $vk = NULL)
  100. {
  101. $array = array();
  102. foreach ($result as $row) {
  103. if ($vk) {
  104. $array[$row[$kk]] = $row[$vk];
  105. } else {
  106. $array[$row[$kk]] = $row;
  107. }
  108. }
  109. return $array;
  110. }
  111. // 检查是否大于四位汉字
  112. public static function checkChineseChars($str)
  113. {
  114. // 使用 mb_strlen 函数获取字符串长度(考虑到多字节字符)
  115. $length = mb_strlen($str, 'utf-8');
  116. // 使用正则表达式匹配汉字,并计算匹配到的数量
  117. preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $str, $matches);
  118. $chineseCharsCount = count($matches[0]);
  119. // 返回汉字数量是否大于四
  120. return $chineseCharsCount < 4;
  121. }
  122. //检测表情
  123. public static function haveEmojiChar($str)
  124. {
  125. $mbLen = mb_strlen($str);
  126. $strArr = [];
  127. for ($i = 0; $i < $mbLen; $i++) {
  128. $strArr[] = mb_substr($str, $i, 1, 'utf-8');
  129. if (strlen($strArr[$i]) >= 4) {
  130. return true;
  131. }
  132. }
  133. return false;
  134. }
  135. //移除表情
  136. public static function removeEmojiChar($str)
  137. {
  138. $mbLen = mb_strlen($str);
  139. $strArr = [];
  140. for ($i = 0; $i < $mbLen; $i++) {
  141. $mbSubstr = mb_substr($str, $i, 1, 'utf-8');
  142. if (strlen($mbSubstr) >= 4) {
  143. continue;
  144. }
  145. $strArr[] = $mbSubstr;
  146. }
  147. return implode('', $strArr);
  148. }
  149. //匹配除标准ASCII字符之外的字符
  150. public static function containsSpecialCharacters($str)
  151. {
  152. return preg_match('/[^\x20-\x7E]/', $str);
  153. }
  154. // 图片压缩
  155. function compressImage($file, $destPath = '', $maxWidth = 800, $maxHeight = 600, $maxFileSize = 2 * 1024 * 1024)
  156. {
  157. // 获取图片文件信息
  158. $fileSize = $file->getSize();
  159. $fileType = $file->getMimeType();
  160. $tmpFilePath = $file->getPathname();
  161. // 如果文件大小小于最大文件大小,直接保存
  162. if ($fileSize <= $maxFileSize) {
  163. return 0;
  164. }
  165. // 创建图像对象
  166. $sourceImage = null;
  167. // 根据图像类型创建图像对象
  168. if ($fileType == 'image/jpeg' || $fileType == 'image/pjpeg') {
  169. $sourceImage = imagecreatefromjpeg($tmpFilePath);
  170. } elseif ($fileType == 'image/png') {
  171. $sourceImage = imagecreatefrompng($tmpFilePath);
  172. } elseif ($fileType == 'image/gif') {
  173. $sourceImage = imagecreatefromgif($tmpFilePath);
  174. }
  175. if ($sourceImage === null) {
  176. return 2;
  177. }
  178. // 获取源图片的宽度和高度
  179. $sourceWidth = imagesx($sourceImage);
  180. $sourceHeight = imagesy($sourceImage);
  181. // 计算等比例压缩后的宽度和高度
  182. $aspectRatio = $sourceWidth / $sourceHeight;
  183. if ($maxWidth / $maxHeight > $aspectRatio) {
  184. $destHeight = $maxHeight;
  185. $destWidth = $maxHeight * $aspectRatio;
  186. } else {
  187. $destWidth = $maxWidth;
  188. $destHeight = $maxWidth / $aspectRatio;
  189. }
  190. // 创建目标图片对象
  191. $destImage = imagecreatetruecolor($destWidth, $destHeight);
  192. // 保持 PNG 和 GIF 的透明度
  193. if ($fileType == 'image/png' || $fileType == 'image/gif') {
  194. imagecolortransparent($destImage, imagecolorallocatealpha($destImage, 0, 0, 0, 127));
  195. imagealphablending($destImage, false);
  196. imagesavealpha($destImage, true);
  197. }
  198. // 进行图片压缩和重采样
  199. imagecopyresampled($destImage, $sourceImage, 0, 0, 0, 0, $destWidth, $destHeight, $sourceWidth, $sourceHeight);
  200. // 尝试不同的压缩质量,直到图片大小小于 2MB
  201. $quality = 90;
  202. do {
  203. ob_start(); // 开启输出缓冲区
  204. imagejpeg($destImage, null, $quality);
  205. $compressedImageData = ob_get_contents();
  206. ob_end_clean(); // 清空输出缓冲区
  207. $compressedFileSize = strlen($compressedImageData);
  208. $quality -= 10;
  209. } while ($compressedFileSize > $maxFileSize && $quality > 10);
  210. // 保存最终压缩的图片
  211. file_put_contents(public_path() . '/' . $destPath, $compressedImageData);
  212. // 释放内存
  213. imagedestroy($sourceImage);
  214. imagedestroy($destImage);
  215. // return [
  216. // 'message' => '图片压缩成功',
  217. // 'size' => round($compressedFileSize / 1024, 2) . ' KB',
  218. // 'path' => $destPath
  219. // ];
  220. return 1;
  221. }
  222. // 数据加密
  223. public static function encryptData($data)
  224. {
  225. return Crypt::encrypt($data);
  226. }
  227. // 数据解密
  228. public static function decryptData($data)
  229. {
  230. return Crypt::decrypt($data);
  231. }
  232. // 自然流 合伙人id
  233. public static function natureId()
  234. {
  235. return 1;
  236. // return 832;
  237. }
  238. // 生成32位随机字符串
  239. public static function uuid4()
  240. {
  241. return str_replace('-', '', Uuid::uuid4()->toString()); //唯一随机值
  242. }
  243. // 生成随机码
  244. public static function generateRandomString($length = 6)
  245. {
  246. $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  247. $charactersLength = strlen($characters);
  248. $randomString = '';
  249. for ($i = 0; $i < $length; $i++) {
  250. $randomString .= $characters[rand(0, $charactersLength - 1)];
  251. }
  252. return $randomString;
  253. }
  254. // 生成RSA密钥对
  255. public static function generateRSAKeys()
  256. {
  257. // 设置密钥配置
  258. $config = [
  259. "private_key_bits" => 2048, // RSA-2048 密钥长度
  260. "private_key_type" => OPENSSL_KEYTYPE_RSA,
  261. ];
  262. // 生成密钥对
  263. $res = openssl_pkey_new($config);
  264. // 从密钥对中提取私钥
  265. openssl_pkey_export($res, $privateKey);
  266. // 从密钥对中提取公钥
  267. $details = openssl_pkey_get_details($res);
  268. $publicKey = $details["key"];
  269. // 去除私钥中的标识符
  270. $privateKey = preg_replace('/-----BEGIN (.*)-----(.*)-----END (.*)-----/s', '$2', $privateKey);
  271. $privateKey = str_replace(["\r", "\n"], '', $privateKey);
  272. // 去除公钥中的标识符
  273. $publicKey = preg_replace('/-----BEGIN (.*)-----(.*)-----END (.*)-----/s', '$2', $publicKey);
  274. $publicKey = str_replace(["\r", "\n"], '', $publicKey);
  275. // 返回公钥和私钥
  276. return [
  277. "privateKey" => $privateKey,
  278. "publicKey" => $publicKey,
  279. ];
  280. }
  281. // RSA解密
  282. public static function rsaDecrypt($encryptedData = null)
  283. {
  284. if (empty($encryptedData)) {
  285. return false;
  286. }
  287. $private = env('RSA_PRIVATE_KEY');
  288. // 解密数据
  289. openssl_private_decrypt(base64_decode($encryptedData), $decryptedData, $private);
  290. return json_decode($decryptedData, true);
  291. }
  292. // 数据aes rsa解密
  293. public static function aesRsaDecrypt($encryptedData, $encryptedKey, $iv)
  294. {
  295. if (empty($encryptedData) || empty($encryptedKey) || empty($iv)) {
  296. return false;
  297. }
  298. // 1. 获取私钥
  299. $privateKey = env('RSA_PRIVATE_KEY');
  300. $res = openssl_private_decrypt(base64_decode($encryptedKey), $symmetricKey, $privateKey);
  301. // 2. 用 RSA 私钥解密对称密钥
  302. if ($res) {
  303. // 3. 使用对称密钥解密数据
  304. $decryptedData = openssl_decrypt($encryptedData, 'AES-128-CBC', base64_decode($symmetricKey), 0, $iv);
  305. $arrData = json_decode($decryptedData, true); // 返回解密后的数据
  306. if (!$arrData) {
  307. Log::error("解密失败密文:" . $decryptedData);
  308. }
  309. return $arrData;
  310. } else {
  311. return false;
  312. }
  313. }
  314. //腾讯云获取用户ip信息
  315. public static function getIpInfo($ip = null)
  316. {
  317. $url = "https://apis.map.qq.com/ws/location/v1/ip";
  318. $data = [
  319. 'key' => "",
  320. 'ip' => $ip
  321. ];
  322. $res = self::sendRequest($url, $data, false);
  323. Log::info('腾讯地图ip信息:' . json_encode($res, JSON_UNESCAPED_UNICODE));
  324. if ($res['status'] == 0) {
  325. return $res['result'];
  326. } else {
  327. return false;
  328. }
  329. }
  330. // 判断base64是否合法
  331. public static function isValidBase64($base64, $maxSizeInMB = 3)
  332. {
  333. // 检查Base64编码字符串的长度是否为4的倍数
  334. if (strlen($base64) % 4 !== 0) {
  335. Log::info("Base64异常:检查Base64编码字符串的长度是否为4的倍数");
  336. return false;
  337. }
  338. // 尝试解码Base64字符串
  339. $decodedData = base64_decode($base64, true);
  340. // 检查解码是否成功并且验证是否是有效的Base64字符串
  341. if ($decodedData === false || base64_encode($decodedData) !== $base64) {
  342. Log::info("Base64异常:检查解码是否成功并且验证是否是有效的Base64字符串");
  343. return false;
  344. }
  345. // 计算解码后的数据大小
  346. $imageSizeInBytes = strlen($decodedData);
  347. // 将大小转换为MB
  348. $imageSizeInMB = $imageSizeInBytes / (1024 * 1024);
  349. // 检查图片大小是否超过指定的最大值
  350. if ($imageSizeInMB > $maxSizeInMB) {
  351. Log::info("Base64异常:图片尺寸 ".$imageSizeInMB);
  352. return false;
  353. }
  354. // 如果需要获取图片信息,例如尺寸,可以在这里获取
  355. $imageInfo = getimagesizefromstring($decodedData);
  356. if ($imageInfo === false) {
  357. Log::info("Base64异常:获取图片信息失败");
  358. return false;
  359. }
  360. // 返回解码后的图片数据
  361. return $decodedData;
  362. }
  363. // 获取每月一号的日期
  364. public static function generateMonthlyDates($months)
  365. {
  366. $dates = [];
  367. // 获取当前时间
  368. $currentDate = Carbon::now();
  369. // 从下个月的1号开始
  370. $currentDate->addMonth()->startOfMonth()->setTime(0, 0);
  371. // 生成每个月1号的日期
  372. for ($i = 0; $i < $months; $i++) {
  373. $dates[] = $currentDate->format('Y-m-d H:i:s');
  374. // 移动到下个月的1号
  375. $currentDate->addMonth()->startOfMonth();
  376. }
  377. return $dates;
  378. }
  379. // 下载图片
  380. public static function downloadImage($url, $savePath)
  381. {
  382. try {
  383. // 使用 Guzzle 通过 HTTP 请求下载图片
  384. $response = Http::timeout(10)->get($url); // 设置超时为10秒
  385. // 检查请求是否成功
  386. if ($response->successful()) {
  387. // 保存图片到本地
  388. file_put_contents($savePath, $response->body());
  389. return true;
  390. } else {
  391. return false;
  392. }
  393. } catch (\Exception $e) {
  394. // 捕获错误
  395. Log::info("下载图片失败:" . $e);
  396. return false;
  397. }
  398. }
  399. // 打印请求信息
  400. public static function printRequestInfo($request, $msg = "")
  401. {
  402. Log::info("{$msg}【" . $request->ip() . "】:" . json_encode($request->all()));
  403. }
  404. /*
  405. 函数:remoteFileExists
  406. 功能:判断远程文件是否存在
  407. 参数: $url_file -远程文件URL
  408. 返回:存在返回true,不存在或者其他原因返回false
  409. */
  410. public static function remoteFileExists($url)
  411. {
  412. $curl = curl_init($url);
  413. curl_setopt($curl, CURLOPT_NOBODY, true); // 不取回数据
  414. curl_setopt($curl, CURLOPT_TIMEOUT, 10); // 设置超时为10秒
  415. curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); // 连接超时5秒
  416. // 发送请求并检查响应码
  417. $result = curl_exec($curl);
  418. if ($result !== false) {
  419. $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  420. curl_close($curl);
  421. return $statusCode == 200;
  422. }
  423. curl_close($curl);
  424. return false;
  425. }
  426. // 邀请码------------------------------------------
  427. // 检查是否为镜像号
  428. private function isPalindrome($number) {
  429. return $number == strrev($number);
  430. }
  431. // 检查数字是否包含重复次数的字符
  432. private function isRepeating($number, $repeatCount) {
  433. $number_str = (string) $number;
  434. for ($i = 0; $i <= 10 - $repeatCount; $i++) {
  435. if (substr_count($number_str, str_repeat(strval($i), $repeatCount)) > 0) {
  436. return true;
  437. }
  438. }
  439. return false;
  440. }
  441. // 检查是否为顺序号
  442. private function isSequential($number) {
  443. $sequences = ['012345', '123456', '234567', '345678', '456789', '567890', '678901', '789012', '890123', '901234'];
  444. return in_array($number, $sequences) || in_array(strrev($number), $sequences);
  445. }
  446. // 检查是否为循环号
  447. private function isCircular($number) {
  448. $segments = str_split($number, 2);
  449. return count($segments) == 2 && $segments[0] == $segments[1];
  450. }
  451. // 检查是否为斜角号
  452. private function isGradient($number) {
  453. $diff = (int) $number[1] - (int) $number[0];
  454. for ($i = 1; $i < strlen($number) - 1; $i++) {
  455. if ((int)$number[$i + 1] - (int)$number[$i] != $diff) {
  456. return false;
  457. }
  458. }
  459. return true;
  460. }
  461. // 检查是否为好数字
  462. private function isGoodNumber($number) {
  463. return $this->isPalindrome($number) ||
  464. $this->isRepeating($number, 5) ||
  465. $this->isRepeating($number, 4) ||
  466. $this->isRepeating($number, 3) ||
  467. $this->isSequential($number) ||
  468. $this->isCircular($number) ||
  469. $this->isGradient($number);
  470. }
  471. // 获取下一个有效编号
  472. private function getNextCode($current) {
  473. do {
  474. $currentNumber = (int)substr($current, 1);
  475. $currentLetter = $current[0];
  476. $currentNumber++;
  477. if ($currentNumber > 99999) {
  478. $currentNumber = 0;
  479. $currentLetter++;
  480. }
  481. $numbers = sprintf('%05d', $currentNumber);
  482. $current = $currentLetter . $numbers;
  483. } while ($this->isGoodNumber($numbers));
  484. return $current;
  485. }
  486. // 生成并返回下一个有效编号
  487. public function generateNextCode() {
  488. $current = Redis::get('current_code') ? Redis::get('current_code') : 'B00000';
  489. $newCode = $this->getNextCode($current);
  490. Redis::set('current_code', $newCode);
  491. return $newCode;
  492. }
  493. // 图片圆角
  494. public static function z_image2circle($src, $dst)
  495. {
  496. //获取原图尺寸,并设置新图片的宽度和高度
  497. list($w, $h) = getimagesize($src);
  498. if ($w > $h) {
  499. $w = $h;
  500. } else {
  501. $h = $w;
  502. }
  503. $oimgSrc = imagecreatefromstring(file_get_contents($src));
  504. $oimgDst = imagecreatetruecolor($w, $h);
  505. imagealphablending($oimgDst, false);
  506. $transparent = imagecolorallocatealpha($oimgDst, 0, 0, 0, 127);
  507. $r = $w / 2;
  508. for ($x = 0; $x < $w; $x++) {
  509. for ($y = 0; $y < $h; $y++) {
  510. $c = imagecolorat($oimgSrc, $x, $y);
  511. $_x = $x - $w / 2;
  512. $_y = $y - $h / 2;
  513. if ((($_x * $_x) + ($_y * $_y)) < ($r * $r)) {
  514. imagesetpixel($oimgDst, $x, $y, $c);
  515. } else {
  516. imagesetpixel($oimgDst, $x, $y, $transparent);
  517. }
  518. }
  519. }
  520. imagesavealpha($oimgDst, true);
  521. imagepng($oimgDst, $dst);
  522. imagedestroy($oimgDst);
  523. imagedestroy($oimgSrc);
  524. }
  525. // 字符串省略
  526. public static function truncateString($string, $length = 30, $ellipsis = '...')
  527. {
  528. if (mb_strlen($string, 'UTF-8') > $length) {
  529. return mb_substr($string, 0, $length, 'UTF-8') . $ellipsis;
  530. } else {
  531. return $string;
  532. }
  533. }
  534. }