admin/app/frontend/modules/member/services/MemberOfficeAccountService.php

607 lines
18 KiB
PHP

<?php
/**
* Created by PhpStorm.
* Author:
* Date: 17/2/22
* Time: 下午4:44
*/
namespace app\frontend\modules\member\services;
use app\common\exceptions\MemberErrorMsgException;
use app\common\facades\EasyWeChat;
use app\common\facades\Setting;
use app\common\helpers\Cache;
use app\common\helpers\Client;
use app\common\helpers\Url;
use app\common\models\AccountWechats;
use app\common\models\Member;
use app\common\services\Session;
use app\frontend\modules\member\models\McMappingFansModel;
use app\frontend\modules\member\models\MemberUniqueModel;
use app\frontend\modules\member\models\SubMemberModel;
use Illuminate\Contracts\Encryption\DecryptException;
class MemberOfficeAccountService extends MemberService
{
const LOGIN_TYPE = '1';
public function __construct()
{
}
public function login()
{
$member_id = 0;
$uniacid = \YunShop::app()->uniacid;
$scope = \YunShop::request()->scope ?: 'userinfo'; //scope: base|home|userinfo
$code = \YunShop::request()->code;
if (Setting::get('shop.member')['wechat_login_mode'] == '1') {
return $this->isPhoneLogin($uniacid);
}
$callback = ($_SERVER['REQUEST_SCHEME'] ? $_SERVER['REQUEST_SCHEME'] : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$wechat_scope = $this->wechatScope();
$config = [
'oauth' => [
'scopes' => [$wechat_scope],
'callback' => $callback,
]
];
$app = EasyWeChat::officialAccount($config);
$oauth = $app->oauth;
if (!empty($code)) {
$oauthUser = $oauth->user();
$userinfo = $oauthUser->getOriginal();
$userinfo['access_token'] = $oauthUser->getAccessToken();
$userinfo['expires_in'] = 7200;
$userinfo['refresh_token'] = $oauthUser->getRefreshToken();
\Log::debug('-----EasyWeChat-----', [$userinfo['openid']]);
$user = $app->user->get($userinfo['openid']);
$userinfo = array_merge($user, $userinfo);
//Login
$member_id = $this->memberLogin($userinfo);
if($member_id) event(new \app\common\events\member\MemberLoginEvent($member_id));
Session::set('member_id', $member_id);
setcookie('Yz-Token', encrypt($userinfo['access_token'] . '\t' . ($userinfo['expires_in'] + time()) . '\t' . $userinfo['openid'] . '\t' . $scope), time() + self::TOKEN_EXPIRE);
} else {
$this->_setClientRequestUrl();
$oauth->redirect()->send();
exit;
}
redirect($this->_getClientRequestUrl())->send();
exit;
}
public function getWechatOpenid(){
$uniacid = \YunShop::app()->uniacid;
$code = \YunShop::request()->code;
$account = AccountWechats::getAccountByUniacid($uniacid);
$appId = $account->key;
$appSecret = $account->secret;
$state = 'yz-' . session_id();
$callback = ($_SERVER['REQUEST_SCHEME'] ? $_SERVER['REQUEST_SCHEME'] : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$authurl = $this->_getAuthBaseUrl($appId, $callback, $state);
$tokenurl = $this->_getTokenUrl($appId, $appSecret, $code);
if (!empty($code)) {
$redirect_url = base64_decode(\YunShop::request()->page).'&code=1';
$token = \Curl::to($tokenurl)
->asJsonResponse(true)
->get();
if (!empty($token) && !empty($token['errmsg']) && $token['errmsg'] == 'invalid code') {
return show_json(5, 'token请求错误');
}
// todo 2024-5-24 注释,添加该内容时;未关注公众号用户登录失败,直接报错;直接进注释操作(不清除后续没有用到userinfo 为什么会进行一次查询)
// $userinfo = $this->getUserInfo($appId, $appSecret, $token);
// if (is_array($userinfo) && !empty($userinfo['errcode'])) {
// \Log::debug('微信登陆授权失败-' . $userinfo['errcode']);
// return show_json(-3, $userinfo['errmsg']);
// }
Session::set('wx_open_id', $token['openid']);
redirect($redirect_url)->send();
} else {
redirect($authurl)->send();
}
}
/**
* 获取用户信息
*
* @param $appId
* @param $appSecret
* @param $token
* @return mixed
*/
public function getUserInfo($appId, $appSecret, $token)
{
$scope = \YunShop::request()->scope ?: '';
$subscribe = 0;
$share = Setting::get('shop.share');
$user_info = [];
if (is_null($share) || $share['follow'] == 1 || ($share && is_null($share['follow']))) {
$global_access_token_url = $this->_getAccessToken($appId, $appSecret);
$global_token = \Curl::to($global_access_token_url)
->asJsonResponse(true)
->get();
$global_userinfo_url = $this->_getInfo($global_token['access_token'], $token['openid']);
$user_info = \Curl::to($global_userinfo_url)
->asJsonResponse(true)
->get();
$subscribe = $user_info['subscribe'];
}
if (0 == $subscribe && $scope != 'base') { //未关注拉取不到用户信息
$userinfo_url = $this->_getUserInfoUrl($token['access_token'], $token['openid']);
$user_info = \Curl::to($userinfo_url)
->asJsonResponse(true)
->get();
$user_info['subscribe'] = $subscribe;
}
return array_merge($user_info, $token);
}
/**
* 用户验证授权 api
*
* snsapi_userinfo
*
* @param $appId
* @param $url
* @param $state
* @return string
*/
private function _getAuthUrl($appId, $url, $state)
{
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . $appId . "&redirect_uri=" . urlencode($url) . "&response_type=code&scope=snsapi_userinfo&state={$state}#wechat_redirect";
}
/**
*
* 静默获取用户信息
*
* snsapi_base
*
* @param $appId
* @param $url
* @param $state
* @return string
*/
private function _getAuthBaseUrl($appId, $url, $state)
{
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . $appId . "&redirect_uri=" . urlencode($url) . "&response_type=code&scope=snsapi_base&state={$state}#wechat_redirect";
}
/**
* 获取token api
*
* @param $appId
* @param $appSecret
* @param $code
* @return string
*/
private function _getTokenUrl($appId, $appSecret, $code)
{
return "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . $appId . "&secret=" . $appSecret . "&code=" . $code . "&grant_type=authorization_code";
}
/**
* 获取用户信息 api
*
* 无需关注
*
* @param $accesstoken
* @param $openid
* @return string
*/
private function _getUserInfoUrl($accesstoken, $openid)
{
return "https://api.weixin.qq.com/sns/userinfo?access_token={$accesstoken}&openid={$openid}&lang=zh_CN";
}
/**
* 获取全局ACCESS TOKEN
* @return string
*/
private function _getAccessToken($appId, $appSecret)
{
return 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appId . '&secret=' . $appSecret;
}
/**
* 获取用户信息
*
* 需要关注
*
* @param $accesstoken
* @param $openid
* @return string
*/
private function _getInfo($accesstoken, $openid)
{
return 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $accesstoken . '&openid=' . $openid;
}
/**
* 验证account_token
*
* @param $accesstoken
* @param $openid
*
* @return string
*/
private function _tokenAuth($accesstoken, $openid)
{
return 'https://api.weixin.qq.com/sns/auth?access_token=' . $accesstoken . '&openid=' . $openid;
}
private function _refreshAuth($appid, $refreshtoken)
{
return 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=' . $appid . '&grant_type=refresh_token&refresh_token=' . $refreshtoken;
}
/**
* 设置客户端请求地址
*
* @return string
*/
private function _setClientRequestUrl()
{
$pattern = '/(&t=([\d]+[^&]*))/';
$t = time();
if (\YunShop::request()->yz_redirect) {
$yz_redirect = base64_decode(\YunShop::request()->yz_redirect);
if (preg_match($pattern, $yz_redirect)) {
$redirect_url = preg_replace($pattern, "&t={$t}", $yz_redirect);
} else {
$redirect_url = $yz_redirect . '&t=' . time();
}
Session::set('client_url', $redirect_url);
} else {
Session::set('client_url', '');
}
}
private function _setClientRequestUrl_v2()
{
$redirect_url = '';
$pattern = '/(&t=([\d]+[^&]*))/';
$t = time();
if (\YunShop::request()->yz_redirect) {
$yz_redirect = base64_decode(\YunShop::request()->yz_redirect);
if (preg_match($pattern, $yz_redirect)) {
$redirect_url = preg_replace($pattern, "&t={$t}", $yz_redirect);
} else {
$redirect_url = $yz_redirect . '&t=' . time();
}
}
return urlencode($redirect_url);
}
/**
* 获取客户端地址
*
* @return mixed
*/
private function _getClientRequestUrl()
{
$url = Session::get('client_url') ?: $this->_getFrontJumpUrl();
if ($url === false || $url == '') {
$url = Url::absoluteApp('home') . '&t=' . time();
}
return $url;
}
private function _getFrontJumpUrl()
{
$redirect_url = '';
$pattern = '/(&t=([\d]+[^&]*))/';
$t = time();
if (\YunShop::request()->yz_redirect) {
$yz_redirect = base64_decode(\YunShop::request()->yz_redirect);
if (preg_match($pattern, $yz_redirect)) {
$redirect_url = preg_replace($pattern, "&t={$t}", $yz_redirect);
} else {
$redirect_url = $yz_redirect . '&t=' . time();
}
}
\Log::debug('-----------------front_url----------------', [$redirect_url]);
return $redirect_url;
}
/**
* 公众号开放平台授权登陆
*
* @param $uniacid
* @param $userinfo
* @return array|int|mixed
*/
public function unionidLogin($uniacid, $userinfo, $upperMemberId = null)
{
$member_id = parent::unionidLogin($uniacid, $userinfo, $upperMemberId, self::LOGIN_TYPE);
return $member_id;
}
public function updateMemberInfo($member_id, $userinfo)
{
parent::updateMemberInfo($member_id, $userinfo);
\Log::debug('----update_mapping_fans----', $member_id);
$record = array(
'nickname' => stripslashes($userinfo['nickname']),
'follow' => $userinfo['subscribe'] ?: 0,
'tag' => base64_encode(serialize($userinfo))
);
McMappingFansModel::updateData($member_id, $record);
}
public function addMemberInfo($uniacid, $userinfo)
{
$uid = parent::addMemberInfo($uniacid, $userinfo);
\Log::debug('----mapping_fans----', $uid);
//添加mapping_fans表
$this->addFansMember($uid, $uniacid, $userinfo);
return $uid;
}
public function addFansMember($uid, $uniacid, $userinfo)
{
if ($userinfo['openid']){
McMappingFansModel::insertData($userinfo, array(
'uid' => $uid,
'acid' => $uniacid,
'uniacid' => $uniacid,
'salt' => Client::random(8),
));
}
}
public function getFansModel($openid)
{
return McMappingFansModel::getFansData($openid);
}
/**
* 会员关联表操作
*
* @param $uniacid
* @param $member_id
* @param $unionid
*/
public function addMemberUnionid($uniacid, $member_id, $unionid)
{
MemberUniqueModel::replace(array(
'uniacid' => $uniacid,
'unionid' => $unionid,
'member_id' => $member_id,
'type' => self::LOGIN_TYPE
));
}
public function updateFansMember($fan, $member_id, $userinfo)
{
$record = array(
'uid' => $member_id,
'nickname' => stripslashes($userinfo['nickname']),
'follow' => isset($userinfo['subscribe']) ? $userinfo['subscribe'] : 0,
'tag' => base64_encode(serialize($userinfo))
);
McMappingFansModel::updateDataById($fan->fanid, $record);
}
protected function updateSubMemberInfoV2($uid, $userinfo)
{
SubMemberModel::updateOpenid(
$uid, [
'yz_openid' => $userinfo['openid'],
'access_token_1' => $userinfo['access_token'],
'access_expires_in_1' => time() + $userinfo['expires_in'],
'refresh_token_1' => $userinfo['refresh_token'],
'refresh_expires_in_1' => time() + (28 * 24 * 3600)
]
);
}
public function checkMemberInfo($mcMember, $fansMember, $yzMember)
{
if ($mcMember->uid != $yzMember->member_id) {
$mcMember->uid = $yzMember->member_id;
$mcMember->save();
}
if ($fansMember->uid != $yzMember->member_id) {
$fansMember->uid = $yzMember->member_id;
$fansMember->save();
}
}
/**
* 添加会员主表信息
*
* @param $uniacid
* @param $userinfo
* @return mixed
*/
public function addMcMemberInfo($uniacid, $userinfo)
{
$uid = parent::addMemberInfo($uniacid, $userinfo);
return $uid;
}
/**
* 判断是否为手机登录
* @param $uniacid
* @return array
*/
public function isPhoneLogin($uniacid)
{
$mid = Member::getMid();
$type = \YunShop::request()->type;
$mobile = \YunShop::request()->mobile;
$password = \YunShop::request()->password;
$yz_redirect = \YunShop::request()->yz_redirect;
if ($mobile && $password) {
$res = (new MemberMobileService)->login();
if ($res['status'] == 1) {
$redirect_url = $this->_getClientRequestUrl();
$res['json']['redirect_url'] = $redirect_url;
}
return $res;
} else {
$this->_setClientRequestUrl();
$redirect_url = Url::absoluteApp('login', ['i' => $uniacid, 'type' => $type, 'mid' => $mid, 'yz_redirect' => $yz_redirect]);
redirect($redirect_url)->send();
}
}
public function chekAccount()
{
$uniacid = \YunShop::app()->uniacid;
$code = \YunShop::request()->code;
$account = AccountWechats::getAccountByUniacid($uniacid);
$appId = $account->key;
$appSecret = $account->secret;
$state = 'yz-' . session_id();
$callback = ($_SERVER['REQUEST_SCHEME'] ? $_SERVER['REQUEST_SCHEME'] : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$authurl = $this->_getAuthBaseUrl($appId, $callback, $state);
$tokenurl = $this->_getTokenUrl($appId, $appSecret, $code);
if (!empty($code)) {
$redirect_url = $this->_getClientRequestUrl();
$token = \Curl::to($tokenurl)
->asJsonResponse(true)
->get();
if (!empty($token) && !empty($token['errmsg']) && $token['errmsg'] == 'invalid code') {
return show_json(5, 'token请求错误');
}
$userinfo = $this->getUserInfo($appId, $appSecret, $token);
if (is_array($userinfo) && !empty($userinfo['errcode'])) {
\Log::debug('微信登陆授权失败-' . $userinfo['errcode']);
return show_json(-3, '微信登陆授权失败');
}
$fans_info = McMappingFansModel::getFansById(\YunShop::app()->getMemberId());
if ($fans_info->openid != $userinfo['openid']) {
\Log::debug('----openid error----', [$fans_info->uid, $userinfo['openid']]);
session_destroy();
Cache::forget($fans_info->uid . ':chekAccount');
redirect($redirect_url)->send();
}
} else {
$this->_setClientRequestUrl();
redirect($authurl)->send();
exit;
}
redirect($redirect_url)->send();
exit;
}
public function checkLogged($login = null)
{
$from = \YunShop::request()->scope;
if (Setting::get('shop.member')['wechat_login_mode'] == '1' || request()->input('min_token')) {
return (new MemberMobileService)->checkLogged();
}
if (isset($_COOKIE['Yz-Token'])) {
try {
$yz_token = decrypt($_COOKIE['Yz-Token']);
list($token, $expires, $openid, $scope) = explode('\t', $yz_token);
} catch (DecryptException $e) {
setcookie('Yz-Token', '', time() - self::TOKEN_EXPIRE);
return false;
}
if ($scope === 'base' && $from != $scope) {
$login->jump = true;
setcookie('Yz-Token', '', time() - self::TOKEN_EXPIRE);
return false;
}
if (empty($openid)) {
setcookie('Yz-Token', '', time() - self::TOKEN_EXPIRE);
return false;
}
$yz_member = SubMemberModel::getMemberByOpenid($openid);
// 增加token验证
if (is_null($yz_member) || $yz_member->member_id == 0 || $yz_member->access_token_1 != $token) {
setcookie('Yz-Token', '', time() - self::TOKEN_EXPIRE);
return false;
}
if (\YunShop::app()->getMemberId() != $yz_member->member_id) {
Session::set('member_id', $yz_member->member_id);
}
return true;
}
return false;
}
private function wechatScope()
{
if (strpos($this->_getClientRequestUrl(), 'cashier_pay')) {
$set = \Setting::get('plugin.store');
if (isset($set['is_open_warrant']) && 1 == $set['is_open_warrant']) {
return 'snsapi_userinfo';
}
return 'snsapi_base';
}
return 'snsapi_userinfo';
}
}