common.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. <?php
  2. use crmeb\services\UploadService;
  3. use Fastknife\Service\BlockPuzzleCaptchaService;
  4. use Fastknife\Service\ClickWordCaptchaService;
  5. use crmeb\services\SystemConfigService;
  6. use think\exception\ValidateException;
  7. use think\facade\Config;
  8. use think\facade\Log;
  9. if (!function_exists('get_tree_value')) {
  10. /**
  11. * 获取
  12. * @param array $data
  13. * @param int|string $value
  14. * @return array
  15. */
  16. function get_tree_value(array $data, $value, array &$childrenValue = [])
  17. {
  18. foreach ($data as &$item) {
  19. if ($item['value'] == $value) {
  20. $childrenValue[] = $item['value'];
  21. if ($item['pid']) {
  22. $value = $item['pid'];
  23. unset($item);
  24. return get_tree_value($data, $value, $childrenValue);
  25. }
  26. }
  27. }
  28. return $childrenValue;
  29. }
  30. }
  31. if (!function_exists('is_brokerage_statu')) {
  32. /**
  33. * 是否能成为推广人
  34. * @param float $price
  35. * @return bool
  36. */
  37. function is_brokerage_statu(float $price)
  38. {
  39. if (!sys_config('brokerage_func_status')) {
  40. return false;
  41. }
  42. $storeBrokerageStatus = sys_config('store_brokerage_statu', 1);
  43. if ($storeBrokerageStatus == 1) {
  44. return false;
  45. } else if ($storeBrokerageStatus == 2) {
  46. return false;
  47. } else {
  48. $storeBrokeragePrice = sys_config('store_brokerage_price', 0);
  49. return $price >= $storeBrokeragePrice;
  50. }
  51. }
  52. }
  53. if (!function_exists('time_tran')) {
  54. /**
  55. * 时间戳人性化转化
  56. * @param $time
  57. * @return string
  58. */
  59. function time_tran($time)
  60. {
  61. $t = time() - $time;
  62. $f = array(
  63. '31536000' => '年',
  64. '2592000' => '个月',
  65. '604800' => '星期',
  66. '86400' => '天',
  67. '3600' => '小时',
  68. '60' => '分钟',
  69. '1' => '秒'
  70. );
  71. foreach ($f as $k => $v) {
  72. if (0 != $c = floor($t / (int)$k)) {
  73. return $c . $v . '前';
  74. }
  75. }
  76. }
  77. }
  78. if (!function_exists('url_to_path')) {
  79. /**
  80. * url转换路径
  81. * @param $url
  82. * @return string
  83. */
  84. function url_to_path($url)
  85. {
  86. $path = trim(str_replace('/', DS, $url), DS);
  87. if (0 !== strripos($path, 'public'))
  88. $path = 'public' . DS . $path;
  89. return app()->getRootPath() . $path;
  90. }
  91. }
  92. if (!function_exists('path_to_url')) {
  93. /**
  94. * 路径转url路径
  95. * @param $path
  96. * @return string
  97. */
  98. function path_to_url($path)
  99. {
  100. return trim(str_replace(DS, '/', $path), '.');
  101. }
  102. }
  103. if (!function_exists('get_image_thumb')) {
  104. /**
  105. * 获取缩略图
  106. * @param $filePath
  107. * @param string $type all|big|mid|small
  108. * @param bool $is_remote_down
  109. * @return mixed|string|string[]
  110. */
  111. function get_image_thumb($filePath, string $type = 'all', bool $is_remote_down = false)
  112. {
  113. if (!$filePath || !is_string($filePath) || strpos($filePath, '?') !== false) return $filePath;
  114. try {
  115. $arr = explode('.', $filePath);
  116. $ext_name = trim($arr[count($arr) - 1]);
  117. if (!in_array($ext_name, ['png', 'jpg', 'jpeg'])) {
  118. return $filePath;
  119. }
  120. $upload = UploadService::getOssInit($filePath, $is_remote_down);
  121. $data = $upload->thumb('', $type);
  122. $image = $type == 'all' ? $data : $data[$type] ?? $filePath;
  123. } catch (\Throwable $e) {
  124. $image = $filePath;
  125. // throw new ValidateException($e->getMessage());
  126. \think\facade\Log::error('获取缩略图失败,原因:' . $e->getMessage() . '----' . $e->getFile() . '----' . $e->getLine() . '----' . $filePath);
  127. }
  128. $data = parse_url($image);
  129. if (!isset($data['host']) && (substr($image, 0, 2) == './' || substr($image, 0, 1) == '/')) {//不是完整地址
  130. $image = sys_config('site_url') . $image;
  131. }
  132. //请求是https 图片是http 需要改变图片地址
  133. if (strpos(request()->domain(), 'https:') !== false && strpos($image, 'https:') === false) {
  134. $image = str_replace('http:', 'https:', $image);
  135. }
  136. return $image;
  137. }
  138. }
  139. if (!function_exists('get_thumb_water')) {
  140. /**
  141. * 处理数组获取缩略图、水印
  142. * @param $list
  143. * @param string $type
  144. * @param array|string[] $field 1、['image','images'] type 取值参数:type 2、['small'=>'image','mid'=>'images'] type 取field数组的key
  145. * @param bool $is_remote_down
  146. * @return array|mixed|string|string[]
  147. */
  148. function get_thumb_water($list, string $type = 'small', array $field = ['image'], bool $is_remote_down = false)
  149. {
  150. if (!$list || !$field) return $list;
  151. $baseType = $type;
  152. $data = $list;
  153. if (is_string($list)) {
  154. $field = [$type => 'image'];
  155. $data = ['image' => $list];
  156. }
  157. if (is_array($data)) {
  158. foreach ($field as $type => $key) {
  159. if (is_integer($type)) {//索引数组,默认type
  160. $type = $baseType;
  161. }
  162. //一维数组
  163. if (isset($data[$key])) {
  164. if (is_array($data[$key])) {
  165. $path_data = [];
  166. foreach ($data[$key] as $k => $path) {
  167. $path_data[] = get_image_thumb($path, $type, $is_remote_down);
  168. }
  169. $data[$key] = $path_data;
  170. } else {
  171. $data[$key] = get_image_thumb($data[$key], $type, $is_remote_down);
  172. }
  173. } else {
  174. foreach ($data as &$item) {
  175. if (!isset($item[$key]))
  176. continue;
  177. if (is_array($item[$key])) {
  178. $path_data = [];
  179. foreach ($item[$key] as $k => $path) {
  180. $path_data[] = get_image_thumb($path, $type, $is_remote_down);
  181. }
  182. $item[$key] = $path_data;
  183. } else {
  184. $item[$key] = get_image_thumb($item[$key], $type, $is_remote_down);
  185. }
  186. }
  187. }
  188. }
  189. }
  190. return is_string($list) ? ($data['image'] ?? '') : $data;
  191. }
  192. }
  193. if (!function_exists('put_image')) {
  194. /**
  195. * 获取图片转为base64
  196. * @param string $avatar
  197. * @return bool|string
  198. */
  199. function put_image($url, $filename = '')
  200. {
  201. if ($url == '') {
  202. return false;
  203. }
  204. try {
  205. if ($filename == '') {
  206. $ext = pathinfo($url);
  207. if ($ext['extension'] != "jpg" && $ext['extension'] != "png" && $ext['extension'] != "jpeg") {
  208. return false;
  209. }
  210. $filename = time() . "." . $ext['extension'];
  211. }
  212. $pathArr = parse_url($url);
  213. $path = $pathArr['path'] ?? '';
  214. if ($path && file_exists(public_path() . trim($path, '/'))) {
  215. return $path;
  216. } else {
  217. //文件保存路径
  218. ob_start();
  219. $url = str_replace('phar://', '', $url);
  220. readfile($url);
  221. $img = ob_get_contents();
  222. ob_end_clean();
  223. $path = 'uploads/qrcode';
  224. $fp2 = fopen(public_path() . $path . '/' . $filename, 'a');
  225. fwrite($fp2, $img);
  226. fclose($fp2);
  227. return $path . '/' . $filename;
  228. }
  229. } catch (\Exception $e) {
  230. return false;
  231. }
  232. }
  233. }
  234. if (!function_exists('make_path')) {
  235. /**
  236. * 上传路径转化,默认路径
  237. * @param $path
  238. * @param int $type
  239. * @param bool $force
  240. * @return string
  241. */
  242. function make_path($path, int $type = 2, bool $force = false)
  243. {
  244. $path = DS . ltrim(rtrim($path));
  245. switch ($type) {
  246. case 1:
  247. $path .= DS . date('Y');
  248. break;
  249. case 2:
  250. $path .= DS . date('Y') . DS . date('m');
  251. break;
  252. case 3:
  253. $path .= DS . date('Y') . DS . date('m') . DS . date('d');
  254. break;
  255. }
  256. try {
  257. if (is_dir(app()->getRootPath() . 'public' . DS . 'uploads' . $path) == true || mkdir(app()->getRootPath() . 'public' . DS . 'uploads' . $path, 0777, true) == true) {
  258. return trim(str_replace(DS, '/', $path), '.');
  259. } else return '';
  260. } catch (\Exception $e) {
  261. if ($force)
  262. throw new \Exception($e->getMessage());
  263. return '无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS;
  264. }
  265. }
  266. }
  267. if (!function_exists('check_phone')) {
  268. /**
  269. * 手机号验证
  270. * @param $phone
  271. * @return false|int
  272. */
  273. function check_phone($phone)
  274. {
  275. return preg_match("/^1[3456789]\d{9}$/", $phone);
  276. }
  277. }
  278. if (!function_exists('check_mail')) {
  279. /**
  280. * 邮箱验证
  281. * @param $mail
  282. * @return false|int
  283. */
  284. function check_mail($mail)
  285. {
  286. if (filter_var($mail, FILTER_VALIDATE_EMAIL)) {
  287. return true;
  288. } else {
  289. return false;
  290. }
  291. }
  292. }
  293. if (!function_exists('aj_captcha_check_one')) {
  294. /**
  295. * 验证滑块1次验证
  296. * @param string $token
  297. * @param string $pointJson
  298. * @return bool
  299. */
  300. function aj_captcha_check_one(string $captchaType, string $token, string $pointJson)
  301. {
  302. aj_get_serevice($captchaType)->check($token, $pointJson);
  303. return true;
  304. }
  305. }
  306. if (!function_exists('aj_captcha_check_two')) {
  307. /**
  308. * 验证滑块2次验证
  309. * @param string $token
  310. * @param string $pointJson
  311. * @return bool
  312. */
  313. function aj_captcha_check_two(string $captchaType, string $captchaVerification )
  314. {
  315. aj_get_serevice($captchaType)->verificationByEncryptCode($captchaVerification);
  316. return true;
  317. }
  318. }
  319. if (!function_exists('aj_captcha_create')) {
  320. /**
  321. * 创建验证码
  322. * @return array
  323. */
  324. function aj_captcha_create(string $captchaType)
  325. {
  326. return aj_get_serevice($captchaType)->get();
  327. }
  328. }
  329. if (!function_exists('aj_get_serevice')) {
  330. /**
  331. * @param string $captchaType
  332. * @return ClickWordCaptchaService|BlockPuzzleCaptchaService
  333. */
  334. function aj_get_serevice(string $captchaType)
  335. {
  336. $config = Config::get('ajcaptcha');
  337. switch ($captchaType) {
  338. case "clickWord":
  339. $service = new ClickWordCaptchaService($config);
  340. break;
  341. case "blockPuzzle":
  342. $service = new BlockPuzzleCaptchaService($config);
  343. break;
  344. default:
  345. throw new ValidateException('captchaType参数不正确!');
  346. }
  347. return $service;
  348. }
  349. }
  350. if (!function_exists('mb_substr_str')) {
  351. /**
  352. * 截取制定长度,并使用填充
  353. * @param string $value
  354. * @param int $length
  355. * @param string $str
  356. * @return string
  357. * @author 等风来
  358. * @email 136327134@qq.com
  359. * @date 2022/12/1
  360. */
  361. function mb_substr_str(string $value, int $length, string $str = '...', int $type = 0)
  362. {
  363. if (mb_strlen($value) > $length) {
  364. $value = mb_substr($value, 0, $length - mb_strlen($str)) . $str;
  365. }
  366. //等于1时去掉数组
  367. if ($type === 1) {
  368. $value = preg_replace('/[0-9]/', '', $value);
  369. }
  370. return $value;
  371. }
  372. }
  373. if (!function_exists('response_log_write')) {
  374. /**
  375. * 日志写入
  376. * @param array $data
  377. * @author 等风来
  378. * @email 136327134@qq.com
  379. * @date 2022/12/2
  380. */
  381. function response_log_write(array $data, string $type = \think\Log::ERROR)
  382. {
  383. try {
  384. $id = 0;
  385. foreach (['adminId', 'kefuId', 'uid', 'supplierId'] as $value) {
  386. if (request()->hasMacro($value)) {
  387. $id = request()->{$value}();
  388. }
  389. }
  390. //日志内容
  391. $log = [
  392. $id, //管理员ID
  393. request()->ip(), //客户ip
  394. ceil(msectime() - (request()->time(true) * 1000)), //耗时(毫秒)
  395. request()->method(true), //请求类型
  396. str_replace("/", "", request()->rootUrl()), //应用
  397. request()->baseUrl(), //路由
  398. json_encode(request()->param(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),//请求参数
  399. json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), //报错数据
  400. ];
  401. Log::write(implode("|", $log), $type);
  402. } catch (\Throwable $e) {
  403. }
  404. }
  405. }
  406. if (!function_exists('supplier_config')) {
  407. /**
  408. * @param int $supplierId
  409. * @param string $name
  410. * @param null $default
  411. * @return array|string|null
  412. */
  413. function supplier_config(int $supplierId, string $name, $default = null)
  414. {
  415. if (empty($name)) {
  416. return $default;
  417. }
  418. /** @var SystemConfigService $configService */
  419. $configService = app('sysConfig');
  420. $configService->setSupplier($supplierId);
  421. $sysConfig = $configService->get($name);
  422. if (is_array($sysConfig)) {
  423. foreach ($sysConfig as &$item) {
  424. if (strpos($item, '/uploads/system/') !== false) {
  425. $item = set_file_url($item);
  426. }
  427. }
  428. } else {
  429. if (strpos($sysConfig, '/uploads/system/') !== false) {
  430. $sysConfig = set_file_url($sysConfig);
  431. }
  432. }
  433. $config = is_array($sysConfig) ? $sysConfig : trim($sysConfig);
  434. if ($config === '' || $config === false) {
  435. return $default;
  436. } else {
  437. return $config;
  438. }
  439. }
  440. }
  441. if (!function_exists('stringToArray')) {
  442. /**
  443. * 处理ids等并过滤参数
  444. * @param $string
  445. * @param string $separator
  446. * @return array
  447. */
  448. function stringToArray($string, string $separator = ',')
  449. {
  450. $res = [];
  451. if ($string) {
  452. $string = is_string($string) ? explode($separator, $string) : $string;
  453. $ids = [];
  454. foreach ($string as $item) {
  455. $ids[] = (int)$item;
  456. }
  457. $res = array_unique(array_diff($ids, [0]));
  458. }
  459. return $res;
  460. }
  461. }
  462. if (!function_exists('getFileHeaders')) {
  463. /**
  464. * 获取文件大小头部信息
  465. * @param string $url
  466. * @param $isData
  467. * @return array
  468. */
  469. function getFileHeaders(string $url, $isData = true)
  470. {
  471. stream_context_set_default(['ssl' => ['verify_peer' => false, 'verify_peer_name' => false]]);
  472. $header['size'] = 0;
  473. $header['type'] = 'image/jpeg';
  474. if (!$isData) {
  475. return $header;
  476. }
  477. try {
  478. $headerArray = get_headers(str_replace('\\', '/', $url), true);
  479. if (!isset($headerArray['Content-Length'])) {
  480. $header['size'] = 0;
  481. } else {
  482. if (is_array($headerArray['Content-Length']) && count($headerArray['Content-Length']) == 2) {
  483. $header['size'] = $headerArray['Content-Length'][1];
  484. } else {
  485. $header['size'] = $headerArray['Content-Length'] ?? 0;
  486. }
  487. }
  488. if (!isset($headerArray['Content-Type'])) {
  489. $header['type'] = 'image/jpeg';
  490. } else {
  491. if (is_array($headerArray['Content-Type']) && count($headerArray['Content-Type']) == 2) {
  492. $header['type'] = $headerArray['Content-Type'][1];
  493. } else {
  494. $header['type'] = $headerArray['Content-Type'] ?? 'image/jpeg';
  495. }
  496. }
  497. } catch (\Exception $e) {
  498. }
  499. return $header;
  500. }
  501. }
  502. if (!function_exists('formatFileSize')) {
  503. /**
  504. * 格式化文件大小
  505. * @param $size
  506. * @return mixed|string|null
  507. */
  508. function formatFileSize($size)
  509. {
  510. if (!$size) {
  511. return '0KB';
  512. }
  513. try {
  514. $toKb = 1024;
  515. $toMb = $toKb * 1024;
  516. $toGb = $toMb * 1024;
  517. if ($size >= $toGb) {
  518. return round($size / $toGb, 2) . 'GB';
  519. } elseif ($size >= $toMb) {
  520. return round($size / $toMb, 2) . 'MB';
  521. } elseif ($size >= $toKb) {
  522. return round($size / $toKb, 2) . 'KB';
  523. } else {
  524. return $size . 'B';
  525. }
  526. } catch (\Exception $e) {
  527. return '0KB';
  528. }
  529. }
  530. }
  531. if (!function_exists('get_group_user')) {
  532. //所有下级
  533. function get_group_user($id, $init = true, $members = null)
  534. {
  535. if ($init) {
  536. $us = \app\model\user\User::column('spread_uid', 'uid');
  537. $members = [];
  538. foreach ($us as $k => $v) {
  539. if ($v > 0)
  540. $members[$v][] = $k;
  541. }
  542. $id = [$id];
  543. }
  544. $arr = array();
  545. foreach ($id as $v) {
  546. $child = $members[$v] ?? [];
  547. $arr = array_merge($arr, $child);
  548. }
  549. if (count($arr)) {
  550. return array_merge($arr, get_group_user($arr, false, $members));
  551. } else {
  552. return $arr;
  553. }
  554. }
  555. }
  556. if (!function_exists('stringToIntArray')) {
  557. /**
  558. * 处理ids等并过滤参数
  559. * @param string $string
  560. * @param string $separator
  561. * @return array
  562. */
  563. function stringToIntArray(string $string, string $separator = ',')
  564. {
  565. return !empty($string) ? array_unique(array_diff(array_map('intval', explode($separator, $string)), [0])) : [];
  566. }
  567. }
  568. if (!function_exists('filter_str')) {
  569. /**
  570. * 过滤字符串敏感字符
  571. * @param $str
  572. * @return array|mixed|string|string[]|null
  573. */
  574. function filter_str($str)
  575. {
  576. $rules = [
  577. '/\.\./', // 禁用包含 ../ 的参数
  578. '/\<\?/', // 禁止 php 脚本出现
  579. '/\bor\b.*=.*/i', // 匹配 'or 1=1',防止 SQL 注入(注意边界词 \b 和不区分大小写 i 修饰符)
  580. '/(select[\s\S]*?)(from|limit)/i', // 防止 SQL 注入
  581. '/(union[\s\S]*?select)/i', // 防止 SQL 注入
  582. '/(having|updatexml|extractvalue)/i', // 防止 SQL 注入
  583. '/sleep\((\s*)(\d*)(\s*)\)/i', // 防止 SQL 盲注
  584. '/benchmark\((.*)\,(.*)\)/i', // 防止 SQL 盲注
  585. '/base64_decode\(/i', // 防止 SQL 变种注入
  586. '/(?:from\W+information_schema\W)/i', // 注意这里的 (?:...) 是不合法的,应该是 (?:...) 表示非捕获组,但通常我们不需要这个
  587. '/(?:current_|user|database|schema|connection_id)\s*\(/i', // 防止 SQL 注入(注意去掉了不必要的 (?:...))
  588. '/(?:etc\/\W*passwd)/i', // 防止窥探 Linux 用户信息
  589. '/into(\s+)(?:dump|out)file\s*/i', // 禁用 MySQL 导出函数
  590. '/group\s+by.+\(/i', // 防止 SQL 注入
  591. '/(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(/i', // 禁用 webshell 相关某些函数
  592. '/(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/\//i', // 防止一些协议攻击(注意协议后的三个斜杠)
  593. '/\$_(GET|POST|COOKIE|FILES|SESSION|ENV|GLOBALS|SERVER)\[/i', // 禁用一些内置变量,注意 PHP 变量名通常是大写的
  594. '/<(iframe|script|body|img|layer|div|meta|style|base|object|input)/i', // 防止 XSS 标签植入
  595. '/(onmouseover|onerror|onload|onclick)\=/i', // 防止 XSS 事件植入
  596. '/\|\|.*?(?:ls|pwd|whoami|ll|ifconfig|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv)/i', // 防止执行 shell(注意去掉了不合适的 ifconfog)
  597. '/\sand\s+.*=.*/i' // 匹配 and 1=1
  598. ];
  599. if (filter_var($str, FILTER_VALIDATE_URL)) {
  600. $url = parse_url($str);
  601. if (!isset($url['scheme'])) return $str;
  602. $host = $url['scheme'] . '://' . $url['host'];
  603. $str = $host . preg_replace($rules, '', str_replace($host, '', $str));
  604. } else {
  605. $str = preg_replace($rules, '', $str);
  606. }
  607. return $str;
  608. }
  609. }