UserMp.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. <?php
  2. /**
  3. * @package merchant
  4. *
  5. * @author xaboy
  6. * @day 2020/6/18
  7. *
  8. *
  9. */
  10. namespace app\controller\api\user;
  11. use app\common\dao\user\UnionUsersDao;
  12. use app\common\repositories\article\AgreementRepository;
  13. use app\common\repositories\merchant\order\OrderMerchantRepository;
  14. use app\common\repositories\user\UnionUsersRepository;
  15. use applet\WXBizDataCrypt;
  16. use crmeb\basic\BaseController;
  17. use app\common\repositories\user\UserRepository;
  18. use crmeb\services\MiniProgramService;
  19. use think\App;
  20. use think\Exception;
  21. use think\facade\Cache;
  22. use think\facade\Db;
  23. use think\facade\Log;
  24. class UserMp extends BaseController
  25. {
  26. public $repository;
  27. private $appid;
  28. private $secret;
  29. protected $merId;
  30. protected $source;
  31. public function __construct(App $app, UserRepository $repository)
  32. {
  33. parent::__construct($app);
  34. $this->repository = $repository;
  35. $this->source = $this->request->header('source');
  36. $this->merId = $this->request->header('merId');
  37. //点餐小程序
  38. // $this->appid = 'wx10669a2eca032216';
  39. // $this->secret = '0e71d5c636fdb9bf1c79c403db70f739';
  40. // $this->appid = 'wx7b4d857deb0447f3';
  41. // $this->secret = '643efbd7f3cd6398df1e7adb441afceb';
  42. $this->appid = 'wx9082e5ac2fdb513f';
  43. $this->secret = 'e334c41e1c4aa962f65d1882092fbda6';
  44. }
  45. public function getUserUnionid(){
  46. $data = $this->request->params(['code','source']);
  47. if(!$data['code'] || $data['code'] == '' || $data['code'] =='undefined') {
  48. return app('json')->fail("异常操作");
  49. }
  50. // $appid = 'wx7b4d857deb0447f3';
  51. // $secret = '643efbd7f3cd6398df1e7adb441afceb';
  52. $appid = 'wx9082e5ac2fdb513f';
  53. $secret = 'e334c41e1c4aa962f65d1882092fbda6';
  54. $url = "https://api.weixin.qq.com/sns/jscode2session?appid=".$appid."&secret=".$secret."&js_code=".$data['code']."&grant_type=authorization_code";
  55. $get = curlGet($url);
  56. if(!$get){
  57. return app('json')->fail($url);
  58. }
  59. $get['cache_key'] = md5(time() . $data['code']);
  60. try {
  61. Cache::set('mp_code_' . $get['cache_key'], $get['session_key'], 86400);
  62. }catch (\Exception $exception) {
  63. Log::error($exception->getMessage());
  64. }
  65. return app('json')->success($get);
  66. }
  67. /**
  68. * 小程序一键登录(合并 getUserUnionid + applet_phone)
  69. * 接收 code、encryptedData、iv,内部调用微信接口获取 session_key,解密手机号后注册/登录
  70. * @param UserRepository $repository
  71. * @return \think\response\Json
  72. */
  73. public function mpLogin(UserRepository $repository)
  74. {
  75. try {
  76. $data = $this->request->params(['code', 'encryptedData', 'iv', 'share_id', 'source']);
  77. if (!$data['code'] || $data['code'] == '' || $data['code'] == 'undefined') {
  78. return app('json')->fail('code参数缺失');
  79. }
  80. if (!$data['encryptedData'] || $data['encryptedData'] == '') {
  81. return app('json')->fail('encryptedData参数缺失');
  82. }
  83. if (!$data['iv'] || $data['iv'] == '') {
  84. return app('json')->fail('iv参数缺失');
  85. }
  86. $appid = 'wx9082e5ac2fdb513f';
  87. $secret = 'e334c41e1c4aa962f65d1882092fbda6';
  88. // 1. 调用微信 jscode2session 接口获取 session_key 和 openid
  89. $url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $appid . "&secret=" . $secret . "&js_code=" . $data['code'] . "&grant_type=authorization_code";
  90. $wxResult = curlGet($url);
  91. if (!$wxResult || !isset($wxResult['session_key'])) {
  92. Db::name('log')->insert(['data' => 'mpLogin jscode2session返回:' . json_encode($wxResult)]);
  93. Log::error('mpLogin jscode2session失败: ' . json_encode($wxResult));
  94. return app('json')->fail('微信登录凭证校验失败');
  95. }
  96. $sessionKey = $wxResult['session_key'];
  97. $openid = $wxResult['openid'] ?? '';
  98. // 2. 解密手机号
  99. $sessionKey = str_replace(' ', '+', $sessionKey);
  100. $encryptedData = str_replace(' ', '+', $data['encryptedData']);
  101. $iv = str_replace(' ', '+', $data['iv']);
  102. $pc = new WXBizDataCrypt($appid, $sessionKey);
  103. $errCode = $pc->decryptData($encryptedData, $iv, $decryptData);
  104. if ($errCode != 0) {
  105. Db::name('log')->insert(['data' => 'mpLogin手机号解密失败,errCode:' . $errCode . ',sessionKey:' . $sessionKey . ',encryptedData:' . $data['encryptedData'] . ',iv:' . $data['iv']]);
  106. return app('json')->fail('手机号解密失败');
  107. }
  108. Db::name('log')->insert(['data' => 'mpLogin一键登录获取的数据:' . $decryptData]);
  109. $decryptData = json_decode($decryptData, true);
  110. $phone = $decryptData['purePhoneNumber'] ?? '';
  111. if ($phone == '') {
  112. return app('json')->fail('未获取到手机号');
  113. }
  114. if (!preg_match("/^1[3456789]{1}\d{9}$/", $phone) && !preg_match("/^[569]\d{7}$/", $phone)) {
  115. return app('json')->fail('手机号格式错误');
  116. }
  117. // 3. 注册或登录
  118. $userRes = Db::name('user')->where('account', $phone)->find();
  119. $isnew = false;
  120. if (!$userRes) {
  121. $spreadUid = 0;
  122. if (!empty($data['share_id'])) {
  123. $spreadUid = Db::name('product_share')->where('id', $data['share_id'])->value('uid');
  124. if (!intval($spreadUid)) {
  125. $spreadUid = 0;
  126. }
  127. }
  128. $repository->registr($phone, 123456, 'APP', '', '', '', $spreadUid);
  129. $isnew = true;
  130. }
  131. $user = $repository->accountByUser($phone);
  132. // 企业用户关联逻辑(与 Auth::applet_phone 保持一致)
  133. if ($this->source == 'yhc' && $this->merId) {
  134. $where = ['mer_id' => $this->merId, 'uid' => $user['uid']];
  135. $count = Db::name('enterprise_user')->where($where)->count();
  136. if ($count < 1) {
  137. $insert = ['mer_id' => $this->merId, 'uid' => $user['uid']];
  138. $epData = $this->request->params(['spread', 'share_id']);
  139. if (isset($epData['spread']) && $epData['spread']) {
  140. $insert['puid'] = $epData['spread'];
  141. $insert['node_uid'] = $epData['spread'];
  142. } else if (isset($epData['share_id']) && $epData['share_id']) {
  143. $spreadUid = Db::name('product_share')->where('id', $epData['share_id'])->value('uid');
  144. $insert['puid'] = $spreadUid;
  145. $insert['node_uid'] = $spreadUid;
  146. }
  147. if (!isset($insert['node_uid']) || !$insert['node_uid']) {
  148. return app('json')->fail('必须要有邀请人才能注册', ['is' => 1]);
  149. }
  150. if (isset($epData['spread']) && isset($zhuce)) {
  151. $insert['puid'] = $epData['spread'];
  152. $insert['node_uid'] = $epData['spread'];
  153. }
  154. Db::name('enterprise_user')->insert($insert);
  155. }
  156. }
  157. $user = $repository->mainUser($user);
  158. $tokenInfo = $repository->createToken($user);
  159. $repository->loginAfter($user);
  160. return app('json')->success(array_merge($repository->returnToken($user, $tokenInfo), [
  161. 'is_new' => $isnew ? 1 : 0,
  162. 'openid' => $openid,
  163. ]));
  164. } catch (\Exception $e) {
  165. Db::name('log')->insert(['data' => 'mpLogin出错:' . $e->getFile() . ':' . $e->getLine() . '【' . $e->getMessage() . '】']);
  166. return app('json')->fail('登录失败');
  167. }
  168. }
  169. public function getPhoneToBind(){
  170. $data = $this->request->params([
  171. 'cache_key',
  172. 'iv',
  173. 'encryptedData',
  174. 'third_user_id',
  175. 'source'
  176. ]);
  177. $session_key = Cache::get('mp_code_' . $data['cache_key']);
  178. $appid = $this -> appid;
  179. $secret = $this -> secret;
  180. if($data['source'] && $data['source'] == 'cxb'){
  181. $appid = env('WECHAT_MP.APPID');
  182. $secret = env('WECHAT_MP.SECRET');
  183. }
  184. //解密获取用户信息urldecode
  185. $returnCode = $this -> decryptData($session_key,$data['encryptedData'],$data['iv'],$userInfo,$appid);
  186. if($returnCode != 0){
  187. return app('json')->fail($returnCode);
  188. }
  189. $userInfo = json_decode($userInfo,true);
  190. if (!$userInfo || !isset($userInfo['purePhoneNumber'])) return app('json')->fail('手机号码获取失败');
  191. $phone = $userInfo['purePhoneNumber'];
  192. $repository = app()->make(UserRepository::class);
  193. $user = $repository->thirdBinding($phone, false,'MP',$data['third_user_id'],1,"http://". $this->request->host(true));//2222
  194. if($user){
  195. $userRepository = app()->make(UserRepository::class);
  196. $userInfo1 = $userRepository->getOne(['uid' => $user['uid']]);
  197. //绑定线下充值金额
  198. $unionUsersRepository = app()->make(UnionUsersRepository::class);
  199. $orderMerchantRepository = app()->make(OrderMerchantRepository::class);
  200. $notBind = $unionUsersRepository->getAllNotBind($data['third_user_id']);
  201. if ($notBind) {
  202. $orderMerchantRepository->doBindUser($userInfo1, 1);
  203. $userAccount = Db::name("UserAccount");
  204. $userAccount -> insert(['type'=>1,'uid'=>$user['uid'],'nickname'=>$notBind['nickname'],'avater'=>$notBind['avatar']]);
  205. }
  206. $user = $repository->accountByUser($userInfo['purePhoneNumber']);
  207. $tokenInfo = $repository->createToken($user);
  208. $repository->loginAfter($user);
  209. return app('json')->success($repository->returnToken($user, $tokenInfo));
  210. }else{
  211. return app('json')->fail("绑定失败");
  212. }
  213. }
  214. public function getUser(){
  215. $data = $this->request->params(['unionid','nickname','avatar']);
  216. if(!$data['unionid'] || $data['unionid'] == '' || $data['unionid'] =='undefined'){
  217. return app('json')->fail("异常操作");
  218. }
  219. $repository = app()->make(UserRepository::class);
  220. $result = $repository ->wechatCheck($data['unionid']);
  221. if(isset($result['code']) && $result['code'] == 200){
  222. //用户已注册并绑定了手机号码
  223. $user = $repository->accountByUser($result['user']['account']);
  224. $tokenInfo = $repository->createToken($user);
  225. $repository->loginAfter($user);
  226. return app('json')->success($repository->returnToken($user, $tokenInfo));
  227. }
  228. else{
  229. try {
  230. if($data['avatar'] && $data['avatar'] != ''){
  231. $data['avatar'] = str_replace('"', '', $data['avatar']);
  232. }
  233. Db::transaction(function () use ($data,$repository) {
  234. $unionData = [
  235. 'unionid' => $data['unionid'],
  236. 'nickname' => $data['nickname'] ? : time(),
  237. 'avatar' => $data['avatar'] ? : 'https://cdn.bjtdba.com/vod/image/2025-01-21/20250121180855764.png',
  238. 'is_lock' => 1,
  239. 'lock_time' => date('Y-m-d H:i:s'),
  240. 'balance' => 0,
  241. 'give_money' => 0,
  242. 'pension' => 0,
  243. 'type' => 1,
  244. ];
  245. $unionUsersDao = app()->make(UnionUsersDao::class);
  246. $unionUsersRepository = app()->make(UnionUsersRepository::class);
  247. $unionUser = $unionUsersRepository->getWhere(['unionid' => $data['unionid']]);
  248. if (!$unionUser) {
  249. $unionUsersDao->create($unionData);
  250. } else {
  251. $updateData = [
  252. 'nickname' => $data['nickname'] ? : time(),
  253. 'avatar' => $data['avatar'] ? : 'https://cdn.bjtdba.com/vod/image/2025-01-21/20250121180855764.png',
  254. 'update_time' => date('Y-m-d H:i:s')
  255. ];
  256. $unionUsersDao->update($unionUser->id, $updateData);
  257. }
  258. });
  259. } catch (\Throwable $e) {
  260. Log::info($e->getMessage());
  261. }
  262. }
  263. return app("json")->fail($result['msg']);
  264. }
  265. /**
  266. * 检验数据的真实性,并且获取解密后的明文.
  267. * @param $sessionKey string sessionKey
  268. * @param $encryptedData string 加密的用户数据
  269. * @param $iv string 与用户数据一同返回的初始向量
  270. * @param $data string 解密后的原文
  271. *
  272. * @return int 成功0,失败返回对应的错误码
  273. */
  274. public function decryptData($sessionKey,$encryptedData, $iv, &$data, $appid)
  275. {
  276. if (strlen($sessionKey) != 24) {
  277. return -41001;
  278. }
  279. $aesKey=base64_decode($sessionKey);
  280. if (strlen($iv) != 24) {
  281. return -41002;
  282. }
  283. $aesIV=base64_decode($iv);
  284. $aesCipher=base64_decode($encryptedData);
  285. $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
  286. $dataObj=json_decode( $result );
  287. if( $dataObj == NULL )
  288. {
  289. return -41003;
  290. }
  291. if( $dataObj->watermark->appid != $appid )
  292. {
  293. return -41003;
  294. }
  295. $data = $result;
  296. return 0;
  297. }
  298. }