common.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. <?php
  2. // 应用公共文件
  3. use app\model\user\User;
  4. use app\services\user\UserServices;
  5. use Fastknife\Service\BlockPuzzleCaptchaService;
  6. use Fastknife\Service\ClickWordCaptchaService;
  7. use qiniu\exceptions\AuthException;
  8. use qiniu\services\CacheService;
  9. use qiniu\services\UploadService;
  10. use think\db\exception\DataNotFoundException;
  11. use think\db\exception\DbException;
  12. use think\db\exception\ModelNotFoundException;
  13. use think\exception\ValidateException;
  14. use think\facade\Config;
  15. use think\facade\Lang;
  16. use think\facade\Log;
  17. if (!function_exists('filter_str')) {
  18. /**
  19. * 过滤字符串敏感字符
  20. * @param $str
  21. * @return array|mixed|string|string[]|null
  22. * @throws Exception
  23. */
  24. function filter_str($str)
  25. {
  26. $param_filter_data = sys_config('param_filter_data');
  27. $param_filter_type = sys_config('param_filter_type', 3);
  28. $rules = preg_split('/\r\n|\r|\n/', base64_decode($param_filter_data));
  29. if ($param_filter_data) {
  30. switch ($param_filter_type) {
  31. case 1://防火墙关闭
  32. return $str;
  33. case 2://报错
  34. foreach ($rules as $rule) {
  35. if (preg_match($rule, $str)) {
  36. throw new \Exception('您的参数存在非要请求,已被拦截');
  37. }
  38. }
  39. break;
  40. case 3://过滤
  41. if (filter_var($str, FILTER_VALIDATE_URL)) {
  42. $url = parse_url($str);
  43. if (!isset($url['scheme'])) return $str;
  44. $host = $url['scheme'] . '://' . $url['host'];
  45. $str = $host . preg_replace($rules, '', str_replace($host, '', $str));
  46. } else {
  47. $str = preg_replace($rules, '', $str);
  48. }
  49. return $str;
  50. }
  51. }
  52. return $str;
  53. }
  54. }
  55. if (!function_exists('response_log_write')) {
  56. /**
  57. * 日志写入
  58. * @param array $data
  59. * @param string $type
  60. */
  61. function response_log_write(array $data, string $type = \think\Log::ERROR)
  62. {
  63. try {
  64. $id = 0;
  65. foreach (['adminId', 'kefuId', 'uid', 'supplierId'] as $value) {
  66. if (method_exists(request(), $value)) {
  67. $id = request()->{$value}();
  68. }
  69. }
  70. //日志内容
  71. $log = [
  72. $id, //管理员ID
  73. request()->ip(), //客户ip
  74. ceil(microtime() - (request()->time(true) * 1000)), //耗时(毫秒)
  75. request()->method(true), //请求类型
  76. str_replace("/", "", request()->rootUrl()), //应用
  77. request()->baseUrl(), //路由
  78. json_encode(request()->param(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),//请求参数
  79. json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), //报错数据
  80. ];
  81. Log::write(implode("|", $log), $type);
  82. } catch (\Throwable $e) {
  83. }
  84. }
  85. }
  86. if (!function_exists('not_empty_check')) {
  87. /**
  88. * 非空验证
  89. * @param $param
  90. * @return bool
  91. */
  92. function not_empty_check($param)
  93. {
  94. if (is_array($param)) {
  95. return !(count($param) <= 0);
  96. } else {
  97. if ($param == '') {
  98. return false;
  99. }
  100. if ($param == null) {
  101. return false;
  102. }
  103. return true;
  104. }
  105. }
  106. }
  107. if (!function_exists('do_request')) {
  108. /**
  109. * CURL 请求接口
  110. * @param string $url 请求地址
  111. * @param array $data 请求参数
  112. * @param array $header 请求头
  113. * @param bool $post true:post请求 false:get请求
  114. * @param bool $json post请求时 请求数据打包方式是否为json
  115. * @param int $format 数据打包为json格式时打包的格式值 来自json_encode
  116. * @param bool $form post请求时 请求数据是否为表单 同时为false时为http提交 优先级高于json
  117. * @return bool|false|string
  118. */
  119. function do_request($url, $query, $data, $header = null, $post = true, $json = false, $format = 0, $form = false)
  120. {
  121. $curl = curl_init();
  122. $url .= ('?' . http_build_query($query));
  123. curl_setopt($curl, CURLOPT_URL, $url);
  124. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  125. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  126. if ($post) {
  127. curl_setopt($curl, CURLOPT_POST, 1);
  128. if (!$json && !$form) {
  129. curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
  130. } else if ($json && !$form) {
  131. curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data, $format));
  132. } else {
  133. curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  134. }
  135. }
  136. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  137. if ($header) {
  138. curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
  139. curl_setopt($curl, CURLOPT_HEADER, 0);
  140. }
  141. $result = curl_exec($curl);
  142. if (curl_errno($curl)) {
  143. return json_encode(['status' => curl_errno($curl), 'msg' => '请求失败']);
  144. }
  145. curl_close($curl);
  146. return $result;
  147. }
  148. }
  149. if (!function_exists('path_to_url')) {
  150. /**
  151. * 路径转url路径
  152. * @param $path
  153. * @return string
  154. */
  155. function path_to_url($path)
  156. {
  157. return trim(str_replace(DS, '/', $path), '.');
  158. }
  159. }
  160. if (!function_exists('get_group_user')) {
  161. //所有下级
  162. function get_group_user($id, $init = true, $members = null)
  163. {
  164. if ($init) {
  165. $us = User::column('spread_uid', 'uid');
  166. $members = [];
  167. foreach ($us as $k => $v) {
  168. if ($v > 0)
  169. $members[$v][] = $k;
  170. }
  171. $id = [$id];
  172. }
  173. $arr = array();
  174. foreach ($id as $v) {
  175. $child = $members[$v] ?? [];
  176. $arr = array_merge($arr, $child);
  177. }
  178. if (count($arr)) {
  179. return array_merge($arr, get_group_user($arr, false, $members));
  180. } else {
  181. return $arr;
  182. }
  183. }
  184. }
  185. if (!function_exists('sys_config')) {
  186. /**
  187. * 获取系统单个配置
  188. * @param string $name
  189. * @param mixed $default
  190. * @param bool $cache
  191. * @return string|array
  192. */
  193. function sys_config(string $name, $default = '', bool $cache = false)
  194. {
  195. if (empty($name))
  196. return $default;
  197. $config = app('sysConfig')->get($name, $default, $cache);
  198. if (is_string($config)) $config = trim($config);
  199. if ($config === '' || $config === false) {
  200. return $default;
  201. } else {
  202. return $config;
  203. }
  204. }
  205. }
  206. if (!function_exists('store_config')) {
  207. /**
  208. * 获取系统单个配置
  209. * @param string $name
  210. * @param int $store_id
  211. * @param mixed $default
  212. * @param bool $cache
  213. * @return string
  214. */
  215. function store_config(string $name, int $store_id, $default = '', bool $cache = false)
  216. {
  217. if (empty($name))
  218. return $default;
  219. $config = app('sysConfig')->setStore($store_id)->get($name, $default, $cache);
  220. if (is_string($config)) $config = trim($config);
  221. if ($config === '' || $config === false) {
  222. return $default;
  223. } else {
  224. return $config;
  225. }
  226. }
  227. }
  228. if (!function_exists('check_phone')) {
  229. /**
  230. * 手机号验证
  231. * @param $phone
  232. * @return false|int
  233. */
  234. function check_phone($phone)
  235. {
  236. return preg_match("/^1[3456789]\d{9}$/", $phone);
  237. }
  238. }
  239. if (!function_exists('check_mail')) {
  240. /**
  241. * 邮箱验证
  242. * @param $mail
  243. * @return false|int
  244. */
  245. function check_mail($mail)
  246. {
  247. if (filter_var($mail, FILTER_VALIDATE_EMAIL)) {
  248. return true;
  249. } else {
  250. return false;
  251. }
  252. }
  253. }
  254. if (!function_exists('aj_captcha_check_one')) {
  255. /**
  256. * 验证滑块1次验证
  257. * @param string $token
  258. * @param string $pointJson
  259. * @return bool
  260. */
  261. function aj_captcha_check_one(string $captchaType, string $token, string $pointJson)
  262. {
  263. aj_get_serevice($captchaType)->check($token, $pointJson);
  264. return true;
  265. }
  266. }
  267. if (!function_exists('aj_captcha_check_two')) {
  268. /**
  269. * 验证滑块2次验证
  270. * @param string $token
  271. * @param string $pointJson
  272. * @return bool
  273. */
  274. function aj_captcha_check_two(string $captchaType, string $captchaVerification)
  275. {
  276. aj_get_serevice($captchaType)->verificationByEncryptCode($captchaVerification);
  277. return true;
  278. }
  279. }
  280. if (!function_exists('aj_captcha_create')) {
  281. /**
  282. * 创建验证码
  283. * @return array
  284. */
  285. function aj_captcha_create(string $captchaType)
  286. {
  287. return aj_get_serevice($captchaType)->get();
  288. }
  289. }
  290. if (!function_exists('aj_get_serevice')) {
  291. /**
  292. * @param string $captchaType
  293. * @return ClickWordCaptchaService|BlockPuzzleCaptchaService
  294. */
  295. function aj_get_serevice(string $captchaType)
  296. {
  297. $config = \think\facade\Config::get('ajcaptcha');
  298. switch ($captchaType) {
  299. case "clickWord":
  300. $service = new ClickWordCaptchaService($config);
  301. break;
  302. case "blockPuzzle":
  303. $service = new BlockPuzzleCaptchaService($config);
  304. break;
  305. default:
  306. throw new ValidateException('captchaType参数不正确!');
  307. }
  308. return $service;
  309. }
  310. }
  311. if (!function_exists('sort_list_tier')) {
  312. /**
  313. * 分级排序
  314. * @param $data
  315. * @param int $pid
  316. * @param string $field
  317. * @param string $pk
  318. * @param string $html
  319. * @param int $level
  320. * @param bool $clear
  321. * @return array
  322. */
  323. function sort_list_tier($data, $pid = 0, $field = 'pid', $pk = 'id', $html = '|-----', $level = 1, $clear = true)
  324. {
  325. static $list = [];
  326. if ($clear) $list = [];
  327. foreach ($data as $k => $res) {
  328. if ($res[$field] == $pid) {
  329. $res['html'] = str_repeat($html, $level);
  330. $list[] = $res;
  331. unset($data[$k]);
  332. sort_list_tier($data, $res[$pk], $field, $pk, $html, $level + 1, false);
  333. }
  334. }
  335. return $list;
  336. }
  337. }
  338. if (!function_exists('get_tree_children')) {
  339. /**
  340. * 获取树状结构子集
  341. */
  342. function get_tree_children($data, $id = 0, $field = 'id', $pid = 'pid', $init = true)
  343. {
  344. static $children;
  345. if ($init) {
  346. $children = [];
  347. foreach ($data as $v) {
  348. $children[$v[$pid]][] = $v;
  349. }
  350. }
  351. $arr = ($children[$id] ?? []);
  352. foreach ($arr as &$v) {
  353. $v['children'] = get_tree_children($data, $v[$field], $field, $pid, false);
  354. }
  355. return $arr;
  356. }
  357. }
  358. if (!function_exists('set_file_url')) {
  359. /**
  360. * @param $file
  361. * @return mixed|string
  362. */
  363. function set_file_url($file)
  364. {
  365. if (!is_array($file)) {
  366. $file = [$file];
  367. }
  368. foreach ($file as &$v) {
  369. if (strpos($v, '://') === false) {
  370. $v = rtrim(sys_config('site_url', ''), '/') . '/' . ltrim($v, '/');
  371. }
  372. }
  373. return $file;
  374. }
  375. }
  376. if (!function_exists('check_link')) {
  377. /**
  378. * @param $file
  379. * @return mixed|string
  380. */
  381. function check_link($url)
  382. {
  383. $ch = curl_init();
  384. try {
  385. curl_setopt($ch, CURLOPT_URL, $url);
  386. curl_setopt($ch, CURLOPT_HEADER, 1);
  387. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  388. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
  389. $contents = curl_exec($ch);
  390. if (preg_match("/404/", $contents)) return false;
  391. if (preg_match("/403/", $contents)) return false;
  392. return true;
  393. } catch (\Exception $e) {
  394. return false;
  395. }
  396. }
  397. }
  398. if (!function_exists('filter_emoji')) {
  399. // 过滤掉emoji表情
  400. function filter_emoji($str)
  401. {
  402. return preg_replace_callback( //执行一个正则表达式搜索并且使用一个回调进行替换
  403. '/./u',
  404. function (array $match) {
  405. return strlen($match[0]) >= 4 ? '' : $match[0];
  406. },
  407. $str);
  408. }
  409. }
  410. if (!function_exists('getFileHeaders')) {
  411. /**
  412. * 获取文件大小头部信息
  413. * @param string $url
  414. * @param $isData
  415. * @return array
  416. */
  417. function getFileHeaders(string $url, $isData = true)
  418. {
  419. stream_context_set_default(['ssl' => ['verify_peer' => false, 'verify_peer_name' => false]]);
  420. $header['size'] = 0;
  421. $header['type'] = 'image/jpeg';
  422. if (!$isData) {
  423. return $header;
  424. }
  425. try {
  426. $headerArray = get_headers(str_replace('\\', '/', $url), true);
  427. if (!isset($headerArray['Content-Length'])) {
  428. $header['size'] = 0;
  429. } else {
  430. if (is_array($headerArray['Content-Length']) && count($headerArray['Content-Length']) == 2) {
  431. $header['size'] = $headerArray['Content-Length'][1];
  432. } else {
  433. $header['size'] = $headerArray['Content-Length'] ?? 0;
  434. }
  435. }
  436. if (!isset($headerArray['Content-Type'])) {
  437. $header['type'] = 'image/jpeg';
  438. } else {
  439. if (is_array($headerArray['Content-Type']) && count($headerArray['Content-Type']) == 2) {
  440. $header['type'] = $headerArray['Content-Type'][1];
  441. } else {
  442. $header['type'] = $headerArray['Content-Type'] ?? 'image/jpeg';
  443. }
  444. }
  445. } catch (\Exception $e) {
  446. }
  447. return $header;
  448. }
  449. }
  450. if (!function_exists('formatFileSize')) {
  451. /**
  452. * 格式化文件大小
  453. * @param $size
  454. * @return mixed|string|null
  455. */
  456. function formatFileSize($size)
  457. {
  458. if (!$size) {
  459. return '0KB';
  460. }
  461. try {
  462. $toKb = 1024;
  463. $toMb = $toKb * 1024;
  464. $toGb = $toMb * 1024;
  465. if ($size >= $toGb) {
  466. return round($size / $toGb, 2) . 'GB';
  467. } elseif ($size >= $toMb) {
  468. return round($size / $toMb, 2) . 'MB';
  469. } elseif ($size >= $toKb) {
  470. return round($size / $toKb, 2) . 'KB';
  471. } else {
  472. return $size . 'B';
  473. }
  474. } catch (Exception $e) {
  475. return '0KB';
  476. }
  477. }
  478. }
  479. if (!function_exists('get_image_thumb')) {
  480. /**
  481. * 获取缩略图
  482. * @param $filePath
  483. * @param string $type all|big|mid|small
  484. * @param bool $is_remote_down
  485. * @return mixed|string|string[]
  486. */
  487. function get_image_thumb($filePath, string $type = 'all', bool $is_remote_down = false)
  488. {
  489. if (!$filePath || !is_string($filePath) || strpos($filePath, '?') !== false) return $filePath;
  490. try {
  491. $arr = explode('.', $filePath);
  492. $ext_name = trim($arr[count($arr) - 1]);
  493. if (!in_array($ext_name, ['png', 'jpg', 'jpeg'])) {
  494. return $filePath;
  495. }
  496. $upload = UploadService::getOssInit($filePath, $is_remote_down);
  497. $data = $upload->thumb('', $type);
  498. $image = $type == 'all' ? $data : $data[$type] ?? $filePath;
  499. } catch (\Throwable $e) {
  500. $image = $filePath;
  501. // throw new ValidateException($e->getMessage());
  502. Log::error('获取缩略图失败,原因:' . $e->getMessage() . '----' . $e->getFile() . '----' . $e->getLine() . '----' . $filePath);
  503. }
  504. $data = parse_url($image);
  505. if (!isset($data['host']) && (substr($image, 0, 2) == './' || substr($image, 0, 1) == '/')) {//不是完整地址
  506. $image = sys_config('site_url') . $image;
  507. }
  508. //请求是https 图片是http 需要改变图片地址
  509. if (strpos(request()->domain(), 'https:') !== false && strpos($image, 'https:') === false) {
  510. $image = str_replace('http:', 'https:', $image);
  511. }
  512. return $image;
  513. }
  514. }
  515. if (!function_exists('get_thumb_water')) {
  516. /**
  517. * 处理数组获取缩略图、水印
  518. * @param $list
  519. * @param string $type
  520. * @param array|string[] $field 1、['image','images'] type 取值参数:type 2、['small'=>'image','mid'=>'images'] type 取field数组的key
  521. * @param bool $is_remote_down
  522. * @return array|mixed|string|string[]
  523. */
  524. function get_thumb_water($list, string $type = 'small', array $field = ['image'], bool $is_remote_down = false)
  525. {
  526. if (!$list || !$field) return $list;
  527. $baseType = $type;
  528. $data = $list;
  529. if (is_string($list)) {
  530. $field = [$type => 'image'];
  531. $data = ['image' => $list];
  532. }
  533. if (is_array($data)) {
  534. foreach ($field as $type => $key) {
  535. if (is_integer($type)) {//索引数组,默认type
  536. $type = $baseType;
  537. }
  538. //一维数组
  539. if (isset($data[$key])) {
  540. if (is_array($data[$key])) {
  541. $path_data = [];
  542. foreach ($data[$key] as $k => $path) {
  543. $path_data[] = get_image_thumb($path, $type, $is_remote_down);
  544. }
  545. $data[$key] = $path_data;
  546. } else {
  547. $data[$key] = get_image_thumb($data[$key], $type, $is_remote_down);
  548. }
  549. } else {
  550. foreach ($data as &$item) {
  551. if (!isset($item[$key]))
  552. continue;
  553. if (is_array($item[$key])) {
  554. $path_data = [];
  555. foreach ($item[$key] as $k => $path) {
  556. $path_data[] = get_image_thumb($path, $type, $is_remote_down);
  557. }
  558. $item[$key] = $path_data;
  559. } else {
  560. $item[$key] = get_image_thumb($item[$key], $type, $is_remote_down);
  561. }
  562. }
  563. }
  564. }
  565. }
  566. return is_string($list) ? ($data['image'] ?? '') : $data;
  567. }
  568. }
  569. if (!function_exists('make_path')) {
  570. /**
  571. * 上传路径转化,默认路径
  572. * @param $path
  573. * @param int $type
  574. * @param bool $force
  575. * @return string
  576. * @throws Exception
  577. */
  578. function make_path($path, int $type = 2, bool $force = false)
  579. {
  580. $path = DS . ltrim(rtrim($path));
  581. switch ($type) {
  582. case 1:
  583. $path .= DS . date('Y');
  584. break;
  585. case 2:
  586. $path .= DS . date('Y') . DS . date('m');
  587. break;
  588. case 3:
  589. $path .= DS . date('Y') . DS . date('m') . DS . date('d');
  590. break;
  591. }
  592. try {
  593. if (is_dir(app()->getRootPath() . 'public' . DS . 'uploads' . $path) == true || mkdir(app()->getRootPath() . 'public' . DS . 'uploads' . $path, 0777, true) == true) {
  594. return trim(str_replace(DS, '/', $path), '.');
  595. } else return '';
  596. } catch (Exception $e) {
  597. if ($force)
  598. throw new Exception($e->getMessage());
  599. return '无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS;
  600. }
  601. }
  602. }
  603. if (!function_exists('verify_domain')) {
  604. /**
  605. * @param $url
  606. * @return false|string
  607. */
  608. function verify_domain($url)
  609. {
  610. if (!$url) return false;
  611. if (strpos($url, 'http') === false) return false;
  612. return rtrim($url, '/');
  613. }
  614. }
  615. if (!function_exists('password')) {
  616. /**
  617. * @param $string
  618. * @param null $salt
  619. * @return array
  620. * @throws Exception
  621. */
  622. function password($string, $salt = null)
  623. {
  624. if (!$salt)
  625. $salt = bin2hex(random_bytes(6));
  626. return [md5(md5($string) . $salt), $salt];
  627. }
  628. }
  629. if (!function_exists('parseName')) {
  630. /**
  631. * 字符串命名风格转换
  632. * type 0 将 Java 风格转换为 C 的风格 1 将 C 风格转换为 Java 的风格
  633. * @access public
  634. * @param string $name 字符串
  635. * @param integer $type 转换类型
  636. * @param bool $ucfirst 首字母是否大写(驼峰规则)
  637. * @return string
  638. */
  639. function parseName($name, $type = 0, $ucfirst = true)
  640. {
  641. if ($type) {
  642. $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
  643. return strtoupper($match[1]);
  644. }, $name ?? '');
  645. return $ucfirst ? ucfirst($name) : lcfirst($name);
  646. }
  647. return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
  648. }
  649. }
  650. if (!function_exists('check_card')) {
  651. function check_card($idCard)
  652. {
  653. // 去除空格
  654. $idCard = trim($idCard);
  655. // 18位身份证号码正则表达式
  656. $pattern = '/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$/';
  657. if (!preg_match($pattern, $idCard)) {
  658. return false;
  659. }
  660. // 校验码验证
  661. $weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  662. $checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
  663. $sum = 0;
  664. for ($i = 0; $i < 17; $i++) {
  665. $sum += intval($idCard[$i]) * $weights[$i];
  666. }
  667. $checkCodeIndex = $sum % 11;
  668. $expectedCheckCode = $checkCodes[$checkCodeIndex];
  669. return strtoupper($idCard[17]) === $expectedCheckCode;
  670. }
  671. }
  672. if (!function_exists('check_password')) {
  673. function check_password($value)
  674. {
  675. // 正则表达式:至少6位,最多18位,包含大小写字母、数字和特殊字符
  676. $pattern = '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{6,18}$/';
  677. return preg_match($pattern, $value) === 1;
  678. }
  679. }
  680. if (!function_exists('check_trade_password')) {
  681. function check_trade_password($value)
  682. {
  683. return preg_match('/^\d{6}$/', $value) === 1;
  684. }
  685. }
  686. if (!function_exists('check_sms_captcha')) {
  687. function check_sms_captcha($phone, $type, $code)
  688. {
  689. if (!check_phone($phone)) throw new AuthException('手机号码格式错误');
  690. $verifyCode = CacheService::get('code_' . $phone . '_' . $type);
  691. if (!$verifyCode)
  692. throw new AuthException('请先获取验证码');
  693. $verifyError = (int)CacheService::get('code_error_' . $phone . '_' . $type, 0);
  694. if ($verifyError >= 10) {
  695. throw new AuthException('错误次数过多,请稍后再试');
  696. }
  697. $verifyCode = substr($verifyCode, 0, 6);
  698. if ($verifyCode != $code) {
  699. CacheService::set('code_error_' . $phone . '_' . $type, $verifyError + 1, 180);
  700. throw new AuthException('验证码错误');
  701. }
  702. CacheService::delete('code_' . $phone . '_' . $type);
  703. CacheService::delete('code_error_' . $phone . '_' . $type);
  704. }
  705. }
  706. if (!function_exists('random_string')) {
  707. function random_string($length)
  708. {
  709. mt_rand();
  710. $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  711. $randomString = '';
  712. for ($i = 0; $i < $length; $i++) {
  713. $index = rand(0, strlen($characters) - 1);
  714. $randomString .= $characters[$index];
  715. }
  716. return $randomString;
  717. }
  718. }
  719. if (!function_exists('create_account')) {
  720. function create_account()
  721. {
  722. do {
  723. $randomString = 'qn_' . random_string(16) . '_' . random_string(4);
  724. } while (User::where('account', $randomString)->find());
  725. return $randomString;
  726. }
  727. }
  728. if (!function_exists('curl_file_exist')) {
  729. function curl_file_exist($url)
  730. {
  731. $ch = curl_init($url);
  732. curl_setopt($ch, CURLOPT_NOBODY, true); // 不需要返回体
  733. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向
  734. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回结果而不是直接输出
  735. curl_exec($ch);
  736. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  737. curl_close($ch);
  738. return $httpCode == 200;
  739. }
  740. }
  741. if (!function_exists('checkCoordinates')) {
  742. /**
  743. * 检测经纬度数据
  744. * @param $longitude
  745. * @param $latitude
  746. * @return bool
  747. */
  748. function checkCoordinates($longitude, $latitude)
  749. {
  750. if ($longitude) {
  751. $longitudePattern = '/^(-?\d{1,3}(?:\.\d+)?)$/'; // 经度,允许1到3位整数,后面跟着小数
  752. if (!preg_match($longitudePattern, $longitude)) {
  753. return false; // 经度格式不正确
  754. }
  755. // 检查经纬度是否在有效范围内
  756. if (($longitude < -180) || ($longitude > 180)) {
  757. return false; // 经度超出范围
  758. }
  759. }
  760. if ($latitude) {
  761. $latitudePattern = '/^[-+]?([0-8]?\d(\.\d+)?|90(\.0+)?)$/'; // 纬度,允许-90到90,包括小数部分
  762. if (!preg_match($latitudePattern, $latitude)) {
  763. return false; // 纬度格式不正确
  764. }
  765. if (($latitude < -90) || ($latitude > 90)) {
  766. return false; // 纬度超出范围
  767. }
  768. }
  769. // 如果所有检查都通过,则返回true
  770. return true;
  771. }
  772. }
  773. if (!function_exists('trade_password')) {
  774. /**
  775. * 交易密码验证
  776. * @param $password
  777. * @param $uid
  778. * @return void
  779. * @throws DataNotFoundException
  780. * @throws DbException
  781. * @throws ModelNotFoundException
  782. */
  783. function trade_password($password, $uid)
  784. {
  785. if (!$password) {
  786. throw new ValidateException('请输入交易密码');
  787. }
  788. /** @var UserServices $userService */
  789. $userService = app()->make(UserServices::class);
  790. $user = $userService->getUserInfo($uid);
  791. if (!$user['trade_pwd']) {
  792. throw new ValidateException('请先设置交易密码');
  793. }
  794. if (password($password, $user['trade_salt'])[0] != $user['trade_pwd']) {
  795. throw new ValidateException('交易密码错误');
  796. }
  797. }
  798. }
  799. if (!function_exists('get_token_info')) {
  800. /**
  801. * 获取token信息
  802. * @param $token
  803. * @param string $field
  804. * @param mixed $default
  805. * @param string $chain
  806. * @return mixed|string
  807. */
  808. function get_token_info($token, string $field = '', $default = '', string $chain = 'bsc')
  809. {
  810. $token = strtolower($token);
  811. $key = 'blockchain.' . $chain . '.tokens.' . $token;
  812. $value = Config::get($key);
  813. if ($field) return $value[$field] ?? $default;
  814. return $value ?? $default;
  815. }
  816. }
  817. if (!function_exists('msg')) {
  818. function msg($name, $vars = [], $lang = '')
  819. {
  820. if (is_numeric($name) || !$name) {
  821. return $name;
  822. }
  823. if (!is_array($vars)) {
  824. $vars = func_get_args();
  825. array_shift($vars);
  826. $lang = '';
  827. }
  828. return Lang::get($name, $vars, $lang);
  829. }
  830. }