common.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. // 应用公共文件
  12. use app\common\repositories\system\config\ConfigValueRepository;
  13. use app\common\repositories\system\groupData\GroupDataRepository;
  14. use crmeb\services\UploadService;
  15. use Swoole\Lock;
  16. use think\db\BaseQuery;
  17. if (!function_exists('go')) {
  18. function go(): bool
  19. {
  20. return \Swoole\Coroutine::create(...func_get_args());
  21. }
  22. }
  23. if (!function_exists('isDebug')) {
  24. function isDebug(): bool
  25. {
  26. return !!env('APP_DEBUG');
  27. }
  28. }
  29. if (!function_exists('formToData')) {
  30. function formToData($form): array
  31. {
  32. $rule = $form->formRule();
  33. $action = $form->getAction();
  34. $method = $form->getMethod();
  35. $title = $form->getTitle();
  36. $config = (object)$form->formConfig();
  37. $admin = config('admin.api_admin_prefix');
  38. $merchant = config('admin.api_merchant_prefix');
  39. $api = $action;
  40. if (strpos($api, '/' . $admin) === 0) {
  41. $api = substr($api, strlen($admin) + 1);
  42. } else if (strpos($api, '/' . $merchant) === 0) {
  43. $api = substr($api, strlen($merchant) + 1);
  44. }
  45. $api = str_replace('.html', '', $api);
  46. return compact('rule', 'action', 'method', 'title', 'config', 'api');
  47. }
  48. }
  49. if (!function_exists('getDistance')) {
  50. function getDistance($lat1, $lng1, $lat2, $lng2)
  51. {
  52. //将角度转为狐度
  53. $radLat1 = deg2rad($lat1); //deg2rad()函数将角度转换为弧度
  54. $radLat2 = deg2rad($lat2);
  55. $radLng1 = deg2rad($lng1);
  56. $radLng2 = deg2rad($lng2);
  57. $a = $radLat1 - $radLat2;
  58. $b = $radLng1 - $radLng2;
  59. $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6371;
  60. return round($s, 1);
  61. }
  62. }
  63. /**
  64. * 无线级分类处理
  65. *
  66. * @param array $data 数据源
  67. * @param string $idName 主键
  68. * @param string $fieldName 父级字段
  69. * @param string $childrenKey 子级字段名
  70. * @return array
  71. * @author 张先生
  72. * @date 2020-03-27
  73. */
  74. if (!function_exists('formatCategory')) {
  75. function formatCategory(array $data, string $idName = "id", string $fieldName = 'pid', $childrenKey = 'children')
  76. {
  77. $items = [];
  78. foreach ($data as $item) {
  79. $items[$item[$idName]] = $item;
  80. }
  81. $result = array();
  82. foreach ($items as $item) {
  83. if (isset($items[$item[$fieldName]])) {
  84. $items[$item[$fieldName]][$childrenKey][] = &$items[$item[$idName]];
  85. } else if ($item[$fieldName] == 0) {
  86. $result[] = &$items[$item[$idName]];
  87. }
  88. }
  89. return $result;
  90. }
  91. }
  92. if (!function_exists('formatTreeList')) {
  93. function formatTreeList(&$options, $name, $pidName = 'pid', $pid = 0, $level = 0, &$data = []): array
  94. {
  95. $_options = $options;
  96. foreach ($_options as $k => $option) {
  97. if ($option[$pidName] == $pid) {
  98. $data[] = ['value' => $k, 'label' => str_repeat('|---', $level + 1) . $option[$name]];
  99. unset($options[$k]);
  100. formatTreeList($options, $name, $pidName, $k, $level + 1, $data);
  101. }
  102. }
  103. return $data;
  104. }
  105. }
  106. if (!function_exists('formatTree')) {
  107. function formatTree(&$options, $name, $pidName = 'pid', $pid = 0, $level = 0, $data = []): array
  108. {
  109. $_options = $options;
  110. foreach ($_options as $k => $option) {
  111. if ($option[$pidName] == $pid) {
  112. $value = ['id' => $k, 'title' => $option[$name]];
  113. unset($options[$k]);
  114. $value['children'] = formatTree($options, $name, $pidName, $k, $level + 1);
  115. $data[] = $value;
  116. }
  117. }
  118. return $data;
  119. }
  120. }
  121. if (!function_exists('formatCascaderData')) {
  122. function formatCascaderData(&$options, $name, $baseLevel = 0, $pidName = 'pid', $pid = 0, $level = 0, $data = []): array
  123. {
  124. $_options = $options;
  125. foreach ($_options as $k => $option) {
  126. if ($option[$pidName] == $pid) {
  127. $value = ['value' => $k, 'label' => $option[$name]];
  128. unset($options[$k]);
  129. $value['children'] = formatCascaderData($options, $name, $baseLevel, $pidName, $k, $level + 1);
  130. if (!count($value['children'])) unset($value['children']);
  131. $data[] = $value;
  132. }
  133. }
  134. return $data;
  135. }
  136. }
  137. /**
  138. * @function toMap 数组重新组装
  139. * @param array $data 数据
  140. * @param string $field key
  141. * @param string $value value default null
  142. * @return array
  143. * @author 张先生
  144. * @date 2020-04-01
  145. */
  146. if (!function_exists('toMap')) {
  147. function toMap(array $data, $field = 'id', $value = '')
  148. {
  149. $result = array();
  150. if (empty($data)) {
  151. return $result;
  152. }
  153. //开始处理数据
  154. foreach ($data as $item) {
  155. $val = $item;
  156. if (!empty($value)) {
  157. $val = $item[$value];
  158. }
  159. $result[$item[$field]] = $val;
  160. }
  161. return $result;
  162. }
  163. }
  164. /**
  165. * @function getUniqueListByArray 从数组中获取某个字段的值,重新拼装成新的一维数组
  166. * @param array $data 数据
  167. * @param string $field key
  168. * @return array
  169. * @author 张先生
  170. * @date 2020-04-01
  171. */
  172. if (!function_exists('getUniqueListByArray')) {
  173. function getUniqueListByArray(array $data, $field = 'id')
  174. {
  175. return array_unique(array_values(array_column($data, $field)));
  176. }
  177. }
  178. if (!function_exists('isPhone')) {
  179. function isPhone($test)
  180. {
  181. return !preg_match("/^1[3456789]{1}\d{9}$/", $test);
  182. }
  183. }
  184. if (!function_exists('getMonth')) {
  185. /**
  186. * 获取本季度 time
  187. * @param int|string $time
  188. * @param $ceil
  189. * @return array
  190. */
  191. function getMonth($time = '', $ceil = 0)
  192. {
  193. if ($ceil != 0)
  194. $season = ceil(date('n') / 3) - $ceil;
  195. else
  196. $season = ceil(date('n') / 3);
  197. $firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
  198. $lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
  199. return array($firstday, $lastday);
  200. }
  201. }
  202. if (!function_exists('getModelTime')) {
  203. /**
  204. * @param BaseQuery $model
  205. * @param string $section
  206. * @param string $prefix
  207. * @param string $field
  208. * @return mixed
  209. * @author xaboy
  210. * @day 2020-04-29
  211. */
  212. function getModelTime(BaseQuery $model, string $section, $prefix = 'create_time', $field = '-',$time = '')
  213. {
  214. if (!isset($section)) return $model;
  215. switch ($section) {
  216. case 'today':
  217. $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('today')), date('Y-m-d H:i:s', strtotime('tomorrow -1second'))]);
  218. break;
  219. case 'week':
  220. $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('this week 00:00:00')), date('Y-m-d H:i:s', strtotime('next week 00:00:00 -1second'))]);
  221. break;
  222. case 'month':
  223. $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('first Day of this month 00:00:00')), date('Y-m-d H:i:s', strtotime('first Day of next month 00:00:00 -1second'))]);
  224. break;
  225. case 'year':
  226. $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('this year 1/1')), date('Y-m-d H:i:s', strtotime('next year 1/1 -1second'))]);
  227. break;
  228. case 'yesterday':
  229. $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('yesterday')), date('Y-m-d H:i:s', strtotime('today -1second'))]);
  230. break;
  231. case 'quarter':
  232. list($startTime, $endTime) = getMonth();
  233. $model = $model->where($prefix, '>', $startTime);
  234. $model = $model->where($prefix, '<', $endTime);
  235. break;
  236. case 'lately7':
  237. $model = $model->where($prefix, 'between', [date('Y-m-d', strtotime("-7 day")), date('Y-m-d H:i:s')]);
  238. break;
  239. case 'lately30':
  240. $model = $model->where($prefix, 'between', [date('Y-m-d', strtotime("-30 day")), date('Y-m-d H:i:s')]);
  241. break;
  242. default:
  243. if (strstr($section, $field) !== false) {
  244. list($startTime, $endTime) = explode($field, $section);
  245. if (strlen($startTime) == 4) {
  246. $model->whereBetweenTime($prefix, date('Y-m-d H:i:s', strtotime($section)), date('Y-m-d H:i:s', strtotime($section . ' +1day -1second')));
  247. } else {
  248. if ($startTime == $endTime) {
  249. $model = $model->whereBetweenTime($prefix, date('Y-m-d 0:0:0', strtotime($startTime)), date('Y-m-d 23:59:59', strtotime($endTime)));
  250. } else if(strpos($startTime, ':')) {
  251. $model = $model->whereBetweenTime($prefix, $startTime, $endTime);
  252. } else {
  253. $model = $model->whereBetweenTime($prefix, date('Y-m-d H:i:s', strtotime($startTime)), date('Y-m-d H:i:s', strtotime($endTime . ' +1day -1second')));
  254. }
  255. }
  256. }
  257. break;
  258. }
  259. return $model;
  260. }
  261. }
  262. if (!function_exists('hasMany')) {
  263. function hasMany($collection, $field, $model, $searchKey, $insertKey, $where = [] ,$select = '*')
  264. {
  265. $ids = [];
  266. $link = [];
  267. if (!$collection) return [];
  268. $collection = $collection->toArray();
  269. foreach ($collection as $k => $item) {
  270. if (is_array($item[$field])) {
  271. $link[$k] = array_unique($item[$field]);
  272. $ids = array_merge($item[$field], $ids);
  273. } else {
  274. $link[$k] = array_unique(explode(',', $item[$field]));
  275. }
  276. $ids = array_merge($link[$k], $ids);
  277. if (isset($collection[$k][$insertKey])) unset($collection[$k][$insertKey]);
  278. }
  279. $ids = array_filter(array_unique($ids));
  280. if (!count($ids)) {
  281. return $collection;
  282. }
  283. $many = $model::whereIn($searchKey, array_unique($ids))->where($where)->field($select)->select();
  284. if (!$many) return $collection;
  285. $many = $many->toArray();
  286. foreach ($link as $k => $val) {
  287. foreach ($many as $item) {
  288. if (in_array($item[$searchKey], $val)) {
  289. if (!isset($collection[$k][$insertKey])) $collection[$k][$insertKey] = [];
  290. $collection[$k][$insertKey][] = $item;
  291. }
  292. }
  293. }
  294. return $collection;
  295. }
  296. }
  297. if (!function_exists('activeProductSku')) {
  298. //格式活动商品SKU
  299. function activeProductSku($activeData, $type = null)
  300. {
  301. $make = app()->make(\app\common\repositories\store\product\ProductRepository::class);
  302. $price = 0;
  303. $data = [];
  304. foreach($activeData as $key => $value) {
  305. $maxPrice = 0;
  306. $must_price = 0;
  307. $attrValue = [];
  308. if(is_null($value['product'])) continue;
  309. $productSku = $value['productSku'];
  310. $productAttr = $value['product']['attr'];
  311. $productAttrValue = $value['product']['attrValue'];
  312. unset($value['productSku'], $value['product']['attrValue'], $value['product']['attr']);
  313. foreach ($productAttrValue as $attr_value) {
  314. if (!empty($productSku)){
  315. foreach ($productSku as $sk => $sv) {
  316. if ( $sv['unique'] == $attr_value['unique']) {
  317. if ($type == 'discounts') {
  318. unset($attr_value['ot_price'], $attr_value['price']);
  319. $attr_value['ot_price'] = $sv['price'];
  320. $attr_value['price'] = $sv['active_price'];
  321. $_price = bcsub($sv['price'], $sv['active_price'], 2);
  322. if ($value['type']){
  323. $must_price = $must_price > $_price ? $must_price : $_price;
  324. } else {
  325. $maxPrice = $maxPrice > $_price ? $maxPrice : $_price;
  326. }
  327. } else {
  328. $attr_value['productSku'] = $sv;
  329. }
  330. $attrValue[] = $attr_value;
  331. }
  332. }
  333. }
  334. }
  335. $attr = $make->detailAttr($productAttr);
  336. if ($type == 'discounts') {
  337. $sku = $make->detailAttrValue($attrValue, null);
  338. $value['product']['sku'] = $sku;
  339. } else {
  340. $value['product']['attrValue'] = $attrValue;
  341. }
  342. $value['product']['attr'] = $attr;
  343. $price = bcadd($price, bcadd($must_price,$maxPrice,2), 2);
  344. if ($value['type'] == 1) {
  345. array_unshift($data,$value);
  346. }else {
  347. $data[] = $value;
  348. }
  349. }
  350. return compact('data', 'price');
  351. }
  352. }
  353. if (!function_exists('systemConfig')) {
  354. /**
  355. * 获取系统配置
  356. *
  357. * @param string|string[] $key
  358. * @return mixed
  359. * @author xaboy
  360. * @day 2020-05-08
  361. */
  362. function systemConfig($key)
  363. {
  364. return merchantConfig(0, $key);
  365. }
  366. }
  367. if (!function_exists('getDatesBetweenTwoDays')) {
  368. function getDatesBetweenTwoDays($startDate, $endDate)
  369. {
  370. $dates = [];
  371. if (strtotime($startDate) > strtotime($endDate)) {
  372. //如果开始日期大于结束日期,直接return 防止下面的循环出现死循环
  373. return $dates;
  374. } elseif ($startDate == $endDate) {
  375. //开始日期与结束日期是同一天时
  376. array_push($dates, date('m-d', strtotime($startDate)));
  377. return $dates;
  378. } else {
  379. array_push($dates, date('m-d', strtotime($startDate)));
  380. $currentDate = $startDate;
  381. do {
  382. $nextDate = date('Y-m-d', strtotime($currentDate . ' +1 days'));
  383. array_push($dates, date('m-d', strtotime($currentDate . ' +1 days')));
  384. $currentDate = $nextDate;
  385. } while ($endDate != $currentDate);
  386. return $dates;
  387. }
  388. }
  389. }
  390. if (!function_exists('getStartModelTime')) {
  391. function getStartModelTime(string $section)
  392. {
  393. switch ($section) {
  394. case 'today':
  395. case 'yesterday':
  396. return date('Y-m-d', strtotime($section));
  397. case 'week':
  398. return date('Y-m-d', strtotime('this week'));
  399. case 'month':
  400. return date('Y-m-d', strtotime('first Day of this month'));
  401. case 'year':
  402. return date('Y-m-d', strtotime('this year 1/1'));
  403. case 'quarter':
  404. list($startTime, $endTime) = getMonth();
  405. return $startTime;
  406. case 'lately7':
  407. return date('Y-m-d', strtotime("-7 day"));
  408. case 'lately30':
  409. return date('Y-m-d', strtotime("-30 day"));
  410. default:
  411. if (strstr($section, '-') !== false) {
  412. list($startTime, $endTime) = explode('-', $section);
  413. return date('Y-m-d H:i:s', strtotime($startTime));
  414. }
  415. return date('Y-m-d H:i:s');
  416. }
  417. }
  418. }
  419. if (!function_exists('merchantConfig')) {
  420. /**
  421. * 获取商户配置
  422. *
  423. * @param int $merId
  424. * @param string|string[] $key
  425. * @return mixed
  426. * @author xaboy
  427. * @day 2020-05-08
  428. */
  429. function merchantConfig(int $merId, $key)
  430. {
  431. $request = request();
  432. $make = app()->make(ConfigValueRepository::class);
  433. if (is_array($key)) {
  434. $_key = [];
  435. $cacheData = [];
  436. foreach ($key as $v) {
  437. if ($request->hasCache($merId, $v)) {
  438. $cacheData[$v] = $request->getCache($merId, $v);
  439. } else {
  440. $_key[] = $v;
  441. }
  442. }
  443. if (!count($_key)) return $cacheData;
  444. $data = $make->more($_key, $merId);
  445. $request->setCache($merId, $data);
  446. $data += $cacheData;
  447. } else {
  448. if ($request->hasCache($merId, $key)) {
  449. $data = $request->getCache($merId, $key);
  450. } else {
  451. $data = $make->get($key, $merId);
  452. $request->setCache($merId, $key, $data);
  453. }
  454. }
  455. return $data;
  456. }
  457. }
  458. if (!function_exists('systemGroupData')) {
  459. /**
  460. * 获取总后台组合数据配置
  461. *
  462. * @param string $key
  463. * @param int|null $page
  464. * @param int|null $limit
  465. * @return array
  466. * @author xaboy
  467. * @day 2020/5/27
  468. */
  469. function systemGroupData(string $key, ?int $page = null, ?int $limit = 10)
  470. {
  471. $make = app()->make(GroupDataRepository::class);
  472. return $make->groupData($key, 0, $page, $limit);
  473. }
  474. }
  475. if (!function_exists('merchantGroupData')) {
  476. /**
  477. * 获取商户后台组合数据配置
  478. *
  479. * @param int $merId
  480. * @param string $key
  481. * @param int|null $page
  482. * @param int|null $limit
  483. * @return array
  484. * @author xaboy
  485. * @day 2020/5/27
  486. */
  487. function merchantGroupData(int $merId, string $key, ?int $page = null, ?int $limit = 10)
  488. {
  489. $make = app()->make(GroupDataRepository::class);
  490. return $make->groupData($key, $merId, $page, $limit);
  491. }
  492. }
  493. if (!function_exists('filter_emoji')) {
  494. // 过滤掉emoji表情
  495. function filter_emoji($str)
  496. {
  497. $str = preg_replace_callback( //执行一个正则表达式搜索并且使用一个回调进行替换
  498. '/./u',
  499. function (array $match) {
  500. return strlen($match[0]) >= 4 ? '' : $match[0];
  501. },
  502. $str
  503. );
  504. return $str;
  505. }
  506. }
  507. if (!function_exists('setHttpType')) {
  508. /**
  509. * TODO 修改 https 和 http 移动到common
  510. * @param $url $url 域名
  511. * @param int $type 0 返回https 1 返回 http
  512. * @return string
  513. */
  514. function setHttpType($url, $type = 0)
  515. {
  516. $domainTop = substr($url, 0, 5);
  517. if ($type) {
  518. if ($domainTop == 'https') $url = 'http' . substr($url, 5, strlen($url));
  519. } else {
  520. if ($domainTop != 'https') $url = 'https:' . substr($url, 5, strlen($url));
  521. }
  522. return $url;
  523. }
  524. }
  525. if (!function_exists('remoteImage')) {
  526. /**
  527. * TODO 获取小程序二维码是否生成
  528. * @param $url
  529. * @return array
  530. */
  531. function remoteImage($url)
  532. {
  533. $curl = curl_init();
  534. curl_setopt($curl, CURLOPT_URL, $url);
  535. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  536. $result = curl_exec($curl);
  537. $result = json_decode($result, true);
  538. if (is_array($result)) return ['status' => false, 'msg' => $result['errcode'] . '---' . $result['errmsg']];
  539. return ['status' => true];
  540. }
  541. }
  542. if (!function_exists('image_to_base64')) {
  543. /**
  544. * 获取图片转为base64
  545. * @param string $avatar
  546. * @return bool|string
  547. */
  548. function image_to_base64($avatar = '', $timeout = 9)
  549. {
  550. try {
  551. $url = parse_url($avatar);
  552. $url = $url['host'];
  553. $header = [
  554. 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:45.0) Gecko/20100101 Firefox/45.0',
  555. 'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
  556. 'Accept-Encoding: gzip, deflate, br',
  557. 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
  558. 'Host:' . $url
  559. ];
  560. checkSuffix($url);
  561. $dir = pathinfo($url);
  562. $host = $dir['dirname'];
  563. $refer = $host . '/';
  564. $curl = curl_init();
  565. curl_setopt($curl, CURLOPT_REFERER, $refer);
  566. curl_setopt($curl, CURLOPT_URL, $avatar);
  567. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  568. curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
  569. curl_setopt($curl, CURLOPT_ENCODING, 'gzip');
  570. curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
  571. curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
  572. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  573. $data = curl_exec($curl);
  574. $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  575. curl_close($curl);
  576. if ($code == 200) {
  577. return "data:image/jpeg;base64," . base64_encode($data);
  578. } else {
  579. return false;
  580. }
  581. } catch (Exception $e) {
  582. return false;
  583. }
  584. }
  585. }
  586. if (!function_exists('put_image')) {
  587. /**
  588. * 获取图片转为base64
  589. * @param string $avatar
  590. * @return bool|string
  591. */
  592. function put_image($url, $filename = '')
  593. {
  594. if ($url == '') {
  595. return false;
  596. }
  597. try {
  598. if ($filename == '') {
  599. $ext = pathinfo($url);
  600. if ($ext['extension'] != "jpg" && $ext['extension'] != "png" && $ext['extension'] != "jpeg") {
  601. return false;
  602. }
  603. $filename = time() . "." . $ext['extension'];
  604. }
  605. //文件保存路径
  606. ob_start();
  607. readfile($url);
  608. $img = ob_get_contents();
  609. ob_end_clean();
  610. $path = 'public/uploads/qrcode';
  611. $fp2 = fopen($path . '/' . $filename, 'a');
  612. fwrite($fp2, $img);
  613. fclose($fp2);
  614. return $path . '/' . $filename;
  615. } catch (Exception $e) {
  616. return false;
  617. }
  618. }
  619. }
  620. if (!function_exists('path_to_url')) {
  621. /**
  622. * 路径转url路径
  623. * @param $path
  624. * @return string
  625. */
  626. function path_to_url($path)
  627. {
  628. return trim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '.');
  629. }
  630. }
  631. if (!function_exists('tidy_url')) {
  632. /**
  633. * 路径转url路径
  634. * @param $url
  635. * @param int $http
  636. * @param string $site
  637. * @return string
  638. */
  639. function tidy_url($url, $http = null, $site = null)
  640. {
  641. if (!$site) {
  642. $site = systemConfig('site_url');
  643. }
  644. $url = path_to_url($url);
  645. if (strpos($url, 'http') === false)
  646. $url = rtrim($site, '/') . '/' . ltrim($url, '/');
  647. if (is_null($http)) {
  648. $http = (parse_url($site)['scheme'] ?? '') == 'https' ? 0 : 1;
  649. }
  650. $url = set_http_type($url, $http);
  651. return $url;
  652. }
  653. }
  654. if (!function_exists('curl_file_exist')) {
  655. /**
  656. * CURL 检测远程文件是否在
  657. * @param $url
  658. * @return bool
  659. */
  660. function curl_file_exist($url)
  661. {
  662. $ch = curl_init();
  663. try {
  664. curl_setopt($ch, CURLOPT_URL, $url);
  665. curl_setopt($ch, CURLOPT_HEADER, 1);
  666. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  667. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
  668. $contents = curl_exec($ch);
  669. if (preg_match("/404/", $contents)) return false;
  670. if (preg_match("/403/", $contents)) return false;
  671. return true;
  672. } catch (Exception $e) {
  673. return false;
  674. }
  675. }
  676. }
  677. if (!function_exists('set_http_type')) {
  678. /**
  679. * 修改 https 和 http
  680. * @param $url $url 域名
  681. * @param int $type 0 返回https 1 返回 http
  682. * @return string
  683. */
  684. function set_http_type($url, $type = 0)
  685. {
  686. $domainTop = substr($url, 0, 5);
  687. if ($type) {
  688. if ($domainTop == 'https') $url = 'http' . substr($url, 5, strlen($url));
  689. } else {
  690. if ($domainTop != 'https') $url = 'https:' . substr($url, 5, strlen($url));
  691. }
  692. return $url;
  693. }
  694. }
  695. if (!function_exists('setSharePoster')) {
  696. /**
  697. * TODO 生成分享二维码图片
  698. * @param array $config
  699. * @param $path
  700. * @return array|bool|string
  701. * @throws Exception
  702. */
  703. function setSharePoster($config, $path)
  704. {
  705. $imageDefault = array(
  706. 'left' => 0,
  707. 'top' => 0,
  708. 'right' => 0,
  709. 'bottom' => 0,
  710. 'width' => 100,
  711. 'height' => 100,
  712. 'opacity' => 100
  713. );
  714. $textDefault = array(
  715. 'text' => '',
  716. 'left' => 0,
  717. 'top' => 0,
  718. 'fontSize' => 32, //字号
  719. 'fontColor' => '255,255,255', //字体颜色
  720. 'angle' => 0,
  721. );
  722. $background = $config['background']; //海报最底层得背景
  723. if (substr($background, 0, 1) === '/') {
  724. $background = substr($background, 1);
  725. }
  726. $backgroundInfo = getimagesize($background);
  727. $background = imagecreatefromstring(file_get_contents($background));
  728. $backgroundWidth = $backgroundInfo[0]; //背景宽度
  729. $backgroundHeight = $backgroundInfo[1]; //背景高度
  730. $imageRes = imageCreatetruecolor($backgroundWidth, $backgroundHeight);
  731. $color = imagecolorallocate($imageRes, 0, 0, 0);
  732. imagefill($imageRes, 0, 0, $color);
  733. imagecopyresampled($imageRes, $background, 0, 0, 0, 0, imagesx($background), imagesy($background), imagesx($background), imagesy($background));
  734. if (!empty($config['image'])) {
  735. foreach ($config['image'] as $key => $val) {
  736. $val = array_merge($imageDefault, $val);
  737. $info = getimagesize($val['url']);
  738. $function = 'imagecreatefrom' . image_type_to_extension($info[2], false);
  739. if ($val['stream']) {
  740. $info = getimagesizefromstring($val['url']);
  741. $function = 'imagecreatefromstring';
  742. }
  743. $res = $function($val['url']);
  744. $resWidth = $info[0];
  745. $resHeight = $info[1];
  746. $canvas = imagecreatetruecolor($val['width'], $val['height']);
  747. imagefill($canvas, 0, 0, $color);
  748. imagecopyresampled($canvas, $res, 0, 0, 0, 0, $val['width'], $val['height'], $resWidth, $resHeight);
  749. $val['left'] = $val['left'] < 0 ? $backgroundWidth - abs($val['left']) - $val['width'] : $val['left'];
  750. $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) - $val['height'] : $val['top'];
  751. imagecopymerge($imageRes, $canvas, $val['left'], $val['top'], $val['right'], $val['bottom'], $val['width'], $val['height'], $val['opacity']); //左,上,右,下,宽度,高度,透明度
  752. }
  753. }
  754. if (isset($config['text']) && !empty($config['text'])) {
  755. foreach ($config['text'] as $key => $val) {
  756. $val = array_merge($textDefault, $val);
  757. list($R, $G, $B) = explode(',', $val['fontColor']);
  758. $fontColor = imagecolorallocate($imageRes, $R, $G, $B);
  759. $val['left'] = $val['left'] < 0 ? $backgroundWidth - abs($val['left']) : $val['left'];
  760. $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) : $val['top'];
  761. imagettftext($imageRes, $val['fontSize'], $val['angle'], $val['left'], $val['top'], $fontColor, $val['fontPath'], $val['text']);
  762. }
  763. }
  764. ob_start();
  765. imagejpeg($imageRes);
  766. imagedestroy($imageRes);
  767. $res = ob_get_contents();
  768. ob_end_clean();
  769. $key = substr(md5(rand(0, 9999)), 0, 5) . date('YmdHis') . rand(0, 999999) . '.jpg';
  770. $uploadType = (int)systemConfig('upload_type') ?: 1;
  771. $upload = UploadService::create($uploadType);
  772. $res = $upload->to($path)->validate()->stream($res, $key);
  773. if ($res === false) {
  774. return $upload->getError();
  775. } else {
  776. $info = $upload->getUploadInfo();
  777. $info['image_type'] = $uploadType;
  778. return $info;
  779. }
  780. }
  781. }
  782. if (!function_exists('getTimes')) {
  783. function getTimes()
  784. {
  785. $dates = [];
  786. for ($i = 0; $i <= 24; $i++) {
  787. for ($j = 0; $j < 60; $j++) {
  788. $dates[] = sprintf('%02.d', $i) . ':' . sprintf('%02.d', $j);
  789. }
  790. }
  791. return $dates;
  792. }
  793. }
  794. if (!function_exists('monday')) {
  795. /**
  796. * 获取周一
  797. *
  798. * @param null $time
  799. * @return false|string
  800. * @author xaboy
  801. * @day 2020/6/22
  802. */
  803. function monday($time = null)
  804. {
  805. return date('Y-m-d', strtotime('Sunday -6 day', $time ?: time()));
  806. }
  807. }
  808. if (!function_exists('orderLock')) {
  809. /**
  810. * @param string $name
  811. * @return Lock
  812. * @author xaboy
  813. * @day 2020/8/25
  814. */
  815. function makeLock($name = 'default'): Lock
  816. {
  817. return $GLOBALS['_swoole_order_lock'][$name];
  818. }
  819. }
  820. if (!function_exists('get_crmeb_version')) {
  821. /**
  822. * 获取CRMEB系统版本号
  823. * @param string $default
  824. * @return string
  825. */
  826. function get_crmeb_version($default = 'v1.0.0')
  827. {
  828. try {
  829. $version = parse_ini_file(app()->getRootPath() . '.version');
  830. return $version['version'] ?? $default;
  831. } catch (Throwable $e) {
  832. return $default;
  833. }
  834. }
  835. }
  836. if (!function_exists('get_crmeb_version_code')) {
  837. /**
  838. * 获取CRMEB系统版本号
  839. * @param string $default
  840. * @return string
  841. */
  842. function get_crmeb_version_code($default = '1.7.2')
  843. {
  844. try {
  845. $version = parse_ini_file(app()->getRootPath() . '.version');
  846. return $version['code'] ?? $default;
  847. } catch (Throwable $e) {
  848. return $default;
  849. }
  850. }
  851. }
  852. if (!function_exists('update_crmeb_compiled')) {
  853. /**
  854. * 获取CRMEB系统版本号
  855. * @param string $default
  856. * @return string
  857. */
  858. function update_crmeb_compiled($default = 'v1.0.0')
  859. {
  860. $compiled = [
  861. '7.1' => 'compiled71',
  862. '7.2' => 'compiled72',
  863. '7.3' => 'compiled73',
  864. '7.4' => 'compiled74',
  865. ];
  866. $phpv = @phpversion();
  867. $phpvs = substr($phpv, 0, 3);
  868. $key = $compiled[$phpvs] ?? '';
  869. if (!$key)
  870. return false;
  871. $root = app()->getRootPath();
  872. $compiledPath = $root . 'install/compiled';
  873. $file = $root . 'install/compiled/' . $key . '.zip';
  874. $toPath = $root . 'crmeb/basic';
  875. $toConfigPath = $root . 'config/crmeb.php';
  876. try {
  877. if (is_file($file)) {
  878. $zip = new ZipArchive();
  879. if ($zip->open($file) === true) {
  880. $zip->extractTo($compiledPath . '/');
  881. $zip->close();
  882. }
  883. if (is_dir($compiledPath . '/basic')) {
  884. if (is_dir($toPath) || mkdir($toPath, 0777) || is_dir($toPath)) {
  885. foreach (glob($compiledPath . '/basic/*') as $item) {
  886. @rename($item, $toPath . '/' . pathinfo($item, PATHINFO_BASENAME));
  887. }
  888. }
  889. @rmdir($compiledPath . '/basic');
  890. }
  891. if (is_file($compiledPath . '/crmeb.php')) {
  892. @rename($compiledPath . '/crmeb.php', $toConfigPath);
  893. }
  894. }
  895. } catch (\Exception $exception) {
  896. return false;
  897. }
  898. return true;
  899. }
  900. }
  901. if (!function_exists('attr_format')) {
  902. /**
  903. * 格式化属性
  904. * @param $arr
  905. * @return array
  906. */
  907. function attr_format($arr)
  908. {
  909. $data = [];
  910. $res = [];
  911. $count = count($arr);
  912. if ($count > 1) {
  913. for ($i = 0; $i < $count - 1; $i++) {
  914. if ($i == 0) $data = $arr[$i]['detail'];
  915. //替代变量1
  916. $rep1 = [];
  917. foreach ($data as $v) {
  918. foreach ($arr[$i + 1]['detail'] as $g) {
  919. //替代变量2
  920. $rep2 = ($i != 0 ? '' : $arr[$i]['value'] . '_$_') . $v . '-$-' . $arr[$i + 1]['value'] . '_$_' . $g;
  921. $tmp[] = $rep2;
  922. if ($i == $count - 2) {
  923. foreach (explode('-$-', $rep2) as $k => $h) {
  924. //替代变量3
  925. $rep3 = explode('_$_', $h);
  926. //替代变量4
  927. $rep4['detail'][$rep3[0]] = isset($rep3[1]) ? $rep3[1] : '';
  928. }
  929. if ($count == count($rep4['detail']))
  930. $res[] = $rep4;
  931. }
  932. }
  933. }
  934. $data = isset($tmp) ? $tmp : [];
  935. }
  936. } else {
  937. $dataArr = [];
  938. foreach ($arr as $k => $v) {
  939. foreach ($v['detail'] as $kk => $vv) {
  940. $dataArr[$kk] = $v['value'] . '_' . $vv;
  941. $res[$kk]['detail'][$v['value']] = $vv;
  942. }
  943. }
  944. $data[] = implode('-', $dataArr);
  945. }
  946. return [$data, $res];
  947. }
  948. }
  949. if (!function_exists('filter_emoji')) {
  950. //过滤掉emoji表情
  951. function filter_emoji($str)
  952. {
  953. $str = preg_replace_callback('/./u', function (array $match) {
  954. return strlen($match[0]) >= 4 ? '' : $match[0];
  955. }, $str);
  956. return $str;
  957. }
  958. }
  959. /**
  960. * 高德经纬度改百度经纬度
  961. * @param $lng 经度
  962. * @param $lat 纬度
  963. * @return mixed
  964. */
  965. if (!function_exists('bd_encrypt')) {
  966. function bd_encrypt($lng, $lat)
  967. {
  968. $x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  969. $x = $lng;
  970. $y = $lat;
  971. $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);
  972. $theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi);
  973. $data['lng'] = $z * cos($theta) + 0.0065;
  974. $data['lat'] = $z * sin($theta) + 0.006;
  975. return $data;
  976. }
  977. }
  978. if (!function_exists('lbs_address')) {
  979. function lbs_address($region, $address)
  980. {
  981. $locationOption = new \Joypack\Tencent\Map\Bundle\AddressOption(systemConfig('tx_map_key'));
  982. $locationOption->setAddress($address);
  983. $locationOption->setRegion($region);
  984. $location = new \Joypack\Tencent\Map\Bundle\Address($locationOption);
  985. $res = $location->request();
  986. if ($res->error) {
  987. throw new \think\exception\ValidateException($res->error);
  988. }
  989. if ($res->status) {
  990. throw new \think\exception\ValidateException($res->message);
  991. }
  992. if (!$res->result) {
  993. throw new \think\exception\ValidateException('获取失败');
  994. }
  995. return $res->result;
  996. }
  997. }
  998. if (!function_exists('aj_captcha_check_one')) {
  999. /**
  1000. * 验证滑块1次验证
  1001. * @param string $token
  1002. * @param string $pointJson
  1003. * @return bool
  1004. */
  1005. function aj_captcha_check_one(string $captchaType, string $token, string $pointJson)
  1006. {
  1007. aj_get_serevice($captchaType)->check($token, $pointJson);
  1008. return true;
  1009. }
  1010. }
  1011. if (!function_exists('aj_captcha_check_two')) {
  1012. /**
  1013. * 验证滑块2次验证
  1014. * @param string $token
  1015. * @param string $pointJson
  1016. * @return bool
  1017. */
  1018. function aj_captcha_check_two(string $captchaType, string $captchaVerification )
  1019. {
  1020. aj_get_serevice($captchaType)->verificationByEncryptCode($captchaVerification);
  1021. return true;
  1022. }
  1023. }
  1024. if (!function_exists('aj_captcha_create')) {
  1025. /**
  1026. * 创建验证码
  1027. * @return array
  1028. */
  1029. function aj_captcha_create(string $captchaType)
  1030. {
  1031. return aj_get_serevice($captchaType)->get();
  1032. }
  1033. }
  1034. if (!function_exists('aj_get_serevice')) {
  1035. function aj_get_serevice(string $captchaType)
  1036. {
  1037. $config = \think\facade\Config::get('ajcaptcha');
  1038. switch ($captchaType) {
  1039. case "clickWord":
  1040. $service = new \Fastknife\Service\ClickWordCaptchaService($config);
  1041. break;
  1042. case "blockPuzzle":
  1043. // $service = new \Fastknife\Service\BlockPuzzleCaptchaService($config);
  1044. $service = new \crmeb\services\BlockPuzzleCaptchaService($config);
  1045. break;
  1046. default:
  1047. throw new \think\exception\ValidateException('captchaType参数不正确:'.$captchaType);
  1048. }
  1049. return $service;
  1050. }
  1051. }
  1052. if (!function_exists('checkSuffix')) {
  1053. function checkSuffix($data)
  1054. {
  1055. $suffix = \think\facade\Config::get('upload.fileExt');
  1056. if (is_array($data)){
  1057. foreach ($data as $datum) {
  1058. $result = pathinfo($datum);
  1059. if (isset($result['extension']) && !in_array($result['extension'],$suffix)) {
  1060. throw new \think\exception\ValidateException('上传文件后缀不允许');
  1061. }
  1062. }
  1063. } else {
  1064. $result = pathinfo($data);
  1065. if (isset($result['extension']) && !in_array($result['extension'],$suffix)) {
  1066. throw new \think\exception\ValidateException('上传文件后缀不允许');
  1067. }
  1068. }
  1069. return ;
  1070. }
  1071. }