RoutineServices.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\services\wechat;
  13. use app\services\BaseServices;
  14. use app\dao\wechat\WechatUserDao;
  15. use app\services\other\QrcodeServices;
  16. use app\services\user\LoginServices;
  17. use app\services\user\UserServices;
  18. use crmeb\services\CacheService;
  19. use crmeb\services\CacheService as Cache;
  20. use crmeb\services\MiniProgramService;
  21. use crmeb\services\template\Template;
  22. use think\exception\ValidateException;
  23. use think\facade\Config;
  24. /**
  25. *
  26. * Class RoutineServices
  27. * @package app\services\wechat
  28. */
  29. class RoutineServices extends BaseServices
  30. {
  31. /**
  32. * RoutineServices constructor.
  33. * @param WechatUserDao $dao
  34. */
  35. public function __construct(WechatUserDao $dao)
  36. {
  37. $this->dao = $dao;
  38. }
  39. /**
  40. * 小程序授权登录
  41. * @param $code
  42. * @param $post_cache_key
  43. * @param $login_type
  44. * @param $spread_spid
  45. * @param $spread_code
  46. * @param $iv
  47. * @param $encryptedData
  48. * @return mixed
  49. */
  50. public function mp_auth($code, $post_cache_key, $login_type, $spread_spid, $spread_code, $iv, $encryptedData)
  51. {
  52. $session_key = Cache::get('eb_api_code_' . $post_cache_key);
  53. if (!$code && !$session_key)
  54. throw new ValidateException('授权失败,参数有误');
  55. if ($code && !$session_key) {
  56. try {
  57. $userInfoCong = MiniProgramService::getUserInfo($code);
  58. $session_key = $userInfoCong['session_key'];
  59. $cache_key = md5(time() . $code);
  60. if (!isset($userInfoCong['openid'])) {
  61. throw new ValidateException('openid获取失败');
  62. }
  63. Cache::set('eb_api_code_' . $cache_key, $session_key, 86400);
  64. } catch (\Exception $e) {
  65. throw new ValidateException('获取session_key失败,请检查您的配置!:' . $e->getMessage() . 'line' . $e->getLine());
  66. }
  67. }
  68. try {
  69. //解密获取用户信息
  70. $userInfo = MiniProgramService::encryptor($session_key, $iv, $encryptedData);
  71. } catch (\Exception $e) {
  72. if ($e->getCode() == '-41003') {
  73. throw new ValidateException('获取会话密匙失败');
  74. }
  75. }
  76. $userInfo['unionId'] = isset($userInfoCong['unionid']) ? $userInfoCong['unionid'] : '';
  77. $userInfo['openId'] = $openid = $userInfoCong['openid'];
  78. $userInfo['spid'] = $spread_spid;
  79. $userInfo['code'] = $spread_code;
  80. $userInfo['session_key'] = $session_key;
  81. $userInfo['login_type'] = $login_type;
  82. $createData = $this->routineOauth($userInfo);
  83. /** @var WechatUserServices $wechatUserServices */
  84. $wechatUserServices = app()->make(WechatUserServices::class);
  85. $user = $wechatUserServices->getAuthUserInfo($openid, 'routine');
  86. if (!$user) {
  87. $user = $wechatUserServices->wechatOauthAfter($createData);
  88. } else {
  89. //更新用户信息
  90. $wechatUserServices->wechatUpdata([$user['uid'], $createData[1]]);
  91. }
  92. $token = $this->createToken((int)$user['uid'], 'routine');
  93. if ($token) {
  94. return [
  95. 'userInfo' => $user
  96. ];
  97. } else
  98. throw new ValidateException('获取用户访问token失败!');
  99. }
  100. /**
  101. * 小程序授权登录
  102. * @param $code
  103. * @param $spid
  104. * @param $spread
  105. * @param $iv
  106. * @param $encryptedData
  107. * @return array
  108. * @throws \think\db\exception\DataNotFoundException
  109. * @throws \think\db\exception\ModelNotFoundException
  110. */
  111. public function newAuth($code, $spid, $spread, $iv, $encryptedData)
  112. {
  113. if (!$code)
  114. throw new ValidateException('授权失败,参数有误');
  115. $session_key = '';
  116. try {
  117. $userInfoCong = MiniProgramService::getUserInfo($code);
  118. $session_key = $userInfoCong['session_key'];
  119. if (!isset($userInfoCong['openid'])) {
  120. throw new ValidateException('openid获取失败');
  121. }
  122. } catch (\Exception $e) {
  123. throw new ValidateException('获取session_key失败,请检查您的配置!:' . $e->getMessage() . 'line' . $e->getLine());
  124. }
  125. try {
  126. //解密获取用户信息
  127. $userInfo = MiniProgramService::encryptor($session_key, $iv, $encryptedData);
  128. } catch (\Exception $e) {
  129. if ($e->getCode() == '-41003') {
  130. throw new ValidateException('获取会话密匙失败');
  131. }
  132. }
  133. $userInfo['unionId'] = isset($userInfoCong['unionid']) ? $userInfoCong['unionid'] : '';
  134. $userInfo['openId'] = $openid = $userInfoCong['openid'];
  135. $userInfo['spid'] = $spid;
  136. $userInfo['code'] = $spread;
  137. $userInfo['session_key'] = $session_key;
  138. $userInfo['login_type'] = 'routine';
  139. $createData = $this->routineOauth($userInfo);
  140. /** @var WechatUserServices $wechatUserServices */
  141. $wechatUserServices = app()->make(WechatUserServices::class);
  142. $user = $wechatUserServices->getAuthUserInfo($openid, 'routine');
  143. //获取是否强制绑定手机号
  144. $storeUserMobile = sys_config('store_user_mobile');
  145. if ($storeUserMobile && !$user) {
  146. $userInfoKey = md5($openid . '_' . time() . '_rouine');
  147. Cache::setTokenBucket($userInfoKey, $createData, 7200);
  148. return ['key' => $userInfoKey];
  149. } else if (!$user) {
  150. $user = $wechatUserServices->wechatOauthAfter($createData);
  151. } else {
  152. //更新用户信息
  153. $wechatUserServices->wechatUpdata([$user['uid'], $createData[1]]);
  154. }
  155. $token = $this->createToken((int)$user['uid'], 'routine');
  156. if ($token) {
  157. $token['userInfo'] = $user;
  158. return $token;
  159. } else
  160. throw new ValidateException('登录失败');
  161. }
  162. /**
  163. * 小程序创建用户后返回uid
  164. * @param $routineInfo
  165. * @return mixed
  166. */
  167. public function routineOauth($routine)
  168. {
  169. $routineInfo['nickname'] = filter_emoji($routine['nickName']);//姓名
  170. $routineInfo['sex'] = $routine['gender'];//性别
  171. $routineInfo['language'] = $routine['language'];//语言
  172. $routineInfo['city'] = $routine['city'];//城市
  173. $routineInfo['province'] = $routine['province'];//省份
  174. $routineInfo['country'] = $routine['country'];//国家
  175. $routineInfo['headimgurl'] = $routine['avatarUrl'];//头像
  176. $routineInfo['openid'] = $routine['openId'];
  177. $routineInfo['session_key'] = $routine['session_key'];//会话密匙
  178. $routineInfo['unionid'] = $routine['unionId'];//用户在开放平台的唯一标识符
  179. $routineInfo['user_type'] = 'routine';//用户类型
  180. $routineInfo['phone'] = $routine['phone'] ?? $routine['purePhoneNumber'] ?? '';
  181. $spid = $routine['spid'] ?? 0;//绑定关系uid
  182. //获取是否有扫码进小程序
  183. /** @var QrcodeServices $qrcode */
  184. $qrcode = app()->make(QrcodeServices::class);
  185. if (isset($routine['code']) && $routine['code'] && ($info = $qrcode->get($routine['code']))) {
  186. $spid = $info['third_id'];
  187. }
  188. return [$routine['openId'], $routineInfo, $spid, $routine['login_type'] ?? 'routine', 'routine'];
  189. }
  190. /**
  191. * 小程序支付回调
  192. */
  193. public function notify()
  194. {
  195. return MiniProgramService::handleNotify();
  196. }
  197. /**
  198. * 获取小程序订阅消息id
  199. * @return mixed
  200. */
  201. public function temlIds()
  202. {
  203. $temlIdsName = Config::get('template.stores.subscribe.template_id', []);
  204. $temlIdsList = Cache::get('TEML_IDS_LIST', function () use ($temlIdsName) {
  205. $temlId = [];
  206. $templdata = new Template('subscribe');
  207. foreach ($temlIdsName as $key => $item) {
  208. $temlId[strtolower($key)] = $templdata->getTempId($item);
  209. }
  210. return $temlId;
  211. });
  212. return $temlIdsList;
  213. }
  214. /**
  215. * 获取小程序直播列表
  216. * @param $pgae
  217. * @param $limit
  218. * @return mixed
  219. */
  220. public function live($page, $limit)
  221. {
  222. $list = Cache::get('WECHAT_LIVE_LIST_' . $page . '_' . $limit, function () use ($page, $limit) {
  223. $list = MiniProgramService::getLiveInfo((int)$page, (int)$limit);
  224. foreach ($list as &$item) {
  225. $item['_start_time'] = date('m-d H:i', $item['start_time']);
  226. }
  227. return $list;
  228. }, 600) ?: [];
  229. return $list;
  230. }
  231. /**
  232. * 静默授权
  233. * @param $code
  234. * @param $spread
  235. * @return mixed
  236. */
  237. public function silenceAuth($code, $spread, $spid)
  238. {
  239. $userInfoConfig = MiniProgramService::getUserInfo($code);
  240. if (!isset($userInfoConfig['openid'])) {
  241. throw new ValidateException('静默授权失败');
  242. }
  243. $routineInfo = [
  244. 'unionid' => $userInfoConfig['unionid'] ?? null
  245. ];
  246. /** @var QrcodeServices $qrcode */
  247. $qrcode = app()->make(QrcodeServices::class);
  248. if ($spread && ($info = $qrcode->getOne(['id' => $spread, 'status' => 1]))) {
  249. $spid = $info['third_id'];
  250. }
  251. $openid = $userInfoConfig['openid'];
  252. $routineInfo['openid'] = $openid;
  253. $routineInfo['headimgurl'] = sys_config('h5_avatar');
  254. /** @var WechatUserServices $wechatUserServices */
  255. $wechatUserServices = app()->make(WechatUserServices::class);
  256. $user = $wechatUserServices->getAuthUserInfo($openid, 'routine');
  257. $createData = [$openid, $routineInfo, $spid, '', 'routine'];
  258. //获取是否强制绑定手机号
  259. $storeUserMobile = sys_config('store_user_mobile');
  260. if ($storeUserMobile && !$user) {
  261. $userInfoKey = md5($openid . '_' . time() . '_routine');
  262. Cache::setTokenBucket($userInfoKey, $createData, 7200);
  263. return ['key' => $userInfoKey];
  264. } else if (!$user) {
  265. //写入用户信息
  266. $user = $wechatUserServices->wechatOauthAfter($createData);
  267. $token = $this->createToken((int)$user['uid'], 'routine');
  268. if ($token) {
  269. return $token;
  270. } else
  271. throw new ValidateException('登录失败');
  272. } else {
  273. //更新用户信息
  274. $wechatUserServices->wechatUpdata([$user['uid'], ['code' => $spid]]);
  275. $token = $this->createToken((int)$user['uid'], 'routine');
  276. if ($token) {
  277. return $token;
  278. } else
  279. throw new ValidateException('登录失败');
  280. }
  281. }
  282. /**
  283. * 静默授权
  284. * @param $code
  285. * @param $spread
  286. * @return mixed
  287. */
  288. public function silenceAuthNoLogin($code, $spread, $spid)
  289. {
  290. $userInfoConfig = MiniProgramService::getUserInfo($code);
  291. if (!isset($userInfoConfig['openid'])) {
  292. throw new ValidateException('静默授权失败');
  293. }
  294. $routineInfo = [
  295. 'unionid' => $userInfoConfig['unionid'] ?? null
  296. ];
  297. /** @var QrcodeServices $qrcode */
  298. $qrcode = app()->make(QrcodeServices::class);
  299. if ($spread && ($info = $qrcode->getOne(['id' => $spread, 'status' => 1]))) {
  300. $spid = $info['third_id'];
  301. }
  302. $openid = $userInfoConfig['openid'];
  303. $routineInfo['openid'] = $openid;
  304. $routineInfo['headimgurl'] = sys_config('h5_avatar');
  305. /** @var WechatUserServices $wechatUserServices */
  306. $wechatUserServices = app()->make(WechatUserServices::class);
  307. $user = $wechatUserServices->getAuthUserInfo($openid, 'routine');
  308. $createData = [$openid, $routineInfo, $spid, '', 'routine'];
  309. if (!$user) {
  310. $userInfoKey = md5($openid . '_' . time() . '_routine');
  311. Cache::setTokenBucket($userInfoKey, $createData, 7200);
  312. return ['auth_login' => 1, 'key' => $userInfoKey];
  313. } else {
  314. //更新用户信息
  315. $wechatUserServices->wechatUpdata([$user['uid'], ['code' => $spid]]);
  316. $token = $this->createToken((int)$user['uid'], 'routine');
  317. if ($token) {
  318. $token['userInfo'] = $user;
  319. return $token;
  320. } else
  321. throw new ValidateException('登录失败');
  322. }
  323. }
  324. /**
  325. * 手机号登录 静默授权绑定关系
  326. * @param $code
  327. * @param $spread
  328. * @return mixed
  329. */
  330. public function silenceAuthBindingPhone($code, $spread, $spid, $phone)
  331. {
  332. $userInfoConfig = MiniProgramService::getUserInfo($code);
  333. if (!isset($userInfoConfig['openid'])) {
  334. throw new ValidateException('静默授权失败');
  335. }
  336. $routineInfo = [
  337. 'unionid' => $userInfoConfig['unionid'] ?? null
  338. ];
  339. /** @var QrcodeServices $qrcode */
  340. $qrcode = app()->make(QrcodeServices::class);
  341. if ($spread && ($info = $qrcode->getOne(['id' => $spread, 'status' => 1]))) {
  342. $spid = $info['third_id'];
  343. }
  344. $openid = $userInfoConfig['openid'];
  345. $routineInfo['openid'] = $openid;
  346. $routineInfo['headimgurl'] = sys_config('h5_avatar');
  347. $routineInfo['phone'] = $phone;
  348. /** @var WechatUserServices $wechatUserServices */
  349. $wechatUserServices = app()->make(WechatUserServices::class);
  350. $createData = [$openid, $routineInfo, $spid, '', 'routine'];
  351. //写入用户信息
  352. $user = $wechatUserServices->wechatOauthAfter($createData);
  353. $token = $this->createToken((int)$user['uid'], 'routine');
  354. if ($token) {
  355. return $token;
  356. } else
  357. throw new ValidateException('登录失败');
  358. }
  359. /**
  360. * 自动获取手机号绑定
  361. * @param $code
  362. * @param $spread
  363. * @return mixed
  364. */
  365. public function authBindingPhone($code, $iv, $encryptedData, $spread, $spid, $key = '')
  366. {
  367. $wechatInfo = [];
  368. $userType = $login_type = 'routine';
  369. if ($key) {
  370. [$openid, $wechatInfo, $spreadId, $login_type, $userType] = $createData = CacheService::getTokenBucket($key);
  371. }
  372. try {
  373. $userInfoCong = MiniProgramService::getUserInfo($code);
  374. $session_key = $userInfoCong['session_key'];
  375. } catch (\Exception $e) {
  376. throw new ValidateException('获取session_key失败,请检查您的配置!:' . $e->getMessage() . 'line' . $e->getLine());
  377. }
  378. try {
  379. //解密获取用户信息
  380. $userInfo = MiniProgramService::encryptor($session_key, $iv, $encryptedData);
  381. } catch (\Exception $e) {
  382. if ($e->getCode() == '-41003') {
  383. throw new ValidateException('获取会话密匙失败');
  384. }
  385. }
  386. if (!$userInfo || !isset($userInfo['purePhoneNumber'])) {
  387. throw new ValidateException('获取用户信息失败');
  388. }
  389. if ($spid) {
  390. $spreadId = $spid;
  391. }
  392. /** @var QrcodeServices $qrcode */
  393. $qrcode = app()->make(QrcodeServices::class);
  394. if ($spread && ($info = $qrcode->getOne(['id' => $spread, 'status' => 1]))) {
  395. $spreadId = $info['third_id'];
  396. }
  397. $openid = $userInfoCong['openid'];
  398. $wechatInfo['openid'] = $openid;
  399. $wechatInfo['unionid'] = $userInfoCong['unionid'] ?? '';
  400. $wechatInfo['spid'] = $spreadId;
  401. $wechatInfo['code'] = $spread;
  402. $wechatInfo['session_key'] = $session_key;
  403. $wechatInfo['phone'] = $userInfo['purePhoneNumber'];
  404. /** @var WechatUserServices $wechatUserServices */
  405. $wechatUserServices = app()->make(WechatUserServices::class);
  406. //写入用户信息
  407. $user = $wechatUserServices->wechatOauthAfter([$openid, $wechatInfo, $spreadId, $login_type, $userType]);
  408. $token = $this->createToken((int)$user['uid'], 'routine');
  409. if ($token) {
  410. return [
  411. 'token' => $token['token'],
  412. 'userInfo' => $user,
  413. 'expires_time' => $token['params']['exp'],
  414. ];
  415. } else
  416. throw new ValidateException('登录失败');
  417. }
  418. public function updateUserInfo($uid, array $data)
  419. {
  420. /** @var UserServices $userServices */
  421. $userServices = app()->make(UserServices::class);
  422. $user = $userServices->getUserInfo($uid);
  423. if (!$user) {
  424. throw new ValidateException('数据不存在');
  425. }
  426. $userInfo = [];
  427. $userInfo['nickname'] = filter_emoji($data['nickName'] ?? '');//姓名
  428. $userInfo['sex'] = $data['gender'] ?? '';//性别
  429. $userInfo['language'] = $data['language'] ?? '';//语言
  430. $userInfo['city'] = $data['city'] ?? '';//城市
  431. $userInfo['province'] = $data['province'] ?? '';//省份
  432. $userInfo['country'] = $data['country'] ?? '';//国家
  433. $userInfo['headimgurl'] = $data['avatarUrl'] ?? '';//头像
  434. $userInfo['is_complete'] = 1;
  435. /** @var LoginServices $loginService */
  436. $loginService = app()->make(LoginServices::class);
  437. $loginService->updateUserInfo($userInfo, $user);
  438. //更新用户信息
  439. if (!$this->dao->update(['uid' => $user['uid'], 'user_type' => 'routine'], $userInfo)) {
  440. throw new ValidateException('更新失败');
  441. }
  442. return true;
  443. }
  444. }