MemberMiniAppService.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * Author: 芸众商城 www.yunzshop.com
  5. * Date: 17/2/23
  6. * Time: 上午11:20
  7. */
  8. namespace app\frontend\modules\member\services;
  9. use app\common\exceptions\MemberNotLoginException;
  10. use app\common\facades\EasyWeChat;
  11. use app\common\helpers\Cache;
  12. use app\common\helpers\Client;
  13. use app\common\services\Session;
  14. use app\frontend\modules\member\models\MemberMiniAppModel;
  15. use app\frontend\modules\member\models\MemberUniqueModel;
  16. use app\frontend\modules\member\models\McMappingFansModel;
  17. use app\frontend\modules\member\models\MemberModel;
  18. use EasyWeChat\Factory;
  19. use EasyWeChat\MiniProgram\Application;
  20. class MemberMiniAppService extends MemberService
  21. {
  22. const LOGIN_TYPE = 2; //小程序
  23. public function __construct()
  24. {
  25. }
  26. public function login()
  27. {
  28. $ver = \YunShop::request()->ver;
  29. if ($ver == 2) {
  30. return $this->newLogin();
  31. } else {
  32. return $this->oldLogin();
  33. }
  34. }
  35. /**
  36. * 小程序登录态
  37. *
  38. * @param $user_info
  39. * @return string
  40. */
  41. function wx_app_session($user_info)
  42. {
  43. if (empty($user_info['session_key']) || empty($user_info['openid'])) {
  44. return show_json(0, '用户信息有误');
  45. }
  46. $random = md5(uniqid(mt_rand()));
  47. $_SESSION['wx_app'] = array($random => iserializer(array('session_key' => $user_info['session_key'], 'openid' => $user_info['openid'])));
  48. return $random;
  49. }
  50. public function createMiniMember($json_user, $arg)
  51. {
  52. $user_info = MemberMiniAppModel::getUserInfo($json_user['openid']);
  53. if (!empty($user_info)) {
  54. MemberMiniAppModel::updateUserInfo($json_user['openid'], array(
  55. 'nickname' => $json_user['nickname'],
  56. 'avatar' => $json_user['headimgurl'],
  57. 'gender' => $json_user['sex'],
  58. ));
  59. } else {
  60. MemberMiniAppModel::replace(array(
  61. 'uniacid' => $arg['uniacid'],
  62. 'member_id' => $arg['member_id'],
  63. 'openid' => $json_user['openid'],
  64. 'nickname' => $json_user['nickname'],
  65. 'avatar' => $json_user['headimgurl'],
  66. 'gender' => $json_user['sex'],
  67. ));
  68. }
  69. }
  70. /**
  71. * 公众号开放平台授权登陆
  72. *
  73. * @param $uniacid
  74. * @param $userinfo
  75. * @return array|int|mixed
  76. */
  77. public function unionidLogin($uniacid, $userinfo, $upperMemberId = NULL)
  78. {
  79. $member_id = parent::unionidLogin($uniacid, $userinfo, $upperMemberId = NULL, self::LOGIN_TYPE);
  80. return $member_id;
  81. }
  82. public function updateMemberInfo($member_id, $userinfo)
  83. {
  84. if (request()->input('route') == 'member.member.bindMobile') {
  85. parent::updateMemberInfo($member_id, $userinfo);
  86. }
  87. $record = array(
  88. 'openid' => $userinfo['openid'],
  89. 'nickname' => stripslashes($userinfo['nickname'])
  90. );
  91. if (request()->input('route') == 'member.member.bindMobile') {
  92. MemberMiniAppModel::updateData($member_id, $record);
  93. }
  94. }
  95. public function addMemberInfo($uniacid, $userinfo)
  96. {
  97. $uid = parent::addMemberInfo($uniacid, $userinfo);
  98. //$this->addMcMemberFans($uid, $uniacid, $userinfo);
  99. $this->addFansMember($uid, $uniacid, $userinfo);
  100. return $uid;
  101. }
  102. public function addMcMemberFans($uid, $uniacid, $userinfo)
  103. {
  104. McMappingFansModel::insertData($userinfo, array(
  105. 'uid' => $uid,
  106. 'acid' => $uniacid,
  107. 'uniacid' => $uniacid,
  108. 'salt' => Client::random(8),
  109. ));
  110. }
  111. public function addFansMember($uid, $uniacid, $userinfo)
  112. {
  113. MemberMiniAppModel::replace(array(
  114. 'uniacid' => $uniacid,
  115. 'member_id' => $uid,
  116. 'openid' => $userinfo['openid'],
  117. 'nickname' => $userinfo['nickname'],
  118. 'avatar' => $userinfo['headimgurl'],
  119. 'gender' => $userinfo['sex'],
  120. ));
  121. }
  122. public function getFansModel($openid)
  123. {
  124. $model = MemberMiniAppModel::getUId($openid);
  125. if (!is_null($model)) {
  126. $model->uid = $model->member_id;
  127. }
  128. return $model;
  129. }
  130. /**
  131. * 添加会员主表信息
  132. *
  133. * @param $uniacid
  134. * @param $userinfo
  135. * @return mixed
  136. */
  137. public function addMcMemberInfo($uniacid, $userinfo)
  138. {
  139. $uid = parent::addMemberInfo($uniacid, $userinfo);
  140. return $uid;
  141. }
  142. /**
  143. * 会员关联表操作
  144. *
  145. * @param $uniacid
  146. * @param $member_id
  147. * @param $unionid
  148. */
  149. public function addMemberUnionid($uniacid, $member_id, $unionid)
  150. {
  151. MemberUniqueModel::replace(array(
  152. 'uniacid' => $uniacid,
  153. 'unionid' => $unionid,
  154. 'member_id' => $member_id,
  155. 'type' => self::LOGIN_TYPE
  156. ));
  157. }
  158. /**
  159. * 验证登录状态
  160. *
  161. * @return bool
  162. */
  163. public function checkLogged($login = null)
  164. {
  165. \Log::info('loggedid='.MemberService::isLogged());
  166. if (MemberService::isLogged()) {
  167. \Log::info('mini_openid='.Session::get('mini_openid'));
  168. if (!empty(Session::get('mini_openid'))) {
  169. return true;
  170. }
  171. $member_mini = MemberMiniAppModel::getFansById(\YunShop::app()->getMemberId());
  172. \Log::info('member_mini='.$member_mini);
  173. \Log::info('member_id='.\YunShop::app()->getMemberId());
  174. if (empty($member_mini)) {
  175. return false;
  176. }
  177. Session::set('mini_openid',$member_mini['openid']);
  178. return true;
  179. }
  180. return false;
  181. }
  182. public function updateFansMember($fan, $member_id, $userinfo)
  183. {
  184. //小程序不更新用户信息
  185. /*$record = array(
  186. 'member_id' => $member_id,
  187. 'nickname' => stripslashes($userinfo['nickname']),
  188. 'avatar' => isset($userinfo['headimgurl']) ? $userinfo['headimgurl'] : '',
  189. 'gender' => isset($userinfo['sex']) ? $userinfo['sex'] : '-1',
  190. );
  191. MemberMiniAppModel::where('mini_app_id', $fan->mini_app_id)->update($record);*/
  192. }
  193. public function oldLogin()
  194. {
  195. include dirname(__FILE__) . "/../vendors/wechat/wxBizDataCrypt.php";
  196. $min_set = \Setting::get('plugin.min_app');
  197. if (is_null($min_set) || 0 == $min_set['switch']) {
  198. return show_json(0, '未开启小程序');
  199. }
  200. $para = \YunShop::request();
  201. $data = array(
  202. 'appid' => $min_set['key'],
  203. 'secret' => $min_set['secret'],
  204. 'js_code' => $para['code'],
  205. 'grant_type' => 'authorization_code',
  206. );
  207. $url = 'https://api.weixin.qq.com/sns/jscode2session';
  208. $user_info = \Curl::to($url)
  209. ->withData($data)
  210. ->asJsonResponse(true)
  211. ->get();
  212. $data = ''; //json
  213. if (!empty($para['info'])) {
  214. $json_data = json_decode($para['info'], true);
  215. $pc = new \WXBizDataCrypt($min_set['key'], $user_info['session_key']);
  216. $errCode = $pc->decryptData($json_data['encryptedData'], $json_data['iv'], $data);
  217. }
  218. \Log::debug('-------------min errcode-------', [$errCode]);
  219. if ($errCode == 0) {
  220. $json_user = json_decode($data, true);
  221. } else {
  222. if (isset($_GET['test'])) {
  223. $json_user = json_decode($_GET['user_info'], true);
  224. $user_info = [
  225. 'openid' => $json_user['openid'],
  226. 'session_key' => $json_user['openid']
  227. ];
  228. } else {
  229. return show_json(0, '登录认证失败');
  230. }
  231. }
  232. if (!empty($json_user)) {
  233. if (isset($json_user['unionId'])) {
  234. $json_user['unionid'] = $json_user['unionId'];
  235. }
  236. if (isset($json_user['openId'])) {
  237. $json_user['openid'] = $json_user['openId'];
  238. $json_user['nickname'] = $json_user['nickName'];
  239. $json_user['headimgurl'] = $json_user['avatarUrl'];
  240. $json_user['sex'] = $json_user['gender'];
  241. }
  242. //Login
  243. $member_id = $this->memberLogin($json_user);
  244. $is_first_time_bind = $this->verifyFirstTimeLogin($member_id,(bool)$min_set['is_first_time_bind']);
  245. Session::set('member_id', $member_id);
  246. Session::set('mini_openid', $json_user['openid']);
  247. $random = $this->wx_app_session($user_info);
  248. $nickname = MemberModel::select('nickname')->where('uid',$member_id)->first();
  249. $result = array(
  250. 'session' => $random,
  251. 'wx_token' => session_id(),
  252. 'uid' => $member_id,
  253. 'user_info' => ['nickname' => $nickname['nickname'] ?: ''],
  254. 'is_first_time_bind' => $is_first_time_bind
  255. );
  256. return show_json(1, $result, $result);
  257. } else {
  258. return show_json(0, '获取用户信息失败');
  259. }
  260. }
  261. public function newLogin()
  262. {
  263. include dirname(__FILE__) . "/../vendors/wechat/wxBizDataCrypt.php";
  264. $min_set = \Setting::get('plugin.min_app');
  265. if (is_null($min_set) || 0 == $min_set['switch']) {
  266. return show_json(0, '未开启小程序');
  267. }
  268. $para = json_decode(\YunShop::request()->info, 1);
  269. $code = \YunShop::request()->code;
  270. $data = array(
  271. 'appid' => $min_set['key'],
  272. 'secret' => $min_set['secret'],
  273. 'js_code' => $code,
  274. 'grant_type' => 'authorization_code',
  275. );
  276. $url = 'https://api.weixin.qq.com/sns/jscode2session';
  277. $user_info = \Curl::to($url)
  278. ->withData($data)
  279. ->asJsonResponse(true)
  280. ->get();
  281. \Log::debug('-------------min errcode-------', ['code: ' . $user_info['errcode'] . ' errmsg: ' . $user_info['errmsg']]);
  282. if (!empty($user_info) && 0 == $user_info['errcode']) {
  283. if ($code && is_null($para)) {
  284. $mini_member = MemberMiniAppModel::uniacid()->where('openid', $user_info['openid'])->count();
  285. if (!$mini_member) {
  286. throw new MemberNotLoginException('请登录', $_SERVER['QUERY_STRING']);
  287. }
  288. }
  289. if (isset($user_info['unionid'])) {
  290. $json_user['unionid'] = $user_info['unionid'];
  291. }
  292. $json_user['openid'] = $user_info['openid'];
  293. $json_user['nickname'] = $para['nickName'] ? $this->filteNickname($para['nickName']) : '';
  294. $json_user['headimgurl'] = $para['avatarUrl'] ?: '';
  295. $json_user['sex'] = $para['gender'] ?: 0;
  296. //Login
  297. $member_id = $this->memberLogin($json_user);
  298. $is_first_time_bind = $this->verifyFirstTimeLogin($member_id,(bool)$min_set['is_first_time_bind']);
  299. Session::set('member_id', $member_id);
  300. Session::set('mini_openid', $json_user['openid']);
  301. $random = $this->wx_app_session($user_info);
  302. $nickname = MemberModel::select('nickname')->where('uid',$member_id)->first();
  303. $result = array(
  304. 'session' => $random,
  305. 'wx_token' => session_id(),
  306. 'uid' => $member_id,
  307. 'user_info' => ['nickname' => $nickname['nickname'] ?: ''],
  308. 'is_first_time_bind' => $is_first_time_bind
  309. );
  310. return show_json(1, $result, $result);
  311. } else {
  312. return show_json(0, '获取用户信息失败');
  313. }
  314. }
  315. /**
  316. * @param $member_id
  317. * @param $first_time_bind_set
  318. * @return int
  319. */
  320. protected function verifyFirstTimeLogin($member_id, $first_time_bind_set): int
  321. {
  322. $member_model = MemberModel::getMemberById($member_id);
  323. $is_first_time_bind = 1;//首次登录显示授权手机号按钮:1-开启
  324. //已绑定手机
  325. if ($member_model->mobile) {
  326. $is_first_time_bind = 0;
  327. }
  328. //未开启
  329. if (!$first_time_bind_set) {
  330. $is_first_time_bind = 0;
  331. }
  332. return $is_first_time_bind;
  333. }
  334. /**
  335. * 获取授权用户手机号
  336. *
  337. * @param $code
  338. * @return array|mixed|\stdClass
  339. */
  340. public function getPhoneNumber($code)
  341. {
  342. $min_set = \Setting::get('plugin.min_app');
  343. if (is_null($min_set) || 0 == $min_set['switch']) {
  344. return show_json(0, '未开启小程序');
  345. }
  346. $token = Cache::remember('mini:phonenumber:' . \YunShop::app()->uniacid, 90, function () use ($min_set) {
  347. $gtoken = \Curl::to("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$min_set['key']}&secret={$min_set['secret']}")->get();
  348. return json_decode($gtoken, 1);
  349. });
  350. $data = \Curl::to("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={$token['access_token']}")
  351. ->withData(json_encode(['code' => $code]))
  352. ->asJsonResponse(true)
  353. ->post();
  354. return $data;
  355. }
  356. }