MemberBusinessScanCodeService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. namespace app\frontend\modules\member\services;
  3. use app\common\exceptions\MemberErrorMsgException;
  4. use app\common\facades\EasyWeChat;
  5. use app\common\models\AccountWechats;
  6. use app\common\models\Member;
  7. use app\common\services\Session;
  8. use app\frontend\modules\member\models\MemberModel;
  9. use app\frontend\modules\member\models\MemberWechatQrcodeModel;
  10. use business\common\models\PlatLog;
  11. use business\common\services\SettingService;
  12. use Illuminate\Support\Facades\Redis;
  13. class MemberBusinessScanCodeService extends MemberService
  14. {
  15. const LOGIN_TYPE = 19;
  16. const IS_PC_QRCODE = 1;
  17. const WE_CHAT_SHOW_QR_CODE_URL = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=';
  18. private $config;
  19. public function __construct()
  20. {
  21. $this->config = '';
  22. if (!is_null(\app\common\modules\shop\ShopConfig::current()->get('wechat_qrcode_config'))) {
  23. $class = array_get(\app\common\modules\shop\ShopConfig::current()->get('wechat_qrcode_config'), 'class');
  24. $function = array_get(\app\common\modules\shop\ShopConfig::current()->get('wechat_qrcode_config'), 'function');
  25. $this->config = $class::$function();
  26. }
  27. return $this->config;
  28. }
  29. //验证是否能扫码登录
  30. public function checkLogin($is_pc_qrcode)
  31. {
  32. $arr = array('status' => 0);
  33. if (empty($this->config)) {
  34. $arr = ['status' => 1, 'msg' => '不支持扫码登录'];
  35. } else if ($this->config['is_open'] == 0) {
  36. $arr = ['status' => 1, 'msg' => '未开启扫码登录'];
  37. } else if ($this->config['is_wechat_login'] == 1 && $is_pc_qrcode <> self::IS_PC_QRCODE) {
  38. $arr = ['status' => 1, 'msg' => '必须使用微信扫码登录'];
  39. }
  40. return $arr;
  41. }
  42. public function login()
  43. {
  44. $check = $this->checkLogin(\YunShop::request()->is_pc_qrcode);
  45. if ($check['status'] == 1) {
  46. exit("5001" . $check['msg']);
  47. }
  48. $yz_redirect = request()->yz_redirect;
  49. if ($this->config['wechat_login_type'] == 1) {
  50. return $this->nowLogin($yz_redirect);
  51. } elseif ($this->config['wechat_login_type'] == 2) {
  52. return $this->interestLogin($yz_redirect);
  53. }
  54. }
  55. /**
  56. * 关注关注公众号登录
  57. * @param $yzRedirect
  58. * @return array|void
  59. * @throws MemberErrorMsgException
  60. */
  61. protected function interestLogin($yzRedirect = '')
  62. {
  63. $yz_redirect = $yzRedirect;
  64. $is_from = request()->is_from;
  65. $pc_token = \YunShop::request()->pc_token;
  66. if ($pc_token) {
  67. if (Redis::get($pc_token)) {
  68. $member_info = Member::find(Redis::get($pc_token . 'member_id'));
  69. //登录成功
  70. if ($member_info) {
  71. $this->save(array_add($member_info->toArray(), 'password', $member_info->password), $member_info->uniacid);
  72. } else {
  73. throw new MemberErrorMsgException('用户不存在,登录失败!');
  74. }
  75. $params = [
  76. 'is_from' => $is_from
  77. ];
  78. return self::redirectUrl($yz_redirect, $params);
  79. } else {
  80. return show_json(10, '登录失败'); //todo status类型待优化
  81. }
  82. } else {
  83. return show_json(11, '生成二维码链接成功', array('account_url' => $this->getQrCodeUrl(), 'pc_token' => $this->scene));
  84. }
  85. }
  86. /**
  87. * 扫码立即登录
  88. * @param $yzRedirect
  89. * @return array|void
  90. * @throws MemberErrorMsgException
  91. * @throws \app\common\exceptions\AppException
  92. */
  93. protected function nowLogin($yzRedirect = '')
  94. {
  95. $yz_redirect = $yzRedirect;
  96. $is_from = request()->is_from;
  97. $code = \YunShop::request()->code;
  98. $business_id = request('business_id', SettingService::bindBusinessId());
  99. $request_url = $_SERVER['REQUEST_URI'] . "&business_id={$business_id}" . "&yz_redirect={$yz_redirect}" . "&is_from={$is_from}";
  100. $callback = ($_SERVER['REQUEST_SCHEME'] ? $_SERVER['REQUEST_SCHEME'] : 'http') . '://' . $_SERVER['HTTP_HOST'] . $request_url;
  101. $state = 'yz-' . session_id();
  102. Session::set('wx_qrcode_state', $state);
  103. $wxurl = $this->_getAuthUrl($this->config['appid'], $callback, $state);
  104. if (!empty($code)) {
  105. $query = parse_url($callback, PHP_URL_QUERY);
  106. parse_str($query, $params);
  107. \YunShop::app()->uniacid = \Setting::$uniqueAccountId = $params['i'];
  108. SettingService::setBusinessId($params['business_id']);
  109. $url_path = base64_decode($params['yz_redirect']);
  110. $is_from = $params['is_from'];
  111. $token = $this->_getTokenUrl($this->config['appid'], $this->config['app_secret'], $code);
  112. // \Log::debug('token信息', $token);
  113. if (!empty($token) && is_array($token) && $token['errmsg'] == 'invalid code') {
  114. return show_json(0, array('msg' => '请求错误'));
  115. }
  116. $user_info = $this->_getUserInfoUrl($token['access_token'], $token['openid']);
  117. \Log::debug('企业微信PC端扫码登录微信授权成功', $user_info);
  118. if (is_array($user_info) && !empty($user_info['errcode'])) {
  119. \Log::debug('---微信扫码登陆授权失败---', $user_info);
  120. throw new MemberErrorMsgException('微信扫码登陆授权失败');
  121. }
  122. $member_id = $this->memberLogin($user_info);
  123. $member_info = Member::find($member_id);
  124. //登录成功
  125. if ($member_info) {
  126. $this->save(array_add($member_info->toArray(), 'password', $member_info->password), $member_info->uniacid);
  127. } else {
  128. throw new MemberErrorMsgException('用户不存在,登录失败!');
  129. }
  130. $busniess_id = PlatLog::where('uid', $member_id)->orderByDesc('id')->value('final_plat_id');
  131. $params = [
  132. 'is_from' => $is_from
  133. ];
  134. self::redirectUrl($url_path, $params, $busniess_id);
  135. } else {
  136. return show_json(9, array('url' => $wxurl, 'msg' => '生成二维码链接成功'));
  137. }
  138. }
  139. /**
  140. * api
  141. * 生成微信扫码登录二维码
  142. * snsapi_userinfo
  143. * @param $appId
  144. * @param $url
  145. * @param $state
  146. * @return string
  147. */
  148. private function _getAuthUrl($appId, $url, $state)
  149. {
  150. return "https://open.weixin.qq.com/connect/qrconnect?appid=" . $appId . "&redirect_uri=" . urlencode($url) . "&response_type=code&scope=snsapi_login&state={$state}#wechat_redirect";
  151. }
  152. /**
  153. * 获取token api
  154. *
  155. * @param $appId
  156. * @param $appSecret
  157. * @param $code
  158. * @return string
  159. */
  160. private function _getTokenUrl($appId, $appSecret, $code)
  161. {
  162. $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . $appId . "&secret=" . $appSecret . "&code=" . $code . "&grant_type=authorization_code";
  163. return $tokenurl = \Curl::to($url)
  164. ->asJsonResponse(true)
  165. ->get();
  166. }
  167. /**
  168. * 获取微信用户信息
  169. * @param $accesstoken
  170. * @param $openid
  171. * @return mixed
  172. */
  173. private function _getUserInfoUrl($accesstoken, $openid)
  174. {
  175. $url = "https://api.weixin.qq.com/sns/userinfo?access_token={$accesstoken}&openid={$openid}&lang=zh_CN";
  176. return $userinfo_url = \Curl::to($url)
  177. ->asJsonResponse(true)
  178. ->get();
  179. }
  180. /**
  181. * 扫码跳转到企业微信PC端
  182. * @param $urlPath
  183. * @param array $from
  184. * @return array|void
  185. */
  186. public function redirectUrl($urlPath = null, array $from = [], $busniessId = null)
  187. {
  188. if ($this->config['wechat_login_type'] == 2) {
  189. return show_json(1, '登陆成功', ['url' => '']);
  190. }
  191. $params['cid'] = $busniessId ?: SettingService::getBusinessId();
  192. SettingService::setBusinessId($params['cid']);
  193. $params = array_merge($params, $from);
  194. if ($urlPath) {
  195. $url = yzBusinessFullUrl($urlPath, $params);;
  196. } else {
  197. $url = yzBusinessFullUrl('business/index', $params);//默认企业微信PC端主页
  198. }
  199. redirect($url)->send();//跳转到前端会员中心页面
  200. }
  201. /**
  202. * 验证登录状态
  203. *
  204. * @return bool
  205. */
  206. public function checkLogged($login = null)
  207. {
  208. return MemberService::isLogged();
  209. }
  210. /**
  211. *
  212. * @param $openid
  213. *
  214. * @return mixed
  215. */
  216. public function getFansModel($openid)
  217. {
  218. $model = MemberWechatQrcodeModel::getUserInfo($openid);
  219. if (!is_null($model)) {
  220. $model->uid = $model->member_id;
  221. }
  222. }
  223. /**
  224. * @param $uid
  225. * @param $uniacid
  226. * @param $userinfo
  227. */
  228. public function addFansMember($uid, $uniacid, $userinfo)
  229. {
  230. $user = MemberWechatQrcodeModel::getUserInfo_memberid($uid);
  231. if (!empty($user)) {
  232. $this->updateMemberInfo($uid, $userinfo);
  233. } else {
  234. MemberWechatQrcodeModel::replace(array(
  235. 'uniacid' => $uniacid,
  236. 'member_id' => $uid,
  237. 'openid' => $userinfo['openid'],
  238. 'nickname' => $userinfo['nickname'],
  239. 'avatar' => $userinfo['headimgurl'],
  240. 'gender' => $userinfo['sex'],
  241. 'province' => '',
  242. 'country' => '',
  243. 'city' => '',
  244. ));
  245. }
  246. }
  247. private function getQrCodeUrl()
  248. {
  249. return static::WE_CHAT_SHOW_QR_CODE_URL . $this->getTicket();
  250. }
  251. private function getTicket()
  252. {
  253. return self::createQR()['ticket'];
  254. }
  255. /**
  256. * 生成公众号临时二维码,默认120s到期
  257. * @param $scene
  258. * @return mixed
  259. */
  260. private function createQR()
  261. {
  262. $account = AccountWechats::getAccountByUniacid(\YunShop::app()->uniacid);
  263. $options = [
  264. 'app_id' => $account->key,
  265. 'secret' => $account->secret,
  266. ];
  267. $app = EasyWeChat::officialAccount($options);
  268. $qrcode = $app->qrcode;
  269. $result = $qrcode->temporary($this->getSceneValue(), 120);
  270. return $result;
  271. }
  272. /**
  273. * 获取唯一场景值
  274. * @return string
  275. */
  276. private function getSceneValue()
  277. {
  278. $scene = sha1(rand(0, 999999));
  279. $result = Redis::get($scene);
  280. if (!$result) {
  281. Redis::setex($scene, 120, 0); //0 = 生成二维码未扫码
  282. $this->scene = $scene;
  283. return $scene;
  284. } else {
  285. $this->getSceneValue();
  286. }
  287. }
  288. }