common.func.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. <?php
  2. /**
  3. * 通用函数库.
  4. *
  5. * @author nj <nj@gmail.com>
  6. * @date 2019-11-01 14:42:37
  7. */
  8. declare(strict_types=1);
  9. use App\Repositories\Service\CommonService;
  10. use App\Repositories\Utils\M3u8CacheRepository;
  11. use Hashids\Hashids;
  12. /**
  13. * 获取分页start offset
  14. * @param $amount
  15. * @param int $page
  16. * @param int $page_size
  17. * @return int|mixed
  18. */
  19. function get_page_start($amount, $page = 1, $page_size = 20)
  20. {
  21. if (empty($amount)) {
  22. return $page_size;
  23. }
  24. $page_size = empty($page_size) ? 20 : $page_size;
  25. $page_most = ceil($amount / $page_size);
  26. if (isset($page)) {
  27. $page = intval($page);
  28. if ($page > $page_most) {
  29. $page = $page_most;
  30. }
  31. } else {
  32. $page = 1;
  33. }
  34. $page = max(1, $page); // 找出最大值.
  35. $start_limit = ($page - 1) * $page_size;
  36. return intval($start_limit);
  37. }
  38. /**
  39. * 格式化页码入参
  40. * @param $page
  41. * @return int
  42. */
  43. function format_page($page)
  44. {
  45. $page = intval($page);
  46. if ($page <= 0) {
  47. $page = 1;
  48. }
  49. if ($page > PHP_INT_MAX) {
  50. $page = PHP_INT_MAX;
  51. }
  52. return $page;
  53. }
  54. /**
  55. * 密码星号加密
  56. * @param string $str 输入的字符串
  57. * @return string
  58. */
  59. function pass_encode($str)
  60. {
  61. $len = strlen($str);
  62. if ($len < 1) {
  63. return '';
  64. }
  65. $new = '';
  66. for ($i = 0; $i < $len; $i++) {
  67. $new .= ($i == 0 || $i == $len - 1) ? $str[$i] : '*';
  68. }
  69. return $new;
  70. }
  71. /**
  72. * 密码星号解密
  73. * @param string $new 明文密码
  74. * @param string $old 原始密码
  75. * @return mixed
  76. */
  77. function pass_decode($new, $old)
  78. {
  79. return $new == pass_encode($old) ? $old : $new;
  80. }
  81. /**
  82. * 加密手机号
  83. * @param $mobile
  84. * @return string
  85. */
  86. function encode_mobile($mobile)
  87. {
  88. $str = '';
  89. if ($mobile) {
  90. $len = strlen($mobile);
  91. for ($i = 0; $i < $len; $i++) {
  92. $str .= ($i < 5 || $i > $len - 4) ? $mobile[$i] : '*';
  93. }
  94. }
  95. return $str;
  96. }
  97. /**
  98. * 更新OpCache
  99. * 生成缓存php文件的地方都需要调用此函数
  100. * @return void
  101. */
  102. function opcache_update()
  103. {
  104. if (function_exists('opcache_reset')) {
  105. opcache_reset();
  106. }
  107. }
  108. /**
  109. * 获取相对依赖双斜杠开头的URL地址
  110. * @param $url
  111. * @return mixed
  112. */
  113. function get_slashes_url($url)
  114. {
  115. if (preg_match('/^(http|https)\:\/\/(.*?)$/i', $url, $arr_matches)) {
  116. return '//' . $arr_matches[2];
  117. } else {
  118. return $url;
  119. }
  120. }
  121. /**
  122. * json响应成功
  123. * @param mixed $data 数据
  124. * @param string $message 消息
  125. * @return mixed
  126. */
  127. function json_success($data, $message = '操作成功')
  128. {
  129. $handshake = '';
  130. $isValidMg = false;
  131. if (class_exists('\Modules\Manage\Services\AuthService')) {
  132. $service = make(\Modules\Manage\Services\AuthService::class);
  133. // 如果有效后台header,则直接不加密,进行明文通讯.
  134. $isValidMg = $service->checkValidMgHeaderHandShake();
  135. }
  136. if (!$isValidMg) {
  137. $handshake = \App\Constants\CommonConstant::getHandShake();
  138. if (!empty($handshake)) {
  139. $inputData = request()->all();
  140. $inputHandShake = $inputData['handshake'] ?? $handshake;
  141. $arrMap = \App\Constants\CommonConstant::getHandSnakeKey($inputHandShake);
  142. // $arrMap = \App\Constants\CommonConstant::getHandSnakeKey($handshake);
  143. $data = hand_encrypt(json_encode($data), $arrMap['key'], '');
  144. $handshake = $inputHandShake;
  145. }
  146. }
  147. $res = [
  148. 'code' => 200,
  149. 'message' => $message,
  150. 'data' => $data,
  151. 'handshake' => $handshake,
  152. ];
  153. return response()->json($res);
  154. }
  155. /**
  156. * json响应失败
  157. * @param string $message 消息
  158. * @param int $code 代码
  159. * @return mixed
  160. */
  161. function json_fail($message, $code = 500, $data = [])
  162. {
  163. $handshake = '';
  164. $isValidMg = false;
  165. if (class_exists('\Modules\Manage\Services\AuthService')) {
  166. $service = make(\Modules\Manage\Services\AuthService::class);
  167. // 如果有效后台header,则直接不加密,进行明文通讯.
  168. $isValidMg = $service->checkValidMgHeaderHandShake();
  169. }
  170. if (!$isValidMg) {
  171. $handshake = \App\Constants\CommonConstant::getHandShake();
  172. if (!empty($handshake)) {
  173. $inputData = request()->all();
  174. $inputHandShake = $inputData['handshake'] ?? $handshake;
  175. $arrMap = \App\Constants\CommonConstant::getHandSnakeKey($inputHandShake);
  176. // $arrMap = \App\Constants\CommonConstant::getHandSnakeKey($handshake);
  177. if (!empty($data)) {
  178. $data = hand_encrypt($data, $arrMap['key'], '');
  179. } else {
  180. $data = '';
  181. }
  182. $handshake = $inputHandShake;
  183. }
  184. }
  185. $res = [
  186. 'code' => $code,
  187. 'message' => $message,
  188. 'data' => $data,
  189. 'handshake' => $handshake,
  190. ];
  191. return response()->json($res);
  192. }
  193. function json_stock_fail($message, $code = 500)
  194. {
  195. $res = [
  196. 'code' => $code,
  197. 'message' => $message,
  198. ];
  199. // return json_encode($res);
  200. $result = '';
  201. $handshake = \App\Constants\CommonConstant::getHandShake();
  202. $handshake = 'prod';
  203. if (!empty($handshake)) {
  204. $key = \App\Constants\CommonConstant::getStockHandSnakeKey();
  205. $result = hand_encrypt($res, $key, '');
  206. }
  207. return $result;
  208. }
  209. function json_stock_success($data, $message = '成功')
  210. {
  211. $res = [
  212. 'code' => 200,
  213. 'result' => $data,
  214. 'message' => $message
  215. ];
  216. // return json_encode($res);
  217. $result = '';
  218. $handshake = \App\Constants\CommonConstant::getHandShake();
  219. $handshake = 'prod';
  220. if (!empty($handshake)) {
  221. $key = \App\Constants\CommonConstant::getStockHandSnakeKey();
  222. $result = hand_encrypt($res, $key, '');
  223. }
  224. return $result;
  225. }
  226. /**
  227. * 随机生成指定长度字符串
  228. * @param int $len 长度
  229. * @return string
  230. */
  231. function rand_letter($len = 18)
  232. {
  233. $str = '';
  234. if ($len <= 0) {
  235. $len = 18;
  236. }
  237. $chars = "abcdefhjmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWYXZ";
  238. $clen = strlen($chars);
  239. $max = $clen - 1;
  240. for ($i = 0; $i < $len; $i++) {
  241. $str .= $chars[mt_rand(0, $max)];
  242. }
  243. return $str;
  244. }
  245. /**
  246. * 随机生成字符串
  247. * @param int $length 长度
  248. * @param int $numeric 纯数字
  249. * @return string
  250. */
  251. function random($length, $numeric = 0)
  252. {
  253. if (version_compare(PHP_VERSION, '4.2.0', '<')) {
  254. mt_srand((double)microtime() * 1000000);
  255. } else {
  256. mt_srand();
  257. }
  258. $seed = base_convert(md5(mt_rand(1, 9) . microtime()), 16, $numeric ? 10 : 35);
  259. $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed));
  260. $hash = '';
  261. $max = strlen($seed) - 1;
  262. for ($i = 0; $i < $length; $i++) {
  263. $hash .= $seed[mt_rand(0, $max)];
  264. }
  265. return $hash;
  266. }
  267. /**
  268. * AES 加密
  269. * @param mixed $content 明文
  270. * @param string $key 密钥
  271. * @param string $iv 向量,必须为数字
  272. * @param string $cipher 算法.
  273. * @param int $option 标记的按位或: OPENSSL_RAW_DATA=1 、 OPENSSL_ZERO_PADDING=2.
  274. * @return string
  275. */
  276. function aes_encrypt($content, $key, $iv = '', $cipher = 'AES-256-CBC', $option = 1)
  277. {
  278. $ivLength = openssl_cipher_iv_length($cipher); // 向量长度.
  279. /*$iv = openssl_random_pseudo_bytes($ivLength); // 根据长度生成向量.*/
  280. //$option = OPENSSL_RAW_DATA; // 标记的按位或: OPENSSL_RAW_DATA=1 、 OPENSSL_ZERO_PADDING=2.
  281. $tag = null; // 使用 AEAD 密码模式(GCM 或 CCM)时传引用的验证标签.
  282. $aad = ''; // 附加的验证数据.
  283. $tagLength = 16; // 验证 tag 的长度。GCM 模式时,它的范围是 4 到 16.
  284. $iv = (string)$iv;
  285. return @openssl_encrypt($content, $cipher, $key, $option, $iv);
  286. }
  287. /**
  288. * AES 解密
  289. * @param string $content base64密文
  290. * @param string $key 密钥
  291. * @param string $iv 向量,必须为数字
  292. * @param string $cipher 算法.
  293. * @param int $option 标记的按位或: OPENSSL_RAW_DATA=1 、 OPENSSL_ZERO_PADDING=2.
  294. * @return string
  295. */
  296. function aes_decrypt($content, $key, $iv = '', $cipher = 'AES-256-CBC', $option = 1)
  297. {
  298. $iv = (string)$iv;
  299. return @openssl_decrypt($content, $cipher, $key, $option, $iv);
  300. }
  301. /**
  302. * 通讯握手加密.
  303. * @param $content
  304. * @param $key
  305. * @param string $iv 向量,必须为数字
  306. * @return string
  307. */
  308. function hand_encrypt($content, $key, $iv = ''): string
  309. {
  310. $cipher = 'AES-128-ECB';
  311. if (is_array($content)) {
  312. $content = json_encode($content, JSON_UNESCAPED_UNICODE);
  313. }
  314. return base64_encode(aes_encrypt($content, $key, $iv, $cipher, 1));
  315. }
  316. /**
  317. * 通信握手解密.
  318. * @param $content
  319. * @param $key
  320. * @param string $iv 向量,必须为数字
  321. * @return false|string
  322. */
  323. function hand_decrypt($content, $key, $iv = '')
  324. {
  325. $cipher = 'AES-128-ECB';
  326. $content = base64_decode($content);
  327. return aes_decrypt($content, $key, $iv, $cipher, 1);
  328. }
  329. /**
  330. * 获取Request解密数据.
  331. * @return array|mixed
  332. */
  333. function getDecodeData()
  334. {
  335. $isValidMg = false;
  336. if (class_exists('\Modules\Manage\Services\AuthService')) {
  337. $service = make(\Modules\Manage\Services\AuthService::class);
  338. // 如果有效后台header,则直接不加密,进行明文通讯.
  339. $isValidMg = $service->checkValidMgHeaderHandShake();
  340. }
  341. $inputData = request()->all();
  342. if (!$isValidMg) {
  343. // 先拿系统里当前flag.
  344. $handshake = \App\Constants\CommonConstant::getHandShake();
  345. if (!empty($handshake)) {
  346. $allowShake = \App\Constants\CommonConstant::allowHandShakeKeys();
  347. $inputHandShake = $inputData['handshake'] ?? random(7);
  348. if (!array_key_exists($inputHandShake, $allowShake) || empty($inputHandShake)) {
  349. throw new \App\Exception\ApiException('在天愿作比翼鸟,在地愿为连理枝');
  350. }
  351. // if ($inputHandShake != $handshake) {
  352. // throw new \App\Exception\ApiException('在天愿作比翼鸟,在地愿为连理枝');
  353. // }
  354. $originData = $inputData['data'] ?? '';
  355. if (!is_string($originData)) {
  356. throw new \App\Exception\ApiException('数据格式有误1');
  357. }
  358. $arrMap = \App\Constants\CommonConstant::getHandSnakeKey($inputHandShake);
  359. try {
  360. $data = !empty($originData) ? json_decode(hand_decrypt($originData, $arrMap['key'], ''), true) : [];
  361. } catch (\Throwable $exception) {
  362. throw new \App\Exception\ApiException('数据格式有误2');
  363. }
  364. } else {
  365. $data = $inputData['data'] ?? [];
  366. }
  367. } else {
  368. $data = $inputData['data'] ?? [];
  369. }
  370. return $data;
  371. }
  372. /**
  373. * 过滤数据
  374. * @param $data - 1维数据
  375. * @return array
  376. * @tutorial 若数组值不是空长度则保留,反之就清除过滤
  377. */
  378. function action_data($data = array())
  379. {
  380. if (!$data) {
  381. return $data;
  382. }
  383. foreach ($data as $k => $v) {
  384. if (mb_strlen((string)$v) < 1) {
  385. unset($data[$k]);
  386. }
  387. }
  388. return $data;
  389. }
  390. /**
  391. * 加密ID.
  392. * @param $id
  393. * @param int $length 长度
  394. * @return string
  395. */
  396. function hashEncodeId($id, $length = 6)
  397. {
  398. $hashids = new Hashids(config('hashids.salt', ''), 6);
  399. return $hashids->encode($id);
  400. }
  401. /**
  402. * 解密ID.
  403. * @param $str
  404. * @return string
  405. */
  406. function hashDecodeId($str)
  407. {
  408. $hashids = new Hashids(config('hashids.salt', ''), 6);
  409. $arr = $hashids->decode($str);
  410. return implode('', $arr);
  411. }
  412. /**
  413. * 权重计算
  414. *
  415. * @param $data
  416. * @return mixed
  417. */
  418. function countWeight($data)
  419. {
  420. $temp = [];
  421. foreach ($data as $v) {
  422. if (isset($v->weights)) {
  423. for ($i = 0; $i < $v->weights; $i++) {
  424. $temp[] = $v;//放大数组
  425. }
  426. } else {
  427. for ($i = 0; $i < $v['weights']; $i++) {
  428. $temp[] = $v;//放大数组
  429. }
  430. }
  431. }
  432. $num = count($temp); //查看网上的有错误,本人已改正
  433. $int = mt_rand(0, $num - 1);//获取一个随机数
  434. $result = $temp[$int];
  435. return $result; //返回一维数组
  436. }
  437. /**
  438. * 凯撒对称加密核心算法
  439. * @param string $str 字符串源
  440. * @param string $type 类型,encode=加密,decode=解密
  441. * @param string $scale 范围, c=中文, l=字母, n=数字,多种用半角逗号分隔开
  442. * @param int $offset 偏移
  443. * @return string
  444. */
  445. function caesar_cipher($str, $type = 'encode', $scale = 'c,l,n', $offset = 3)
  446. {
  447. if (empty($str)) {
  448. return '';
  449. }
  450. if (!$offset) {
  451. // 无偏移, 直接返回原来的字符串
  452. return $str;
  453. }
  454. if (empty($scale)) {
  455. $scale = 'c,l,n';
  456. }
  457. if ($type == 'decode') {
  458. // 解密反向偏移
  459. $offset = -$offset;
  460. }
  461. $func = function ($match, $offset, $start, $end) {
  462. $min = ord($start);
  463. $max = ord($end);
  464. $flag_old = ord($match);
  465. $flag = $flag_old + $offset;
  466. if ($offset > 0) {
  467. if ($flag > $max) {
  468. $flag -= ($max - $min) + 1;
  469. }
  470. } elseif ($offset < 0) {
  471. if ($flag < $min) {
  472. $flag += ($max - $min) + 1;
  473. }
  474. }
  475. return chr($flag);
  476. };
  477. $arr_scale = explode(',', $scale); //允许的范围转换成数组,方便判断
  478. $pattern = '/[\x{4e00}-\x{9fbb}a-zA-Z0-9]/u';
  479. $result = preg_replace_callback(
  480. $pattern,
  481. function ($matches) use ($offset, $arr_scale, $func) {
  482. $str = $match = $matches[0];
  483. if (preg_match('/[\x{4e00}-\x{9fbb}]/u', $match)) {
  484. // 汉字
  485. if (in_array('c', $arr_scale)) {
  486. $min = intval(hexdec(unpack("H6codes", "一")['codes']));
  487. $max = intval(hexdec(unpack("H6codes", "龻")['codes']));
  488. $arr_hex = unpack("H6codes", $match);
  489. $zi_hex = $arr_hex['codes'];
  490. $zi_dec = intval(hexdec($zi_hex));
  491. $flag = $zi_dec + $offset;
  492. if ($offset > 0) {
  493. if ($flag > $max) {
  494. $flag -= ($max - $min) + 1;
  495. }
  496. } elseif ($offset < 0) {
  497. if ($flag < $min) {
  498. $flag += ($max - $min) + 1;
  499. }
  500. }
  501. $str_hex = dechex($flag);
  502. $str = pack("H". strlen($str_hex), $str_hex);
  503. }
  504. } elseif (preg_match('/[0-9]/', $match)) {
  505. // 数字
  506. if (in_array('n', $arr_scale)) {
  507. $str = $func($match, $offset, '0', '9');
  508. }
  509. } elseif (preg_match('/[a-z]/', $match)) {
  510. // 小写字母
  511. if (in_array('l', $arr_scale)) {
  512. $str = $func($match, $offset, 'a', 'z');
  513. }
  514. } elseif (preg_match('/[A-Z]/', $match)) {
  515. // 大写字母
  516. if (in_array('l', $arr_scale)) {
  517. $str = $func($match, $offset, 'A', 'Z');
  518. }
  519. }
  520. return $str;
  521. },
  522. $str
  523. );
  524. return $result;
  525. }
  526. /**
  527. * 凯撒对称加密
  528. * @param string $str 字符串源
  529. * @param string $scale 范围, c=中文, l=字母, n=数字,多种用半角逗号分隔开
  530. * @param int $offset 偏移
  531. * @return string
  532. */
  533. function caesar_encode($str, $scale = 'c,l,n', $offset = 3)
  534. {
  535. return caesar_cipher($str, 'encode', $scale, $offset);
  536. }
  537. /**
  538. * 凯撒对称解密
  539. * @param string $str 字符串源
  540. * @param string $scale 范围, c=中文, l=字母, n=数字,多种用半角逗号分隔开
  541. * @param int $offset 偏移
  542. * @return string
  543. */
  544. function caesar_decode($str, $scale = 'c,l,n', $offset = 3)
  545. {
  546. return caesar_cipher($str, 'decode', $scale, $offset);
  547. }
  548. /**
  549. * 处理异常时间的问题(如2022-02-31)
  550. *
  551. * @param $date
  552. * @return bool
  553. */
  554. function checkmydate($date) {
  555. $tempDate = explode('-', $date);
  556. return checkdate((int)$tempDate[1], (int)$tempDate[2], (int)$tempDate[0]);
  557. }
  558. /**
  559. * 处理结构体
  560. *
  561. * @param $message
  562. * @return mixed
  563. */
  564. function structureHandle(string $content, string $msgType)
  565. {
  566. $content = json_decode($content, true);
  567. switch ($msgType) {
  568. case 'text':
  569. $content['text'] = make(CommonService::class)->filterString($content['text']);
  570. break;
  571. case 'image':
  572. case 'file':
  573. case 'audio':
  574. $content['url'] = M3u8CacheRepository::getImageUrl($content['url']);
  575. break;
  576. case 'media':
  577. $content['url'] = M3u8CacheRepository::getVideoInnerUrl($content['url']);
  578. $content['cover'] = M3u8CacheRepository::getImageUrl($content['cover']);
  579. }
  580. return $content;
  581. }
  582. /**
  583. * 计算两个日期相隔多少年,多少月,多少天
  584. *
  585. * @param $startDate
  586. * @param $endData
  587. * @return array
  588. * @throws Exception
  589. */
  590. function diffDate($startDate, $endData)
  591. {
  592. $datetime1 = new \DateTime($startDate);
  593. $datetime2 = new \DateTime($endData);
  594. $interval = $datetime1->diff($datetime2);
  595. $time['y'] = $interval->format('%Y');
  596. $time['m'] = $interval->format('%m');
  597. $time['d'] = $interval->format('%d');
  598. return $time;
  599. }
  600. /**
  601. * 检测支付链接协议
  602. *
  603. * @param $payUrl
  604. * @return mixed|string
  605. */
  606. function checkPayUrl($payUrl) {
  607. if (strpos($payUrl, 'alipays://') !== false) {
  608. $payUrl = 'https://r.tool.py163.xyz/dk.html?_r_=' . urlencode($payUrl);
  609. }
  610. return $payUrl;
  611. }
  612. function truncateText($text, $max_length = 100, $suffix = '...') {
  613. if (mb_strlen($text, 'UTF-8') <= $max_length) {
  614. return $text;
  615. }
  616. return mb_substr($text, 0, $max_length, 'UTF-8') . $suffix;
  617. }