WechatUserServices.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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 qiniu\basic\BaseServices;
  14. use app\model\wechat\WechatUser;
  15. use qiniu\exceptions\AdminException;
  16. use qiniu\exceptions\AuthException;
  17. use qiniu\services\wechat\OfficialAccount;
  18. use think\db\exception\DataNotFoundException;
  19. use think\db\exception\DbException;
  20. use think\db\exception\ModelNotFoundException;
  21. use think\exception\ValidateException;
  22. /**
  23. *
  24. * Class WechatUserServices
  25. * @package app\services\wechat
  26. * @mixin WechatUser
  27. */
  28. class WechatUserServices extends BaseServices
  29. {
  30. /**
  31. * WechatUserServices constructor.
  32. * @param WechatUser $model
  33. */
  34. public function __construct(WechatUser $model)
  35. {
  36. $this->model = $model;
  37. }
  38. public function getColumnUser($user_ids, $column, $key, string $user_type = 'wechat')
  39. {
  40. return $this->getColumn([['uid', 'IN', $user_ids], ['user_type', '=', $user_type]], $column, $key);
  41. }
  42. /**
  43. * 获取单个微信用户
  44. * @param array $where
  45. * @param string $field
  46. * @return array
  47. * @throws DataNotFoundException
  48. * @throws DbException
  49. * @throws ModelNotFoundException
  50. */
  51. public function getWechatUserInfo(array $where, $field = '*')
  52. {
  53. return $this->getOne($where, $field);
  54. }
  55. /**
  56. * 用uid获得 微信openid
  57. * @param int $uid
  58. * @param string $userType
  59. * @return mixed
  60. * @throws DataNotFoundException
  61. * @throws DbException
  62. * @throws ModelNotFoundException
  63. */
  64. public function uidToOpenid(int $uid, string $userType = 'wechat')
  65. {
  66. return $this->getOne(['uid' => $uid, 'user_type' => $userType])['openid'] ?? null;
  67. }
  68. /**
  69. * 用openid获得uid
  70. * @param $openid
  71. * @param string $openidType
  72. * @return mixed
  73. * @throws DataNotFoundException
  74. * @throws DbException
  75. * @throws ModelNotFoundException
  76. */
  77. public function openidToUid($openid, string $openidType = 'openid')
  78. {
  79. $uid = $this->getOne([[$openidType, '=', $openid], ['user_type', '<>', 'h5']])['uid'] ?? 0;
  80. if (!$uid)
  81. throw new AdminException('对应的uid不存在');
  82. return $uid;
  83. }
  84. /**
  85. * 获取用户信息
  86. * @param $openid
  87. * @return array|mixed
  88. * @throws DataNotFoundException
  89. * @throws DbException
  90. * @throws ModelNotFoundException
  91. */
  92. public function getAuthUserInfo($openid)
  93. {
  94. $user = [];
  95. if ($openid) {
  96. $uid = $this->model->getOneValue(['unionid|openid' => $openid], 'uid');
  97. /** @var UserServices $userServices */
  98. $userServices = app()->make(UserServices::class);
  99. $user = $userServices->getUserInfo($uid);
  100. if (isset($user['status']) && !$user['status'])
  101. throw new AuthException('您已被禁止登录,请联系管理员', 410020);
  102. }
  103. return $user;
  104. }
  105. /**
  106. * 更新微信用户信息
  107. * @param $event
  108. * @return bool
  109. */
  110. public function wechatUpdata($data)
  111. {
  112. [$uid, $userData] = $data;
  113. /** @var UserServices $userServices */
  114. $userServices = app()->make(UserServices::class);
  115. if (!$userInfo = $userServices->getUserInfo($uid)) {
  116. return false;
  117. }
  118. /** @var LoginServices $loginService */
  119. $loginService = app()->make(LoginServices::class);
  120. $loginService->updateUserWechatLogin($uid, $userData, $userInfo);
  121. //更新用户信息
  122. /** @var WechatUserServices $wechatUser */
  123. $wechatUser = app()->make(WechatUserServices::class);
  124. $wechatUserInfo = [];
  125. if (isset($userData['nickname']) && $userData['nickname']) $wechatUserInfo['nickname'] = filter_emoji($userData['nickname'] ?? '');//姓名
  126. if (isset($userData['headimgurl']) && $userData['headimgurl']) $wechatUserInfo['headimgurl'] = $userData['headimgurl'] ?? '';//头像
  127. if (isset($userData['sex']) && $userData['sex']) $wechatUserInfo['sex'] = $userData['gender'] ?? '';//性别
  128. if (isset($userData['language']) && $userData['language']) $wechatUserInfo['language'] = $userData['language'] ?? '';//语言
  129. if (isset($userData['city']) && $userData['city']) $wechatUserInfo['city'] = $userData['city'] ?? '';//城市
  130. if (isset($userData['province']) && $userData['province']) $wechatUserInfo['province'] = $userData['province'] ?? '';//省份
  131. if (isset($userData['country']) && $userData['country']) $wechatUserInfo['country'] = $userData['country'] ?? '';//国家
  132. if (!empty($wechatUserInfo['nickname']) || !empty($wechatUserInfo['headimgurl'])) {
  133. $wechatUserInfo['is_complete'] = 1;
  134. } else {
  135. $wechatUserInfo['is_complete'] = 0;
  136. }
  137. if ($wechatUserInfo) {
  138. if (isset($userData['openid']) && $userData['openid'] && false === $wechatUser->update(['uid' => $userInfo['uid'], 'openid' => $userData['openid']], $wechatUserInfo)) {
  139. throw new ValidateException('更新失败');
  140. }
  141. }
  142. return true;
  143. }
  144. /**
  145. * 微信授权成功后
  146. * @param array $data
  147. * @return mixed
  148. * @throws DataNotFoundException
  149. * @throws DbException
  150. * @throws ModelNotFoundException
  151. */
  152. public function wechatOauthAfter(array $data)
  153. {
  154. [$openid, $wechatInfo, $spread_uid, $login_type, $userType] = $data;
  155. /** @var UserServices $userServices */
  156. $userServices = app()->make(UserServices::class);
  157. if ($spread_uid && !$userServices->userExist((int)$spread_uid)) {
  158. $spread_uid = 0;
  159. }
  160. //删除多余字段
  161. unset($wechatInfo['subscribe_scene'], $wechatInfo['qr_scene'], $wechatInfo['qr_scene_str']);
  162. if ($login_type) {
  163. $wechatInfo['login_type'] = $login_type;
  164. }
  165. if (!isset($wechatInfo['nickname']) || !$wechatInfo['nickname']) {
  166. if (isset($wechatInfo['phone']) && $wechatInfo['phone']) {
  167. $wechatInfo['nickname'] = substr_replace($wechatInfo['phone'], '****', 3, 4);
  168. } else {
  169. mt_srand();
  170. $wechatInfo['nickname'] = 'wx' . rand(100000, 999999);
  171. }
  172. } else {
  173. $wechatInfo['is_complete'] = 1;
  174. $wechatInfo['nickname'] = filter_emoji($wechatInfo['nickname']);
  175. }
  176. $userInfo = [];
  177. if (isset($wechatInfo['phone']) && $wechatInfo['phone']) {
  178. $userInfo = $userServices->getOne(['phone' => $wechatInfo['phone']]);
  179. }
  180. if (!$userInfo) {
  181. if (isset($wechatInfo['unionid']) && $wechatInfo['unionid']) {
  182. $uid = $this->getOneValue(['unionid' => $wechatInfo['unionid']], 'uid');
  183. if ($uid) {
  184. $userInfo = $userServices->getOne(['uid' => $uid]);
  185. } else {
  186. $userInfo = $this->getAuthUserInfo($openid);
  187. }
  188. } else {
  189. $userInfo = $this->getAuthUserInfo($openid);
  190. }
  191. }
  192. $uid = (int)($userInfo['uid'] ?? 0);
  193. $wechatInfo['user_type'] = $userType;
  194. return $this->transaction(function () use ($openid, $uid, $userInfo, $wechatInfo, $userServices, $spread_uid, $userType) {
  195. $wechatInfo['uid'] = $uid;
  196. if ($userInfo) {
  197. if (isset($userInfo['status']) && !$userInfo['status'])
  198. throw new ValidateException('您已被禁止登录,请联系管理员');
  199. //更新用户表
  200. /** @var LoginServices $loginService */
  201. $loginService = app()->make(LoginServices::class);
  202. $loginService->updateUserWechatLogin($uid, $wechatInfo, $userInfo);
  203. if ($spread_uid > 0) {
  204. /** @var UserSpreadServices $spreadService */
  205. $spreadService = app()->make(UserSpreadServices::class);
  206. $spreadService->setSpread($userInfo['uid'], $spread_uid);
  207. }
  208. } else {
  209. //新增用户表
  210. $userInfo = $userServices->setUserInfo($wechatInfo, (int)$spread_uid, $userType);
  211. if (!$userInfo) {
  212. throw new AuthException('生成用户失败!');
  213. }
  214. }
  215. $uid = $userInfo['uid'];
  216. $wechatInfo['uid'] = $userInfo->uid;
  217. $wechatInfo['add_time'] = $userInfo->add_time;
  218. //判断该类性用户在wechatUser中是否存在
  219. $wechatUser = [];
  220. if (!empty($wechatInfo['unionid'])) {
  221. $wechatUser = $this->getOne(['unionid' => $wechatInfo['unionid']]);
  222. }
  223. if (!$wechatUser) {
  224. $wechatUser = $this->getOne(['openid' => $openid]);
  225. }
  226. if ($wechatUser) {
  227. //更换微信登录情况
  228. if (!$this->update($wechatUser['id'], $wechatInfo, 'id')) {
  229. throw new ValidateException('更新数据失败');
  230. }
  231. } else {
  232. if (!$this->save($wechatInfo)) {
  233. throw new AuthException('生成微信用户失败!');
  234. }
  235. }
  236. return $userInfo;
  237. });
  238. }
  239. /**
  240. * 更新用户信息
  241. * @param $openid
  242. * @param string $phone
  243. * @return bool
  244. */
  245. public function updateWecahtUser($openid)
  246. {
  247. try {
  248. $userInfo = OfficialAccount::getUserInfo($openid);
  249. } catch (\Throwable $e) {
  250. $userInfo = [];
  251. }
  252. if (isset($userInfo['nickname']) && $userInfo['nickname']) {
  253. $userInfo['nickname'] = filter_emoji($userInfo['nickname']);
  254. } else {
  255. if (isset($userInfo['nickname'])) unset($userInfo['nickname']);
  256. }
  257. if (isset($userInfo['tagid_list'])) {
  258. $userInfo['tagid_list'] = implode(',', $userInfo['tagid_list']);
  259. }
  260. if ($userInfo && !$this->update($openid, $userInfo, 'openid'))
  261. throw new AdminException('更新失败');
  262. return true;
  263. }
  264. /**
  265. * 添加新用户
  266. * @param $openid
  267. * @param int $spread_uid
  268. * @param array $append 追加字段
  269. * @return \app\services\user\User|\think\Model
  270. * @throws \think\db\exception\DataNotFoundException
  271. * @throws \think\db\exception\DbException
  272. * @throws \think\db\exception\ModelNotFoundException
  273. */
  274. public function setNewUser($openid, $spread_uid = 0, array $append = [])
  275. {
  276. try {
  277. $wechatInfo = OfficialAccount::getUserInfo($openid);
  278. } catch (\Throwable $e) {
  279. $wechatInfo = [];
  280. }
  281. if (!isset($wechatInfo['openid']))
  282. throw new ValidateException('请关注公众号!');
  283. if (isset($wechatInfo['nickname']) && $wechatInfo['nickname']) {
  284. $wechatInfo['is_complete'] = 1;
  285. } else {
  286. //昵称不存在的信息不完整
  287. $wechatInfo['is_complete'] = 0;
  288. mt_srand();
  289. $wechatInfo['nickname'] = 'wx' . rand(100000, 999999);
  290. }
  291. if (isset($wechatInfo['tagid_list'])) {
  292. $wechatInfo['tagid_list'] = implode(',', $wechatInfo['tagid_list']);
  293. }
  294. $uid = 0;
  295. $userType = 'wechat';
  296. $userInfo = [];
  297. /** @var UserServices $userServices */
  298. $userServices = app()->make(UserServices::class);
  299. if (isset($append['phone']) && $append['phone']) {
  300. $userInfo = $userServices->getOne(['phone' => $append['phone']]);
  301. $wechatInfo['phone'] = $append['phone'];
  302. }
  303. if (!$userInfo) {
  304. if (isset($wechatInfo['unionid']) && $wechatInfo['unionid']) {
  305. $uid = $this->getOneValue(['unionid' => $wechatInfo['unionid']], 'uid');
  306. if ($uid) {
  307. $userInfo = $userServices->getOne(['uid' => $uid]);
  308. }
  309. } else {
  310. $userInfo = $this->getAuthUserInfo($openid);
  311. }
  312. }
  313. if ($userInfo) {
  314. $uid = (int)$userInfo['uid'];
  315. if (isset($userInfo['status']) && !$userInfo['status'])
  316. throw new ValidateException('您已被禁止登录,请联系管理员');
  317. }
  318. $wechatInfo['user_type'] = $userType;
  319. if ($userInfo) {
  320. //更新用户表和wechat_user表
  321. //判断该类性用户在wechatUser中是否存在
  322. $wechatUser = $this->getOne(['uid' => $uid, 'user_type' => $userType]);
  323. if ($wechatUser) {
  324. $wechatUser = $this->getOne(['openid' => $openid]);
  325. }
  326. /** @var LoginServices $loginService */
  327. $loginService = app()->make(LoginServices::class);
  328. $this->transaction(function () use ($openid, $loginService, $wechatInfo, $userInfo, $uid, $userType, $spread_uid, $wechatUser) {
  329. $wechatInfo['spread_uid'] = $spread_uid;
  330. $wechatInfo['uid'] = $uid;
  331. $loginService->updateUserWechatLogin($wechatInfo, $userInfo);
  332. if ($wechatUser) {
  333. //更换微信登录情况
  334. if (!$this->update($wechatUser['id'], $wechatInfo, 'id')) {
  335. throw new ValidateException('更新数据失败');
  336. }
  337. } else {
  338. if (!$this->save($wechatInfo)) {
  339. throw new ValidateException('写入信息失败');
  340. }
  341. }
  342. });
  343. } else {
  344. //user表没有用户,wechat_user表没有用户创建新用户
  345. //不存在则创建用户
  346. $userInfo = $this->transaction(function () use ($openid, $userServices, $wechatInfo, $spread_uid, $userType) {
  347. $userInfo = $userServices->setUserInfo($wechatInfo, (int)$spread_uid, $userType);
  348. if (!$userInfo) {
  349. throw new AuthException('生成User用户失败!');
  350. }
  351. $wechatInfo['uid'] = $userInfo->uid;
  352. $wechatInfo['add_time'] = $userInfo->add_time;
  353. $wechatUser = $this->getOne(['openid' => $openid]);
  354. if ($wechatUser) {
  355. if (!$this->update($wechatUser['id'], $wechatInfo, 'id')) {
  356. throw new ValidateException('更新数据失败');
  357. }
  358. } else {
  359. if (!$this->save($wechatInfo)) {
  360. throw new AuthException('生成微信用户失败!');
  361. }
  362. }
  363. return $userInfo;
  364. });
  365. }
  366. return $userInfo;
  367. }
  368. /**
  369. * 用户存在就更新 不存在就添加
  370. * @param $openid
  371. * @param int $spread_uid
  372. * @param string $phone
  373. * @return \app\services\user\User|array|\think\Model|null
  374. * @throws \think\db\exception\DataNotFoundException
  375. * @throws \think\db\exception\DbException
  376. * @throws \think\db\exception\ModelNotFoundException
  377. */
  378. public function saveUser($openid, $spread_uid = 0, $phone = '')
  379. {
  380. /** @var UserServices $userServices */
  381. $userServices = app()->make(UserServices::class);
  382. $wechatUser = $this->getOne(['openid' => $openid]);
  383. if ($wechatUser && $wechatUser['uid']) {
  384. $userInfo = $userServices->getUserInfo((int)$wechatUser['uid']);
  385. $this->updateWecahtUser($openid);
  386. } else {
  387. $userInfo = $this->setNewUser($openid, $spread_uid, ['phone' => $phone]);
  388. }
  389. return $userInfo;
  390. }
  391. }