Helper.php 11 KB

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