MemberCpsAppService.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: dingran
  5. * Date: 2019/7/9
  6. * Time: 上午11:03
  7. */
  8. namespace app\frontend\modules\member\services;
  9. use app\backend\modules\charts\modules\phone\models\PhoneAttribution;
  10. use app\backend\modules\charts\modules\phone\services\PhoneAttributionService;
  11. use app\common\exceptions\AppException;
  12. use app\common\facades\Setting;
  13. use app\common\helpers\Client;
  14. use app\common\helpers\Url;
  15. use app\common\models\AccountWechats;
  16. use app\common\models\McMappingFans;
  17. use Illuminate\Support\Facades\Redis;
  18. use Yunshop\AggregationCps\models\MemberAggregationAppModel;
  19. use app\common\models\MemberGroup;
  20. use app\common\models\Store;
  21. use app\common\services\api\WechatApi;
  22. use app\frontend\models\Member;
  23. use app\frontend\models\MemberShopInfo;
  24. use app\frontend\modules\member\models\McMappingFansModel;
  25. use app\frontend\modules\member\models\MemberModel;
  26. use app\frontend\modules\member\models\MemberUniqueModel;
  27. use app\frontend\modules\member\models\MemberWechatModel;
  28. use app\frontend\modules\member\models\SubMemberModel;
  29. use Crypt;
  30. use Illuminate\Support\Str;
  31. use Yunshop\AggregationCps\models\MobileLoginRecordModel;
  32. use Yunshop\AggregationCps\services\CommonService;
  33. use Yunshop\AggregationCps\services\SettingManageService;
  34. use Yunshop\Commission\models\Agents;
  35. class MemberCpsAppService extends MemberService
  36. {
  37. public $uniacid;
  38. const LOGIN_TYPE = 15;
  39. /**
  40. * @return array
  41. * @throws AppException
  42. * @throws \app\common\exceptions\MemberErrorMsgException
  43. */
  44. public function login()
  45. {
  46. $mobile = \YunShop::request()->mobile;
  47. $password = \YunShop::request()->password;
  48. $code = \YunShop::request()->code;
  49. $weixin_code = \YunShop::request()->weixin_code;
  50. $this->uniacid = \YunShop::app()->uniacid;
  51. $uniacid = \YunShop::app()->uniacid;
  52. $page = \YunShop::request()->page ?: 0;
  53. $data = ['first_login' => 0];
  54. if (\Request::isMethod('post')) {
  55. if (!app('plugins')->isEnabled('aggregation-cps')) {
  56. return show_json(8, "聚合cps插件未开启");
  57. }
  58. //密码登录
  59. if (!empty($password)) {
  60. // 是否首次登陆
  61. if ($this->secondAuth($page, $mobile)) {
  62. $data['first_login'] = 1;
  63. }
  64. MemberService::validate($mobile, $password);
  65. $remain_time = $this->getLoginLimit($mobile);
  66. if($remain_time){
  67. return show_json(6, "账号锁定中,请".$remain_time."分钟后再登录");
  68. }
  69. $has_mobile = MemberModel::checkMobile($uniacid, $mobile);
  70. if (!empty($has_mobile)) {
  71. $password = md5($password . $has_mobile->salt);
  72. $member_info = MemberModel::getUserInfo($uniacid, $mobile, $password)->first();
  73. if (!$member_info) {
  74. $error_count = $this->setLoginLimit($mobile);
  75. if ($error_count > 0) {
  76. return show_json(6, "密码错误!你还剩" . $error_count . "次机会");
  77. } else {
  78. return show_json(6, "密码错误次数已达5次,您的账号已锁定,请30分钟之后登录!");
  79. }
  80. }
  81. $member_info = $member_info->toArray();
  82. } else {
  83. return show_json(7, '用户不存在');
  84. }
  85. }
  86. //验证码登录 member.register.alySendCode&mobile=&captcha=&sms_type=1
  87. if (!empty($code)) {
  88. // 首次登陆
  89. if ($this->secondAuth($page, $mobile)) {
  90. $data['first_login'] = 1;
  91. }
  92. $data['mobile'] = $mobile;
  93. $data['code'] = $code;
  94. self::validate($data);
  95. $check_code = MemberService::checkAppCode();
  96. if ($check_code['status'] != 1) {
  97. return show_json('6',$check_code['json']);
  98. }
  99. $member_info = MemberModel::checkMobile($this->uniacid, $data['mobile']);
  100. if (empty($member_info)) {
  101. $member_info = $this->register($data);
  102. }
  103. if(!empty($member_info)){
  104. $member_info = $member_info->toArray();
  105. } else {
  106. return show_json(6, "手机号或验证码错误");
  107. }
  108. }
  109. //微信授权登录
  110. if ($weixin_code) {
  111. $set = \Setting::get('plugin.aggregation-cps');
  112. $tokenurl = $this->_getTokenUrl($set['weixin_appid'], $set['weixin_secret'], $weixin_code);
  113. $token = \Curl::to($tokenurl)
  114. ->asJsonResponse(true)
  115. ->get();
  116. if (!empty($token) && !empty($token['errmsg']) && $token['errmsg'] == 'invalid code') {
  117. return show_json(5, 'token请求错误');
  118. }
  119. $userinfo = $this->getUserInfo($set['weixin_appid'], $set['weixin_secret'], $token);
  120. if (is_array($userinfo) && !empty($userinfo['errcode'])) {
  121. \Log::debug('微信登陆授权失败-', $userinfo);
  122. return show_json(5, '微信登陆授权失败');
  123. }
  124. $member_id = $this->memberLogin($userinfo);
  125. $member_info['uid'] = $member_id;
  126. }
  127. if (!empty($member_info)) {
  128. MemberService::countReset($mobile);
  129. $yz_member = MemberShopInfo::getMemberShopInfo($member_info['uid']);
  130. if (!empty($yz_member)) {
  131. if (!$yz_member->access_token_2) {
  132. $data['token'] = Client::create_token('yz');
  133. $yz_member->access_token_2 = $data['token'];
  134. $yz_member->save();
  135. }
  136. $set = \Setting::get('plugin.aggregation-cps');
  137. if (((!empty($password) || !empty($code)) && !$this->secondAuth($page, $mobile)) || $weixin_code) {
  138. $data['token'] = $yz_member->access_token_2;
  139. $data['uid'] = $yz_member->member_id;
  140. }
  141. $data['shop_name'] = \Setting::get('shop.shop.name') ?: '未设置商城名称';
  142. $data['ratio'] = (float)CommonService::getBuyRatio($set);
  143. $data['ratio_name'] = CommonService::getBuyName($set);
  144. $data['ratio_type'] = $set['buy_show'];
  145. $data['download_url'] = $set['download_url'];
  146. if (app('plugins')->isEnabled('commission')){
  147. $agent = Agents::uniacid()->where('member_id', $yz_member->member_id)->first();
  148. }
  149. $data['agent_ratio'] = empty($agent) ? 0 : (float)$set['commission']['rule']['level_'.$agent->agent_level_id]['first_level_rate'];
  150. } else {
  151. return show_json(7, '用户不存在');
  152. }
  153. // 是否首次登陆
  154. if ((!empty($password) || !empty($code)) && (($this->secondAuth($page, $mobile) && $page == 2) || !$this->secondAuth($page, $mobile))
  155. && !MobileLoginRecordModel::isExists($mobile)) {
  156. MobileLoginRecordModel::insertData([
  157. 'uniacid' => $uniacid,
  158. 'mobile' => $mobile
  159. ]);
  160. }
  161. return show_json(1, '', $data);
  162. }
  163. } else {
  164. return show_json(6, '手机号或密码错误');
  165. }
  166. }
  167. /**
  168. * 验证登录状态
  169. *
  170. * @return bool
  171. */
  172. public function checkLogged($login = null)
  173. {
  174. $token = \Yunshop::request()->yz_token;
  175. if (empty($token)) {
  176. return false;
  177. }
  178. $member = SubMemberModel::getMemberByNativeToken($token);
  179. \Log::debug('---------cps checkLogged--------', [$token, $member->member_id]);
  180. if (!is_null($member)) {
  181. return true;
  182. } else {
  183. return false;
  184. }
  185. }
  186. /**
  187. * @param $token
  188. * @return int
  189. * @throws AppException
  190. */
  191. public function getMemberId($token)
  192. {
  193. if (!$token) {
  194. return 0;
  195. }
  196. $member = SubMemberModel::getMemberByNativeToken($token);
  197. if (is_null($member)) {
  198. throw new AppException('token_invalid');
  199. }
  200. return $member->member_id;
  201. }
  202. public static function validate($data)
  203. {
  204. $data = array(
  205. 'mobile' => $data['mobile'],
  206. 'code' => $data['code'],
  207. );
  208. $rules = array(
  209. 'mobile' => 'regex:/^1\d{10}$/',
  210. 'code' => 'required|min:4|regex:/^[A-Za-z0-9@!#\$%\^&\*]+$/',
  211. );
  212. $message = array(
  213. 'regex' => ':attribute 格式错误',
  214. 'required' => ':attribute 不能为空',
  215. 'min' => ':attribute 最少4位'
  216. );
  217. $attributes = array(
  218. "mobile" => '手机号',
  219. 'code' => '短信验证码',
  220. );
  221. $validate = \Validator::make($data,$rules,$message,$attributes);
  222. if ($validate->fails()) {
  223. $warnings = $validate->messages();
  224. $show_warning = $warnings->first();
  225. return show_json('0', $show_warning);
  226. } else {
  227. return show_json('1');
  228. }
  229. }
  230. //注册
  231. public function register($data)
  232. {
  233. $array = array();
  234. //获取分组
  235. $array['default_groupid']= MemberGroup::getDefaultGroupId()->first();
  236. $array['member_set'] = \Setting::get('shop.member');
  237. if (isset($array['member_set']) && $array['member_set']['headimg']) {
  238. $array['avatar'] = replace_yunshop(tomedia($array['member_set']['headimg']));
  239. } else {
  240. $array['avatar'] = Url::shopUrl('static/images/photo-mr.jpg');
  241. }
  242. $array['data'] = array(
  243. 'uniacid' => $this->uniacid,
  244. 'mobile' => $data['mobile'],
  245. 'groupid' => $array['default_groupid']->id ? $array['default_groupid']->id : 0,
  246. 'createtime' => $_SERVER['REQUEST_TIME'],
  247. 'nickname' => $data['mobile'],
  248. 'avatar' => $array['avatar'],
  249. 'gender' => 0,
  250. 'residecity' => '',
  251. );
  252. $array['data']['salt'] = Str::random(8);
  253. $array['data']['password'] = md5(str_random(8) . $data['salt']);
  254. $array['memberModel'] = MemberModel::create($array['data']);
  255. $array['member_id'] = $array['memberModel']->uid;
  256. //手机归属地查询插入
  257. $array['phoneData'] = file_get_contents((new PhoneAttributionService())->getPhoneApi($data['mobile']));
  258. $array['phoneArray'] = json_decode($array['phoneData']);
  259. $array['phone']['uid'] = $array['member_id'];
  260. $array['phone']['uniacid'] = $this->uniacid;
  261. $array['phone']['province'] = $array['phoneArray']->data->province;
  262. $array['phone']['city'] = $array['phoneArray']->data->city;
  263. $array['phone']['sp'] = $array['phoneArray']->data->sp;
  264. $phoneModel = new PhoneAttribution();
  265. $phoneModel->updateOrCreate(['uid' => $data['mobile']], $array['phone']);
  266. //添加yz_member表
  267. $array['default_sub_group_id'] = MemberGroup::getDefaultGroupId()->first();
  268. if (!empty($array['default_sub_group_id'])) {
  269. $array['default_subgroup_id'] = $array['default_sub_group_id']->id;
  270. } else {
  271. $array['default_subgroup_id'] = 0;
  272. }
  273. $array['sub_data'] = array(
  274. 'member_id' => $array['member_id'],
  275. 'uniacid' => $this->uniacid,
  276. 'group_id' => $array['default_subgroup_id'],
  277. 'level_id' => 0,
  278. 'invite_code' => \app\frontend\modules\member\models\MemberModel::getUniqueInviteCode(),
  279. );
  280. SubMemberModel::insertData($array['sub_data']);
  281. //生成分销关系链
  282. Member::createRealtion($array['member_id']);
  283. $member = MemberModel::checkMobile($this->uniacid, $data['mobile']);
  284. event(new \app\common\events\member\RegisterMember(0, $array['member_id']));
  285. //dd($array);
  286. return $member;
  287. }
  288. /**
  289. * app获取用户信息并存储
  290. * @param $token
  291. * @param $openid
  292. * @param $uuid
  293. * @return int
  294. * @throws AppException
  295. * @throws \app\common\exceptions\MemberErrorMsgException
  296. */
  297. public function app_get_userinfo($token, $openid, $uuid)
  298. {
  299. //通过接口获取用户信息
  300. $url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $token . '&openid=' . $openid;
  301. $user_info = \Curl::to($url)
  302. ->asJsonResponse(true)
  303. ->get();
  304. if (!empty($uuid)) {
  305. $user_info['uuid'] = $uuid;
  306. }
  307. if (!empty($user_info)) {
  308. return $this->memberLogin($user_info);
  309. } else {
  310. throw new AppException('微信授权验证失败');
  311. }
  312. }
  313. /**
  314. * 获取用户信息
  315. *
  316. * @param $appId
  317. * @param $appSecret
  318. * @param $token
  319. * @return mixed
  320. */
  321. public function getUserInfo($appId, $appSecret, $token)
  322. {
  323. $scope = \YunShop::request()->scope ?: '';
  324. $subscribe = 0;
  325. $share = Setting::get('shop.share');
  326. $user_info = [];
  327. if (is_null($share) || $share['follow'] == 1 || ($share && is_null($share['follow']))) {
  328. $global_access_token_url = $this->_getAccessToken($appId, $appSecret);
  329. $global_token = \Curl::to($global_access_token_url)
  330. ->asJsonResponse(true)
  331. ->get();
  332. $global_userinfo_url = $this->_getInfo($global_token['access_token'], $token['openid']);
  333. $user_info = \Curl::to($global_userinfo_url)
  334. ->asJsonResponse(true)
  335. ->get();
  336. $subscribe = $user_info['subscribe'];
  337. }
  338. if (0 == $subscribe && $scope != 'base') { //未关注拉取不到用户信息
  339. $userinfo_url = $this->_getUserInfoUrl($token['access_token'], $token['openid']);
  340. $user_info = \Curl::to($userinfo_url)
  341. ->asJsonResponse(true)
  342. ->get();
  343. $user_info['subscribe'] = $subscribe;
  344. }
  345. return array_merge($user_info, $token);
  346. }
  347. /**
  348. * 获取token api
  349. *
  350. * @param $appId
  351. * @param $appSecret
  352. * @param $code
  353. * @return string
  354. */
  355. private function _getTokenUrl($appId, $appSecret, $code)
  356. {
  357. return "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . $appId . "&secret=" . $appSecret . "&code=" . $code . "&grant_type=authorization_code";
  358. }
  359. /**
  360. * 获取用户信息 api
  361. *
  362. * 无需关注
  363. *
  364. * @param $accesstoken
  365. * @param $openid
  366. * @return string
  367. */
  368. private function _getUserInfoUrl($accesstoken, $openid)
  369. {
  370. return "https://api.weixin.qq.com/sns/userinfo?access_token={$accesstoken}&openid={$openid}&lang=zh_CN";
  371. }
  372. /**
  373. * 获取全局ACCESS TOKEN
  374. * @return string
  375. */
  376. private function _getAccessToken($appId, $appSecret)
  377. {
  378. return 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appId . '&secret=' . $appSecret;
  379. }
  380. /**
  381. * 获取用户信息
  382. *
  383. * 需要关注
  384. *
  385. * @param $accesstoken
  386. * @param $openid
  387. * @return string
  388. */
  389. private function _getInfo($accesstoken, $openid)
  390. {
  391. return 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $accesstoken . '&openid=' . $openid;
  392. }
  393. /**
  394. * 公众号开放平台授权登陆
  395. * @param $uniacid
  396. * @param $userinfo
  397. * @param null $upperMemberId
  398. * @return array|int|mixed
  399. * @throws AppException
  400. * @throws \app\common\exceptions\MemberErrorMsgException
  401. */
  402. public function unionidLogin($uniacid, $userinfo, $upperMemberId = NULL)
  403. {
  404. $member_id = parent::unionidLogin($uniacid, $userinfo, $upperMemberId = NULL, self::LOGIN_TYPE);
  405. return $member_id;
  406. }
  407. public function updateMemberInfo($member_id, $userinfo)
  408. {
  409. if (request()->input('route') == 'member.member.bindMobile') {
  410. parent::updateMemberInfo($member_id, $userinfo);
  411. }
  412. $record = array(
  413. 'openid' => $userinfo['openid'],
  414. 'nickname' => stripslashes($userinfo['nickname'])
  415. );
  416. if (request()->input('route') == 'member.member.bindMobile') {
  417. MemberAggregationAppModel::updateData($member_id, $record);
  418. }
  419. }
  420. public function addMemberInfo($uniacid, $userinfo)
  421. {
  422. $uid = parent::addMemberInfo($uniacid, $userinfo);
  423. //$this->addMcMemberFans($uid, $uniacid, $userinfo);
  424. $this->addFansMember($uid, $uniacid, $userinfo);
  425. return $uid;
  426. }
  427. public function addMcMemberFans($uid, $uniacid, $userinfo)
  428. {
  429. McMappingFansModel::insertData($userinfo, array(
  430. 'uid' => $uid,
  431. 'acid' => $uniacid,
  432. 'uniacid' => $uniacid,
  433. 'salt' => Client::random(8),
  434. ));
  435. }
  436. public function addFansMember($uid, $uniacid, $userinfo)
  437. {
  438. MemberAggregationAppModel::replace(array(
  439. 'uniacid' => $uniacid,
  440. 'member_id' => $uid,
  441. 'openid' => $userinfo['openid'],
  442. 'nickname' => $userinfo['nickname'],
  443. 'avatar' => $userinfo['headimgurl'],
  444. 'gender' => $userinfo['sex'],
  445. ));
  446. }
  447. public function getFansModel($openid)
  448. {
  449. $model = MemberAggregationAppModel::getUId($openid);
  450. if (!is_null($model)) {
  451. $model->uid = $model->member_id;
  452. }
  453. return $model;
  454. }
  455. /**
  456. * 会员关联表操作
  457. *
  458. * @param $uniacid
  459. * @param $member_id
  460. * @param $unionid
  461. */
  462. public function addMemberUnionid($uniacid, $member_id, $unionid)
  463. {
  464. MemberUniqueModel::replace(array(
  465. 'uniacid' => $uniacid,
  466. 'unionid' => $unionid,
  467. 'member_id' => $member_id,
  468. 'type' => self::LOGIN_TYPE
  469. ));
  470. }
  471. public function updateFansMember($fan, $member_id, $userinfo)
  472. {
  473. $record = array(
  474. 'member_id' => $member_id,
  475. 'nickname' => stripslashes($userinfo['nickname']),
  476. 'avatar' => isset($userinfo['headimgurl']) ? $userinfo['headimgurl'] : '',
  477. 'gender' => isset($userinfo['sex']) ? $userinfo['sex'] : '-1',
  478. );
  479. MemberAggregationAppModel::where('id', $fan->id)->update($record);
  480. }
  481. public function secondAuth($page, $mobile)
  482. {
  483. $mobileExists = MobileLoginRecordModel::isExists($mobile);
  484. $category_setting = SettingManageService::linkCategorySetting();
  485. $login_type = $category_setting['login_type'];
  486. if ($page == 1 && !$mobileExists && $login_type['together']) {
  487. return true;
  488. }
  489. return false;
  490. }
  491. }