Helper.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. <?php
  2. namespace App\libs\helpers;
  3. use app\Auth;
  4. use App\libs\cache\redis\Redis;
  5. use Illuminate\Support\Facades\Config;
  6. use Illuminate\Support\Facades\DB;
  7. class Helper
  8. {
  9. protected $client;
  10. protected $key;
  11. public function __construct()
  12. {
  13. $this->key = 'odsniK8Xk0tMuJbwyztEPjRLLo';
  14. $this->sk = '9936be1a0451712e0f58866ac6be7a4f';
  15. }
  16. public function opensd($post = [])
  17. {
  18. $API_URL = 'https://api.wike.cc/api/painting/opensd';
  19. $post['key'] = $this->key;
  20. $res = $this->send($API_URL, $post, 'POST', true, $this->sk);
  21. return $res;
  22. }
  23. public function opensdDetail($id)
  24. {
  25. $API_URL = 'https://api.wike.cc/api/painting/result';
  26. $post['key'] = $this->key;
  27. $post['id'] = $id;
  28. $res = $this->send($API_URL, $post, 'GET', true, $this->sk);
  29. return $res;
  30. }
  31. /**
  32. * 获取框架 root 路径.
  33. *
  34. * @return bool
  35. */
  36. public static function frameRootPath()
  37. {
  38. return DIRECTORY_SEPARATOR === '\\' ? 'E:\TP6_V4' : '/Users/wangdakun/Desktop/wangdakun/TP6_V4';
  39. }
  40. public static function send($API_URL, $get_post_data, $type, $ifsign, $sk)
  41. {
  42. $get_post_data = http_build_query($get_post_data);
  43. if ($ifsign) {
  44. $sign = md5($get_post_data . $sk);
  45. $res = self::send_curl($API_URL, $type, $get_post_data, $sign);
  46. } else {
  47. $res = self::send_curl($API_URL, $type, $get_post_data, null);
  48. }
  49. return $res;
  50. }
  51. public static function send_curl($API_URL, $type, $get_post_data, $sign)
  52. {
  53. $ch = curl_init();
  54. if ('POST' == $type) {
  55. curl_setopt($ch, CURLOPT_URL, $API_URL);
  56. curl_setopt($ch, CURLOPT_POST, true);
  57. curl_setopt($ch, CURLOPT_POSTFIELDS, $get_post_data);
  58. } elseif ('GET' == $type) {
  59. curl_setopt($ch, CURLOPT_URL, $API_URL . '?' . $get_post_data);
  60. }
  61. if ($sign) {
  62. curl_setopt($ch, CURLOPT_HTTPHEADER, ['sign:' . $sign]);
  63. }
  64. curl_setopt($ch, CURLOPT_REFERER, $API_URL);
  65. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  66. curl_setopt($ch, CURLOPT_TIMEOUT, 300);
  67. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  68. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  69. $resdata = curl_exec($ch);
  70. curl_close($ch);
  71. return $resdata;
  72. }
  73. public static function getAccessToken()
  74. {
  75. $curl = curl_init();
  76. $postData = [
  77. 'grant_type' => getenv('BAIDU_GRANT_TYPE'),
  78. 'client_id' => getenv('BAIDU_CLIENT_ID'),
  79. 'client_secret' => getenv('BAIDU_CLIENT_SECRET'),
  80. ];
  81. curl_setopt_array($curl, [
  82. CURLOPT_URL => 'https://aip.baidubce.com/oauth/2.0/token',
  83. CURLOPT_CUSTOMREQUEST => 'POST',
  84. CURLOPT_RETURNTRANSFER => true,
  85. CURLOPT_POSTFIELDS => http_build_query($postData),
  86. ]);
  87. $response = curl_exec($curl);
  88. curl_close($curl);
  89. $rtn = json_decode($response);
  90. return $rtn->access_token;
  91. }
  92. /**
  93. * @desc 过滤emoji表情
  94. *
  95. * @return string|string[]|null
  96. */
  97. public static function filterEmoji($str)
  98. {
  99. return preg_replace_callback('/./u', static fn (array $match) => \strlen($match[0]) >= 4 ? '' : $match[0], $str);
  100. }
  101. /**
  102. * @desc 字节转换
  103. *
  104. * @return string
  105. */
  106. public static function sizeConvert(int $numSize)
  107. {
  108. if ($numSize >= 1073741824) {
  109. $charSize = round($numSize / 1024 ** 3 * 100) / 100 . ' GB';
  110. } elseif ($numSize >= 1048576) {
  111. // 转成MB
  112. $charSize = round($numSize / 1024 ** 2 * 100) / 100 . ' MB';
  113. } elseif ($numSize >= 1024) {
  114. // 转成KB
  115. $charSize = round($numSize / 1024 * 100) / 100 . ' KB';
  116. } else {
  117. // 不转换直接输出
  118. $charSize = $numSize . ' B';
  119. }
  120. return $charSize;
  121. }
  122. /**
  123. * @desc 数字单位转换
  124. *
  125. * @return string
  126. */
  127. public static function numberConvert(int $number)
  128. {
  129. if ($number >= 1000 && $number < 10000) {
  130. $number = sprintf('%.1f', $number / 1000) . ' K';
  131. } elseif ($number >= 10000) {
  132. $number = sprintf('%.1f', $number / 10000) . ' W';
  133. } elseif ($number >= 1000000) {
  134. $number = sprintf('%.1f', $number / 10000) . ' M';
  135. }
  136. return $number;
  137. }
  138. /**
  139. * @desc 生成 hash token
  140. */
  141. public static function hashToken(string $value)
  142. {
  143. $hash = hash_hmac('sha1', $value . mt_rand() . time(), mt_rand(), true);
  144. return str_replace('=', '', strtr(base64_encode($hash), '+/', '-_'));
  145. }
  146. /**
  147. * @desc 是否微信环境
  148. *
  149. * @return bool|mixed
  150. */
  151. public static function isWeixin()
  152. {
  153. return str_contains($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') ? true : false;
  154. }
  155. /**
  156. * @desc ssl 加密
  157. *
  158. * @param $str 待加密字符
  159. * @param string $key 加密key
  160. * @param string $iv 偏移iv
  161. *
  162. * @return string
  163. */
  164. public static function encrypt($str, $key = 'cdlchdwxcdh5', $iv = 'cdlchd0123456789')
  165. {
  166. return bin2hex(openssl_encrypt($str, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv));
  167. }
  168. /**
  169. * @desc ssl 解密
  170. *
  171. * @param string $str 待解密字符
  172. * @param string $key 加密key
  173. * @param string $iv 偏移iv
  174. *
  175. * @return string
  176. */
  177. public static function decrypt($str, $key = 'cdlchdwxcdh5', $iv = 'cdlchd0123456789')
  178. {
  179. return openssl_decrypt(hex2bin($str), 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
  180. }
  181. /**
  182. * @desc 记录日志
  183. */
  184. public static function apiLogs(array $data, string $remarks = ''): void
  185. {
  186. $request = request();
  187. $data = [
  188. 'token' => $request->header('token', null),
  189. 'uid' => Auth::$userId,
  190. 'url' => $request->url(),
  191. 'controller' => $request->controller(),
  192. 'func' => $request->action(),
  193. 'method' => $request->method(),
  194. 'ip' => $request->ip(),
  195. 'params' => json_encode($data, 256),
  196. 'remarks' => $remarks,
  197. 'day' => strtotime('today'),
  198. 'create' => time(),
  199. ];
  200. $rdsConf = Config::get('lc.redis');
  201. if ($rdsConf['log_open']) {
  202. $redis = Redis::instance();
  203. $redis->select($rdsConf['db']);
  204. $redis->rPush(env('id') . '_apilogs', json_encode($data, 256));
  205. } else {
  206. Db::name('api_logs')->insert($data);
  207. }
  208. }
  209. /**
  210. * @desc 将xml转为array
  211. *
  212. * @return array
  213. *
  214. * @throws \Exception
  215. */
  216. public static function xmlToArray($xml)
  217. {
  218. if (!$xml) {
  219. throw new \Exception('xml数据异常!');
  220. }
  221. // 禁止引用外部xml实体
  222. libxml_disable_entity_loader(true);
  223. return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  224. }
  225. /**
  226. * @desc 输出xml字符
  227. *
  228. * @param array $data
  229. *
  230. * @return string
  231. *
  232. * @throws \Exception
  233. */
  234. public static function arrayToXml($data)
  235. {
  236. if (!\is_array($data) || \count($data) <= 0) {
  237. throw new \Exception('数组数据异常!');
  238. }
  239. $xml = '<xml>';
  240. foreach ($data as $key => $val) {
  241. if (is_numeric($val)) {
  242. $xml .= '<' . $key . '>' . $val . '</' . $key . '>';
  243. } else {
  244. $xml .= '<' . $key . '><![CDATA[' . $val . ']]></' . $key . '>';
  245. }
  246. }
  247. $xml .= '</xml>';
  248. return $xml;
  249. }
  250. /**
  251. * @desc 按字典序生成签名
  252. *
  253. * @param array $data 签名数据
  254. * @param string $key 前面key
  255. *
  256. * @return string
  257. */
  258. public static function makeSign(array $data, string $key)
  259. {
  260. // 1. 按字典序排序参数
  261. ksort($data);
  262. $string = self::signUrlParams($data);
  263. // 2. 在string后加入KEY
  264. $string = $string . '&key=' . $key;
  265. // 3. MD5加密
  266. $string = md5($string);
  267. // 4. 所有字符转为大写
  268. return strtoupper($string);
  269. }
  270. /**
  271. * @desc 获取毫秒级别的时间戳
  272. */
  273. public static function millisecond()
  274. {
  275. // 获取毫秒的时间戳
  276. $time = explode(' ', microtime());
  277. $time = $time[1] . ($time[0] * 1000);
  278. $time2 = explode('.', $time);
  279. return $time2[0];
  280. }
  281. /**
  282. * @desc 产生随机字符串,不长于32位
  283. *
  284. * @param int $length
  285. *
  286. * @return string 产生的随机字符串
  287. */
  288. public static function generateNonceStr($length = 32)
  289. {
  290. $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  291. $str = '';
  292. for ($i = 0; $i < $length; ++$i) {
  293. $str .= substr($chars, mt_rand(0, \strlen($chars) - 1), 1);
  294. }
  295. return $str;
  296. }
  297. /**
  298. * @desc 对emoji表情转义
  299. *
  300. * @return string
  301. */
  302. public static function emojiEncode($str)
  303. {
  304. $strEncode = '';
  305. $length = mb_strlen($str, 'utf-8');
  306. for ($i = 0; $i < $length; ++$i) {
  307. $tmpStr = mb_substr($str, $i, 1, 'utf-8');
  308. if (\strlen($tmpStr) >= 4) {
  309. $strEncode .= '[[EMOJI:' . rawurlencode($tmpStr) . ']]';
  310. } else {
  311. $strEncode .= $tmpStr;
  312. }
  313. }
  314. return $strEncode;
  315. }
  316. /**
  317. * @desc 对emoji表情转反义
  318. *
  319. * @return string|string[]|null
  320. */
  321. public static function emojiDecode($str)
  322. {
  323. return preg_replace_callback('|\[\[EMOJI:(.*?)\]\]|', static fn ($matches) => rawurldecode($matches[1]), $str);
  324. }
  325. /**
  326. * @desc 判断请求机型
  327. *
  328. * @return string
  329. */
  330. public static function deviceType()
  331. {
  332. $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
  333. $type = 'other';
  334. // 分别进行判断
  335. if (strpos($agent, 'iphone') || strpos($agent, 'ipad')) {
  336. $type = 'ios';
  337. }
  338. if (strpos($agent, 'android')) {
  339. $type = 'android';
  340. }
  341. return $type;
  342. }
  343. /**
  344. * @desc 记录日志
  345. *
  346. * @param string $filename 文件名
  347. * @param string $log 日志内容
  348. * @param float|int $fileSize 文件日志大小,默认最大2M,超过则重命名
  349. */
  350. public static function log(string $filename, string $log, $fileSize = 2 * 1024 * 1024): void
  351. {
  352. $path = \dirname($filename);
  353. if (!is_dir($path)) {
  354. mkdir($path, 0755, true);
  355. }
  356. if (is_file($filename) && floor($fileSize) <= filesize($filename)) {
  357. try {
  358. rename($filename, \dirname($filename) . \DIRECTORY_SEPARATOR . time() . '-' . basename($filename));
  359. } catch (\Exception $e) {
  360. }
  361. }
  362. error_log($log, 3, $filename);
  363. }
  364. /**
  365. * 求两点之间的距离.
  366. *
  367. * @param $thisLongitude 当前经度
  368. * @param $thisLatitude 当前纬度
  369. * @param $stayLongitude 待计算经度
  370. * @param $stayLatitude 待计算纬度
  371. * @param int $unit 单位,1米,2千米
  372. * @param int $decimals 保留小数点几位
  373. *
  374. * @return string
  375. */
  376. public static function calculateDistance($thisLongitude, $thisLatitude, $stayLongitude, $stayLatitude, $unit = 1, $decimals = 0)
  377. {
  378. // 原始坐标纬度弧度 deg2rad()函数将角度转换为弧度
  379. $oriLatRad = deg2rad($thisLatitude);
  380. // 新坐标纬度弧度
  381. $newLatRad = deg2rad($stayLatitude);
  382. // 坐标纬度弧度差
  383. $diffLatRad = deg2rad($thisLatitude) - deg2rad($stayLatitude);
  384. // 经度弧度差
  385. $diffLngRad = deg2rad($thisLongitude) - deg2rad($stayLongitude);
  386. // sin 求正弦值 参数单位为弧度 sin(2) => 0.90929742682568
  387. // cos 求余弦值 参数单位为弧度 cos(0.2) => 0.98006657784124
  388. // sqrt 求平方根 sqrt(2) => 1.4142135623731
  389. // asin 求反正弦 参数单位为弧度 asin(2) => 1.4142135623731
  390. // pow 求幂 pow(2, 2) => 4
  391. $distance = 2 * asin(sqrt(sin($diffLatRad / 2) ** 2 + cos($oriLatRad) * cos($newLatRad) * sin($diffLngRad / 2) ** 2)) * 6378.137 * 1000;
  392. if (2 === $unit) {
  393. $distance = $distance / 1000;
  394. }
  395. return number_format($distance, $decimals);
  396. }
  397. /**
  398. * 导出csv数据.
  399. *
  400. * @param $title 表名
  401. * @param $cell 表头
  402. * @param $data 数据
  403. * @param null $closure
  404. */
  405. public static function exportCsv($title, $cell, $data, $closure = null): void
  406. {
  407. set_time_limit(0);
  408. ini_set('memory_limit', '1024M');
  409. $output = fopen('php://output', 'w') || exit("can't open php://output");
  410. if (ob_get_contents()) {
  411. ob_clean();
  412. }
  413. header('Content-Type: application/force-download');
  414. header('Content-type: text/csv;charset=utf-8');
  415. header('Content-Disposition: attachment; filename=' . $title . '.csv');
  416. echo \chr(0xEF) . \chr(0xBB) . \chr(0xBF);
  417. fputcsv($output, $cell);
  418. foreach ($data as $v) {
  419. if ($closure instanceof \Closure) {
  420. $v = $closure($v);
  421. }
  422. fputcsv($output, array_values($v));
  423. }
  424. fclose($output) || exit("can't close php://output");
  425. exit;
  426. }
  427. /**
  428. * @desc 签名格式化成url参数
  429. *
  430. * @param array $params 格式化参数
  431. *
  432. * @return string
  433. */
  434. private static function signUrlParams(array $params)
  435. {
  436. $buff = '';
  437. foreach ($params as $k => $v) {
  438. if ('sign' !== $k && '' !== $v && !\is_array($v)) {
  439. $buff .= $k . '=' . $v . '&';
  440. }
  441. }
  442. return trim($buff, '&');
  443. }
  444. }