helpers.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. <?php
  2. /*
  3. * This file is part of the Jiannei/lumen-api-starter.
  4. *
  5. * (c) Jiannei <longjian.huang@foxmail.com>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. use App\Repositories\Enums\ResponseCodeEnum;
  11. use Illuminate\Support\Arr;
  12. use Illuminate\Support\Facades\Http;
  13. use Illuminate\Support\Facades\Log;
  14. use Illuminate\Support\Facades\Storage;
  15. /**
  16. * @param $str
  17. * @param $glue
  18. * @return array
  19. */
  20. function str2arr($str, $glue = ',')
  21. {
  22. return array_filter(array_unique(explode($glue, $str)));
  23. }
  24. function arr2str($arr, $glue = ',')
  25. {
  26. return implode($glue, array_unique(Arr::wrap($arr)));
  27. }
  28. function str2arr0($str, $glue = ',')
  29. {
  30. return explode($glue, $str);
  31. }
  32. function arr2str0($arr, $glue = ',')
  33. {
  34. return implode($glue, (Arr::wrap($arr)));
  35. }
  36. function php2js($arr)
  37. {
  38. return json_encode($arr, JSON_UNESCAPED_UNICODE);
  39. }
  40. function js2php($json)
  41. {
  42. return json_decode($json, JSON_UNESCAPED_UNICODE);
  43. }
  44. /**
  45. * 取数组的值
  46. * @param $key
  47. * @param $arr
  48. * @param string $default
  49. * @return mixed|string
  50. * Author: Mead
  51. */
  52. function get_arr_val($key, $arr = [], $default = '')
  53. {
  54. if (array_key_exists($key, $arr) && $arr[$key] != null) {
  55. return $arr[$key];
  56. }
  57. return $default;
  58. }
  59. /**
  60. * 路径转地址
  61. * @param $path
  62. * @param string $disk
  63. * @return mixed
  64. * Author: Mead
  65. */
  66. function path_to_url($path, $disk = 'public')
  67. {
  68. if (empty($path)) return null;
  69. // 如果 image 字段本身就已经是完整的 url 就直接返回
  70. if (\Illuminate\Support\Str::startsWith($path, ['http://', 'https://'])) {
  71. return $path;
  72. }
  73. return \Illuminate\Support\Facades\Storage::disk($disk)->url($path);
  74. }
  75. function url_to_path($val, $disk = 'public')
  76. {
  77. return str_replace(config("filesystems.disks.{$disk}.url") . '/', '', $val);
  78. }
  79. function is_user_login()
  80. {
  81. return auth('api')->check();
  82. }
  83. function login_user()
  84. {
  85. return auth('api')->user();
  86. }
  87. function login_admin()
  88. {
  89. return auth('admins')->user();
  90. }
  91. function login_user_id()
  92. {
  93. return auth('api')->id();
  94. }
  95. function login_admin_id()
  96. {
  97. return auth('admins')->id();
  98. }
  99. function is_admin_login()
  100. {
  101. return auth('admins')->check();
  102. }
  103. /**
  104. * 数组转树状
  105. * @param array $data
  106. * @param string $primary
  107. * @param string $parent
  108. * @param string $children
  109. * @return array
  110. * Author: Mead
  111. */
  112. function toTree($data = [], $primary = 'id', $parent = 'parent_id', $children = 'children')
  113. {
  114. if (!isset($data[0][$parent])) {
  115. return [];
  116. }
  117. $items = array();
  118. // $pids = [];
  119. foreach ($data as $v) {
  120. $items[$v[$primary]] = $v;
  121. // $pids[] = $v[$parent];
  122. }
  123. $tree = array();
  124. foreach ($items as &$item) {
  125. // if (in_array($item['id'], $pids)) {
  126. // $item['is_base'] = false;
  127. // } else {
  128. // $item['is_base'] = true;
  129. // }
  130. if (isset($items[$item[$parent]])) {
  131. $items[$item[$parent]][$children][] = &$items[$item[$primary]];
  132. } else {
  133. $tree[] = &$items[$item[$primary]];
  134. }
  135. }
  136. return $tree;
  137. }
  138. /**
  139. * 二维数组根据某个字段排序
  140. * @param array $array 要排序的数组
  141. * @param string $keys 要排序的键字段
  142. * @param string $sort 排序类型 SORT_ASC SORT_DESC
  143. * @return array 排序后的数组
  144. */
  145. function arraySort($array, $keys, $sort = SORT_DESC)
  146. {
  147. $keysValue = [];
  148. foreach ($array as $k => $v) {
  149. $keysValue[$k] = $v[$keys];
  150. }
  151. array_multisort($keysValue, $sort, $array);
  152. return $array;
  153. }
  154. function match_chinese($chars, $encoding = 'utf8')
  155. {
  156. $pattern = ($encoding == 'utf8') ? '/[\x{4e00}-\x{9fa5}a-zA-Z0-9_.]/u' : '/[\x80-\xFF]/';
  157. preg_match_all($pattern, $chars, $result);
  158. $temp = join('', $result[0]);
  159. return $temp;
  160. }
  161. function arr_str($arr)
  162. {
  163. return '-' . arr2str($arr, '-') . '-';
  164. }
  165. function str_arr($str)
  166. {
  167. return str2arr(trim($str, '-'), '-');
  168. }
  169. function wechat_fee($money)
  170. {
  171. $m = (int)($money * 100);
  172. if (login_admin_id() > 3) {
  173. if ($money <= 0) {
  174. return 1;
  175. }
  176. }
  177. return $m;
  178. }
  179. function arr2type($arr)
  180. {
  181. return '-' . arr2str($arr, '-') . '-';
  182. }
  183. function type2arr($str)
  184. {
  185. return str2arr(trim($str, '-'), '-');
  186. }
  187. function T($key)
  188. {
  189. if (\Illuminate\Support\Facades\App::getLocale() == 'zh_CN') {
  190. return __("messages.{$key}");
  191. } else {
  192. return __($key);
  193. }
  194. }
  195. if (!function_exists('config_path')) {
  196. /**
  197. * Get the configuration path.
  198. *
  199. * @param string $path
  200. * @return string
  201. */
  202. function config_path($path = '')
  203. {
  204. return app()->basePath() . '/config' . ($path ? '/' . $path : $path);
  205. }
  206. }
  207. /**
  208. * 秒数转时间
  209. * @param $sec
  210. * @return string
  211. * Author: Mead
  212. */
  213. function sec2time($sec)
  214. {
  215. $mes = '';
  216. if ($sec >= 3600) {
  217. $hours = str_pad(floor($sec / 3600), 2, "0", STR_PAD_LEFT);
  218. $sec = ($sec % 3600);
  219. $mes .= "{$hours}:";
  220. }
  221. if ($sec >= 60) {
  222. $minutes = str_pad(floor($sec / 60), 2, "0", STR_PAD_LEFT);;
  223. $sec = ($sec % 60);
  224. $mes .= "{$minutes}:";
  225. } else {
  226. $mes .= "00:";
  227. }
  228. $seconds = str_pad(floor($sec), 2, "0", STR_PAD_LEFT);;
  229. $mes .= "{$seconds}";
  230. return $mes;
  231. }
  232. /**
  233. * 字符为空
  234. * @return string
  235. * Author: Mead
  236. */
  237. function str_is_null()
  238. {
  239. return '--';
  240. }
  241. /**
  242. * 检查密码
  243. * @param $password
  244. * @return bool|string
  245. * Author: Mead
  246. */
  247. function check_password($password)
  248. {
  249. $score = 0;
  250. $str = $password;
  251. $num = 0;
  252. if (preg_match("/[0-9]+/", $str)) {
  253. $score++;
  254. $num++;
  255. }
  256. if (preg_match("/[0-9]{3,}/", $str)) {
  257. $score++;
  258. }
  259. if (preg_match("/[a-z]+/", $str)) {
  260. $score++;
  261. $num++;
  262. }
  263. if (preg_match("/[a-z]{3,}/", $str)) {
  264. $score++;
  265. }
  266. if (preg_match("/[A-Z]+/", $str)) {
  267. $score++;
  268. $num++;
  269. }
  270. if (preg_match("/[A-Z]{3,}/", $str)) {
  271. $score++;
  272. }
  273. if (preg_match("/[_|\-|+|=|*|!|@|#|$|%|.|^|&|(|)]+/", $str)) {
  274. $score += 2;
  275. $num++;
  276. }
  277. if (preg_match("/[_|\-|+|=|*|!|@|#|$|%|.|^|&|(|)]{3,}/", $str)) {
  278. $score++;
  279. }
  280. if (strlen($str) >= 10) {
  281. $score++;
  282. }
  283. $msg = false;
  284. if ($score < 4) {
  285. return false;
  286. // $msg = '密码太简单!';
  287. }
  288. if ($num < 2) {
  289. return false;
  290. // $msg = '密码必须包含数字、字母、符号两种类型!';
  291. }
  292. return true;
  293. }
  294. /**
  295. * 获取登录ip
  296. * @return array|false|mixed|string
  297. * Author: Mead
  298. */
  299. function getClientIp()
  300. {
  301. if (getenv('HTTP_CLIENT_IP')) {
  302. $ip = getenv('HTTP_CLIENT_IP');
  303. } elseif (getenv('HTTP_X_REAL_IP')) {
  304. $ip = getenv('HTTP_X_REAL_IP');
  305. } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
  306. $ip = getenv('HTTP_X_FORWARDED_FOR');
  307. $ips = explode(',', $ip);
  308. $ip = $ips[0];
  309. } elseif (getenv('REMOTE_ADDR')) {
  310. $ip = getenv('REMOTE_ADDR');
  311. } else {
  312. $ip = '0.0.0.0';
  313. }
  314. return $ip;
  315. }
  316. /**
  317. * 获取控制器的方法
  318. * @return array
  319. */
  320. function getControllerAndFunction()
  321. {
  322. $routeInfo = app('request')->route()[1]['uses'];
  323. $module = 'Api';
  324. if (strpos($routeInfo, "\Admin\\") !== false) $module = 'Admin';
  325. list($class, $method) = explode('@', $routeInfo);
  326. $class = substr(strrchr($class, '\\'), 1);
  327. return ['controller' => $class, 'method' => $method, 'module' => $module];
  328. }
  329. /**
  330. * 是否为后台模块
  331. * @return bool
  332. */
  333. function isAdminModule()
  334. {
  335. $routeInfo = app('request')->route()[1]['uses'];
  336. $module = false;
  337. if (strpos($routeInfo, "\Admin\\") !== false) $module = true;
  338. return $module;
  339. }
  340. /**
  341. * 二维数组去重
  342. * @param $arr
  343. * @param $key
  344. * @return array
  345. */
  346. function array_unset_tt($arr = [], $key = null)
  347. {
  348. //建立一个目标数组
  349. $res = array();
  350. foreach ($arr as $value) {
  351. //查看有没有重复项
  352. if (isset($res[$value[$key]])) {
  353. unset($value[$key]);
  354. } else {
  355. $res[$value[$key]] = $value;
  356. }
  357. }
  358. return array_values($res);
  359. }
  360. /**
  361. * 获取权限key
  362. * @return string
  363. */
  364. function getPermissionKey()
  365. {
  366. $request = request();
  367. $method = $request->method();
  368. $path = str_replace('/', ':', trim($request->path(), '/'));
  369. $key = "{$method}|{$path}";
  370. return $key;
  371. }
  372. /**
  373. * 获取配置参数
  374. * @param $code
  375. * @return string|mixed
  376. */
  377. function byCodeGetSetting($code)
  378. {
  379. return \App\Repositories\Models\Base\Setting::byCodeGetSetting($code);
  380. }
  381. /**
  382. *$ip string 必传
  383. *获取ip归属地
  384. *demo 四川省成都市 电信
  385. */
  386. function get_ip_city($ip)
  387. {
  388. $ch = curl_init();
  389. $url = 'https://whois.pconline.com.cn/ipJson.jsp?ip=' . $ip;
  390. //用curl发送接收数据
  391. curl_setopt($ch, CURLOPT_URL, $url);
  392. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  393. //请求为https
  394. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  395. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  396. $location = curl_exec($ch);
  397. curl_close($ch);
  398. //转码
  399. $location = mb_convert_encoding($location, 'utf-8', 'GB2312');
  400. //var_dump($location);
  401. //截取{}中的字符串
  402. $location = substr($location, strlen('({') + strpos($location, '({'), (strlen($location) - strpos($location, '})')) * (-1));
  403. //将截取的字符串$location中的‘,’替换成‘&’ 将字符串中的‘:‘替换成‘=’
  404. $location = str_replace('"', "", str_replace(":", "=", str_replace(",", "&", $location)));
  405. //php内置函数,将处理成类似于url参数的格式的字符串 转换成数组
  406. parse_str($location, $ip_location);
  407. if (isset($ip_location['addr'])) return $ip_location['addr'];
  408. return '';
  409. }
  410. /**
  411. * 异常处理
  412. * @param Exception $exception
  413. * @param $msg
  414. * @return void
  415. */
  416. function exception(\Exception $exception, $msg = '操作失败')
  417. {
  418. Log::error($exception);
  419. if (config('app.env') == 'production') abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, $msg);
  420. abort(ResponseCodeEnum::SERVICE_OPERATION_ERROR, $exception->getMessage());
  421. }
  422. /**
  423. * 解析身份证号
  424. * @param $card_id
  425. * @return array
  426. */
  427. function parse_card_id($card_id)
  428. {
  429. $sex_val = (int)substr($card_id, 16, 1);
  430. $sex = $sex_val % 2 === 0 ? 2 : 1;
  431. $bir = substr($card_id, 6, 8);
  432. $year = (int)substr($bir, 0, 4);
  433. $month = (int)substr($bir, 4, 2);
  434. $day = (int)substr($bir, 6, 2);
  435. $birthday = $year . "-" . $month . "-" . $day;
  436. $area_key = substr($card_id, 0, 6);
  437. // $address = \App\Repositories\Models\Base\Area::byCodeGetAreas($area_key);
  438. $age = \Illuminate\Support\Carbon::parse($birthday)->diffInYears();
  439. return [
  440. 'sex' => $sex,
  441. 'age' => $age,
  442. 'birthday' => $birthday,
  443. 'address' => [
  444. 'province' => substr($area_key, 0, 2) . '0000',
  445. 'city' => substr($area_key, 0, 4) . '00',
  446. 'area' => $area_key,
  447. ],
  448. ];
  449. }
  450. /**
  451. * 科学计数转数值
  452. * @param $number
  453. * @return array|mixed|string|string[]|null
  454. */
  455. function scientific_number_to_normal($number)
  456. {
  457. if (stripos($number, 'e') === false) {
  458. //判断是否为科学计数法
  459. return $number;
  460. }
  461. if (!preg_match(
  462. "/^([\\d.]+)[eE]([\\d\\-\\+]+)$/",
  463. str_replace(array(" ", ","), "", trim($number)), $matches)
  464. ) {
  465. //提取科学计数法中有效的数据,无法处理则直接返回
  466. return $number;
  467. }
  468. //对数字前后的0和点进行处理,防止数据干扰,实际上正确的科学计数法没有这个问题
  469. $data = preg_replace(array("/^[0]+/"), "", rtrim($matches[1], "0."));
  470. $length = (int)$matches[2];
  471. if ($data[0] == ".") {
  472. //由于最前面的0可能被替换掉了,这里是小数要将0补齐
  473. $data = "0{$data}";
  474. }
  475. //这里有一种特殊可能,无需处理
  476. if ($length == 0) {
  477. return $data;
  478. }
  479. //记住当前小数点的位置,用于判断左右移动
  480. $dot_position = strpos($data, ".");
  481. if ($dot_position === false) {
  482. $dot_position = strlen($data);
  483. }
  484. //正式数据处理中,是不需要点号的,最后输出时会添加上去
  485. $data = str_replace(".", "", $data);
  486. if ($length > 0) {
  487. //如果科学计数长度大于0
  488. //获取要添加0的个数,并在数据后面补充
  489. $repeat_length = $length - (strlen($data) - $dot_position);
  490. if ($repeat_length > 0) {
  491. $data .= str_repeat('0', $repeat_length);
  492. }
  493. //小数点向后移n位
  494. $dot_position += $length;
  495. $data = ltrim(substr($data, 0, $dot_position), "0") . "." . substr($data, $dot_position);
  496. } elseif ($length < 0) {
  497. //当前是一个负数
  498. //获取要重复的0的个数
  499. $repeat_length = abs($length) - $dot_position;
  500. if ($repeat_length > 0) {
  501. //这里的值可能是小于0的数,由于小数点过长
  502. $data = str_repeat('0', $repeat_length) . $data;
  503. }
  504. $dot_position += $length;//此处length为负数,直接操作
  505. if ($dot_position < 1) {
  506. //补充数据处理,如果当前位置小于0则表示无需处理,直接补小数点即可
  507. $data = ".{$data}";
  508. } else {
  509. $data = substr($data, 0, $dot_position) . "." . substr($data, $dot_position);
  510. }
  511. }
  512. if ($data[0] == ".") {
  513. //数据补0
  514. $data = "0{$data}";
  515. }
  516. return trim($data, ".");
  517. }
  518. /**
  519. * 获取设备类型
  520. * @return array|string|null
  521. */
  522. function device_type()
  523. {
  524. return strtolower(request()->header('device', 'pc'));
  525. }
  526. /**
  527. * 是否为手机端
  528. * @return bool
  529. */
  530. function is_mobile()
  531. {
  532. $type = request()->header('device', 'pc');
  533. return in_array($type, ['h5', 'weapp']);
  534. }
  535. /**
  536. * 是否为PC端
  537. * @return bool
  538. */
  539. function is_pc()
  540. {
  541. $type = request()->header('device', 'pc');
  542. return ($type === 'pc');
  543. }
  544. /**
  545. * 获取微信小程序配置
  546. *
  547. * @param array|string|null $key
  548. * @param mixed $default
  549. * @return \Illuminate\Http\Request|string|array
  550. */
  551. function wechat_mini_config($type)
  552. {
  553. $miniConfig = \App\Repositories\Models\Base\Setting::typeToWxappConfig($type);
  554. $config = [
  555. 'app_id' => $miniConfig['app_id'],
  556. 'secret' => $miniConfig['app_secret'],
  557. // 下面为可选项
  558. // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
  559. 'response_type' => 'array',
  560. 'log' => [
  561. 'level' => 'debug',
  562. 'file' => base_path('storage/logs') . '/' . $type . '/wechat-' . date('Y-m-d') . '.log',
  563. ],
  564. ];
  565. return $config;
  566. }
  567. /**
  568. * 去除符号
  569. * @param $body
  570. * @return array|string|string[]|null
  571. */
  572. function remove_symbol($body)
  573. {
  574. $char = "。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔!¡?¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐­˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼(), ,";
  575. $pattern = array(
  576. "/[[:punct:]]/i", //英文标点符号
  577. '/[' . $char . ']/u', //中文标点符号
  578. '/[ ]{2,}/'
  579. );
  580. $text = preg_replace($pattern, ' ', $body);
  581. return $text;
  582. }
  583. function word_arr2str($arr)
  584. {
  585. $str = [];
  586. foreach ($arr as $a) {
  587. $str[] = "{$a['name']}({$a['nums']})";
  588. }
  589. return arr2str($str, ',');
  590. }
  591. function post_url($url, $data)
  592. {
  593. $data = json_encode($data);
  594. $headerArray = array("Content-type:application/json;charset='utf-8'", "Accept:application/json");
  595. $curl = curl_init();
  596. curl_setopt($curl, CURLOPT_URL, $url);
  597. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  598. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
  599. curl_setopt($curl, CURLOPT_POST, 1);
  600. curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  601. curl_setopt($curl, CURLOPT_HTTPHEADER, $headerArray);
  602. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  603. $output = curl_exec($curl);
  604. curl_close($curl);
  605. return json_decode($output,true);
  606. }
  607. function log_record($name, $data)
  608. {
  609. \Illuminate\Support\Facades\Log::error("==============>{$name}<==============");
  610. \Illuminate\Support\Facades\Log::error($data);
  611. \Illuminate\Support\Facades\Log::error("<==============完结==============>");
  612. }
  613. function rk($val)
  614. {
  615. return str_replace(" ", '', $val);
  616. }
  617. /**
  618. * 手机号中间四位隐藏
  619. * @param $mobile
  620. * @return mixed
  621. * User: Mead
  622. */
  623. function mobile_hidden($mobile)
  624. {
  625. return substr_replace($mobile, '****', 3, 4);
  626. }
  627. /**
  628. * 保存网络图片
  629. * @param $url
  630. * @param $path
  631. * @param $disk
  632. * @return mixed
  633. */
  634. function saveImageFromUrl($url, $path, $disk = 'public')
  635. {
  636. $response = Http::get($url);
  637. if ($response->successful()) {
  638. $imageData = $response->body();
  639. Storage::disk($disk)->put($path, $imageData);
  640. return $path;
  641. }
  642. return $url;
  643. }