Utils.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <?php
  2. namespace App\Libs;
  3. use App\Cache\CacheKeys;
  4. use App\Exceptions\ApiException;
  5. use Hashids;
  6. use Illuminate\Support\Arr;
  7. use Illuminate\Support\Facades\DB;
  8. use Illuminate\Support\Facades\Redis;
  9. class Utils
  10. {
  11. /**
  12. * 异常报错
  13. * @param $errorData
  14. * @throws ApiException
  15. */
  16. public static function throwError($errorData)
  17. {
  18. // 分解错误码、错误信息
  19. $errorStr = (string)$errorData;
  20. // 查找第一个冒号的位置
  21. $firstColonPos = strpos($errorStr, ':');
  22. if ($firstColonPos === false) {
  23. // 如果没有冒号,默认错误码为0,整个字符串作为错误信息
  24. $code = 0;
  25. $msg = $errorStr;
  26. } else {
  27. // 提取错误码(第一个冒号之前的部分)
  28. $code = (int)substr($errorStr, 0, $firstColonPos);
  29. // 提取错误信息(第一个冒号之后的部分)
  30. $msg = substr($errorStr, $firstColonPos + 1);
  31. // 将错误信息中剩余的英文冒号替换为中文冒号
  32. $msg = str_replace(':', ':', $msg);
  33. }
  34. throw new ApiException($code, $msg);
  35. }
  36. /**
  37. * 解码加密id
  38. * @param $idStr
  39. * @return int
  40. */
  41. public static function getDecodeId($idStr)
  42. {
  43. if (!is_numeric($idStr)) {
  44. $idArr = Hashids::decode($idStr);
  45. $id = isset($idArr[0]) ? (int)$idArr[0] : 0;
  46. } else {
  47. $id = $idStr;
  48. }
  49. return $id;
  50. }
  51. /**
  52. * 加密id
  53. * @param $id
  54. * @return mixed
  55. */
  56. public static function getEncodeId($id)
  57. {
  58. return Hashids::encode($id);
  59. }
  60. /**
  61. * 加密批量bid
  62. * @param $bids
  63. * @return array
  64. */
  65. public static function getEncodeIds($bids)
  66. {
  67. return array_map(function ($bid) {
  68. return Hashids::encode($bid);
  69. }, $bids);
  70. }
  71. /**
  72. * 审核状态判断,true为审核状态,false默认
  73. * @param $package
  74. * @param $brand
  75. * @param $codeVersion
  76. * @return bool
  77. */
  78. public static function checkIsAudit($package, $brand, $codeVersion): bool
  79. {
  80. $audit = getProp(config('audit'), $package, []);
  81. if ($audit && $codeVersion === getProp($audit, 'codeVersion') && strtolower($brand) === getProp($audit, 'brand')) {
  82. return true;
  83. }
  84. return false;
  85. }
  86. /**
  87. * redis key组装
  88. * @param $keyStr
  89. * @param $args
  90. * @return string
  91. */
  92. public static function getCacheKey($keyStr, $args = [])
  93. {
  94. $stdStr = Arr::get(CacheKeys::$all, $keyStr, '');
  95. if ($args) {
  96. $stdStr = sprintf($stdStr, ...$args);
  97. }
  98. return $stdStr;
  99. }
  100. /**
  101. * 展示友好数字
  102. * @param $num
  103. * @return string
  104. */
  105. public static function showNiceNumber($num)
  106. {
  107. if ($num >= 10000) {
  108. $num = sprintf('%.1f', round($num / 10000 * 100) / 100) . '万';
  109. } elseif ($num >= 1000) {
  110. $num = sprintf('%.1f', round($num / 1000 * 100) / 100) . '千';
  111. }
  112. return $num;
  113. }
  114. /**
  115. * 根据日期获得这周的周一
  116. * @param $date
  117. * @param int $d
  118. * @param string $format
  119. * @return false|string
  120. */
  121. public static function firstOfWeek($date, $d = 0, $format = 'Ymd')
  122. {
  123. $now = strtotime($date) - $d * 86400; //当时的时间戳
  124. $number = date("w", $now); //当时是周几
  125. $number = $number == 0 ? 7 : $number; //如遇周末,将0换成7
  126. $diff_day = $number - 1; //求到周一差几天
  127. return date($format, $now - ($diff_day * 60 * 60 * 24));
  128. }
  129. /**
  130. * 老原创的签名
  131. * @param $time
  132. * @return string
  133. */
  134. public static function getOldYcSign($time): string
  135. {
  136. $privateKey = env('EXTERNAL_PRIVATE_KEY');
  137. return md5(md5($time . $privateKey) . $privateKey);
  138. }
  139. /**
  140. * @param array $data
  141. * @param array $colHeaders
  142. * @param bool $asString
  143. * @return bool|string
  144. */
  145. public static function toCSV(array $data, array $colHeaders = array(), $asString = false)
  146. {
  147. $stream = $asString ? fopen('php://temp/maxmemory', 'wb+') : fopen('php://output', 'wb');
  148. if (!empty($colHeaders)) {
  149. fputcsv($stream, $colHeaders);
  150. }
  151. foreach ($data as $record) {
  152. fputcsv($stream, $record);
  153. }
  154. if ($asString) {
  155. rewind($stream);
  156. $returnVal = stream_get_contents($stream);
  157. fclose($stream);
  158. return $returnVal;
  159. }
  160. fclose($stream);
  161. return true;
  162. }
  163. /**
  164. * 设备信息
  165. * @return string
  166. */
  167. public static function getDeviceType(): string
  168. {
  169. //全部变成小写字母
  170. $agent = strtolower(getProp($_SERVER, 'HTTP_USER_AGENT'));
  171. $type = 'other';
  172. //分别进行判断
  173. if (strpos($agent, 'iphone') || strpos($agent, 'ipad')) {
  174. $type = 'ios';
  175. }
  176. if (strpos($agent, 'android')) {
  177. $type = 'android';
  178. }
  179. return $type;
  180. }
  181. /**
  182. * 是否在微信内打卡
  183. * @return bool
  184. */
  185. public static function isOpenedInWechat(): bool
  186. {
  187. //全部变成小写字母
  188. $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
  189. //判断
  190. if (strpos($agent, 'micromessenger')) {
  191. return true;
  192. }
  193. return false;
  194. }
  195. /**
  196. * 组装meta数据
  197. * @param $page
  198. * @param $total
  199. * @param int $pageSize
  200. * @return array
  201. */
  202. public static function buildMeta($page, $total, $pageSize = 15): array
  203. {
  204. $lastPage = (int)ceil($total / $pageSize);
  205. return [
  206. 'current_page' => (int)$page,
  207. 'next_page' => ++$page,
  208. 'last_page' => $lastPage ?? 1,
  209. 'per_page' => (int)$pageSize,
  210. 'total' => (int)$total,
  211. 'next_page_url' => '',
  212. 'prev_page_url' => ''
  213. ];
  214. }
  215. /**
  216. * 获取token保存的信息
  217. * @param $token
  218. * @return mixed
  219. */
  220. public static function getTokenData($token) {
  221. $tokenJson = Redis::get($token);
  222. return json_decode($tokenJson, true);
  223. }
  224. /**
  225. * 获取口令码
  226. * @param $uid
  227. * @param $bid
  228. * @return int|mixed|null
  229. */
  230. public static function getPasswordCode($uid, $bid) {
  231. $code = DB::table('user_book_code')->where(['uid'=>$uid, 'bid'=>$bid])->value('id');
  232. if (!$code) {
  233. $code = DB::table('user_book_code')->insertGetId([
  234. 'uid' => $uid,
  235. 'bid' => $bid,
  236. 'created_at' => date('Y-m-d H:i:s'),
  237. 'updated_at' => date('Y-m-d H:i:s'),
  238. ]);
  239. }
  240. return '请在抖音搜索"火猫小说"后搜索口令'.$code.',开始阅读吧!';
  241. }
  242. /**
  243. * 获取远程图片信息
  244. * @param string $url 图片URL
  245. * @param bool $needSize 是否需要获取文件大小
  246. * @return array|false
  247. */
  248. public static function getRemoteImageInfo($url, $needSize = false)
  249. {
  250. try {
  251. // 使用getimagesize获取图片信息
  252. $imageInfo = @getimagesize($url);
  253. if ($imageInfo === false) {
  254. return false;
  255. }
  256. $info = [
  257. 'width' => $imageInfo[0],
  258. 'height' => $imageInfo[1],
  259. 'mime' => $imageInfo['mime'] ?? '',
  260. 'size' => 0,
  261. 'extension' => ''
  262. ];
  263. if ($info['mime']) {
  264. $info['extension'] = mimeToExt($info['mime']);
  265. }
  266. // 如果需要获取文件大小
  267. if ($needSize) {
  268. $headers = @get_headers($url, 1);
  269. if ($headers && isset($headers['Content-Length'])) {
  270. $info['size'] = is_array($headers['Content-Length']) ?
  271. (int)end($headers['Content-Length']) :
  272. (int)$headers['Content-Length'];
  273. } else {
  274. // 如果无法通过headers获取,尝试下载部分内容来估算大小
  275. $context = stream_context_create([
  276. 'http' => [
  277. 'method' => 'GET',
  278. 'header' => 'Range: bytes=0-1023', // 只下载前1KB来估算
  279. 'timeout' => 10
  280. ]
  281. ]);
  282. $partialContent = @file_get_contents($url, false, $context);
  283. if ($partialContent !== false) {
  284. // 这只是一个估算值,实际大小可能不同
  285. $info['size'] = strlen($partialContent);
  286. }
  287. }
  288. }
  289. return $info;
  290. } catch (\Exception $e) {
  291. return false;
  292. }
  293. }
  294. }