123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146 |
- <?php
- /**
- * Created by PhpStorm.
- * User: Bear
- * Date: 2018/11/22
- * Time: 下午12:42
- */
- namespace app\main\service;
- use app\common\library\Ip;
- use app\common\library\Redis;
- use app\common\library\Ua;
- use app\common\library\User as LibUser;
- use app\common\model\Sign;
- use app\common\model\User as mUser;
- use app\common\model\User;
- use app\common\model\UserCollect;
- use app\common\model\UserRecentlyRead;
- use app\common\utility\WhiteList;
- use app\main\constants\AdminConstants;
- use app\main\constants\CacheConstants;
- use app\main\constants\ErrorCodeConstants;
- use app\main\constants\KafkaDotConstants;
- use app\main\constants\MessageConstants;
- use app\main\constants\MqConstants;
- use app\main\constants\OpenPlatformConstants;
- use app\main\constants\PayConstants;
- use app\main\constants\UrlConstants;
- use app\main\constants\UserConstants;
- use app\main\model\object\AnalysisObject;
- use app\main\model\object\BaseObject;
- use app\main\model\object\DotObject;
- use app\main\model\object\ReturnObject;
- use app\main\model\object\RunTimeObject;
- use app\main\model\object\UserObject;
- use app\source\model\UserUpdate;
- use fast\Random;
- use GuzzleHttp\Client;
- use Overtrue\Socialite\AuthorizeFailedException;
- use Symfony\Component\HttpFoundation\RedirectResponse;
- use think\Config;
- use think\Cookie;
- use think\exception\HttpException;
- use think\Log;
- use think\Request;
- /**
- * 处理前台用户信息
- * Class UserService
- * @package app\main\service
- */
- class UserService extends BaseService
- {
- const USER_OPERATE_EXPIRE = 86400;
- const USER_OTHER_DATA_EXPIRE = 172800; //两天
- const USER_OTHER_DATA_KEY_PREFIX= 'UOTD:';
- /**
- * @var UserService
- */
- protected static $self = NULL;
- /**
- * @var UserObject
- */
- private $libUser;
- /**
- * @var RunTimeObject
- */
- private $runTimeObject;
- /**
- * 耗时统计
- * @var int
- */
- private $useTime = 0;
- /**
- * @return UserService | UserObject
- */
- public static function instance()
- {
- if (self::$self == NULL) {
- self::$self = new self();
- }
- return self::$self;
- }
- public function getUserPhoneModel()
- {
- return model('UserPhone');
- }
- /**
- * @return User
- */
- public function getUserModel()
- {
- return model('User');
- }
- /**
- * @param LibUser $user
- * @return LibUser
- */
- public function setUserLib(LibUser $user)
- {
- return $this->getRunTimeObject()->user = $user;
- }
- /**
- * @return UserCollect
- */
- public function getUserCollectModel()
- {
- return model('UserCollect');
- }
- /**
- * @return UserRecentlyRead
- */
- public function getUserRecentlyReadModel()
- {
- return model('UserRecentlyRead');
- }
- /**
- * @return Sign
- */
- public function getSignModel()
- {
- return model('Sign');
- }
- /**
- * 更新用户操作时间
- * @param $userId
- * @param string $event
- */
- public function updateUserOperateTime($userId, $event = MessageConstants::MESSAGE_EVENT_UNSUBSCRIBE)
- {
- $time = Request::instance()->server('REQUEST_TIME');
- if ($userId) {
- $update = ['operate_time' => $time];
- if ($event != MessageConstants::MESSAGE_EVENT_UNSUBSCRIBE) {
- $user = UserService::instance()->getUserModel()->getUserInfo($userId);
- if (!empty($user) && isset($user['is_subscribe']) && $user['is_subscribe'] == UserConstants::USER_IS_SUBSCRIBE_NO) {
- $update['is_subscribe'] = UserConstants::USER_IS_SUBSCRIBE_YES;
- $update['subscribe_time'] = $time;
- }
- }
- $where = ['id' => $userId];
- UserService::instance()->update($update, $where);
- }
- }
- /**
- * 处理前台用户登录
- * @return \app\main\model\object\ReturnObject
- */
- public function frontUserLogin()
- {
- try{
- $response = false;
- if (Ua::isWeiXin()) {// 微信内
- //检测是否需要验证登录 && 检测是否登录
- if (!UrlService::instance()->checkActionMatch(OpenPlatformConstants::WEXIN_NEED_LOGIN) && !$this->isLogin()) {
- //登录
- $response = $this->login();
- }
- } else { // 其他(浏览器)
- if (UrlService::instance()->checkActionMatch(OpenPlatformConstants::BROWSER_NEED_LOGIN) && !$this->isLogin()) {
- //登录
- $response = $this->login();
- }
- }
- if ($response instanceof ReturnObject) {
- if ($response->code == ErrorCodeConstants::SUCCESS) {
- if (UserService::instance()->getRunTimeObject()->urlType == UrlConstants::REFERRAL_GROUND_PAGE_SPREAD) {
- UrlService::instance()->setUserAgentId((int)Request::instance()->get('agent_id'));
- UrlService::instance()->setUserReferralId((int)Request::instance()->get('referral_id'));
- }
- $result = UrlService::instance()->unlimitSecondaryDomain();
- if ($result->code != ErrorCodeConstants::SUCCESS) {
- return $result;
- }
- Log::info('用户已登录-> user_id:' . Cookie::get('user_id') . ' openid:' . Cookie::get('openid'));
- }
- return $response;
- }
- return $this->getReturn();
- }catch (\Exception $e){
- if ($e instanceof HttpException) {
- LogService::info('HttpException:' . $e->getMessage());
- throw $e;
- } else {
- return $this->getExceptionReturn($e);
- }
- }
- }
- /**
- * 获取用户id
- * @param $channel_id
- * @param $open_id
- * @return ReturnObject
- */
- public function getCallbackUserId($channel_id, $open_id)
- {
- $user_id = OfficialAccountsService::instance()->getOpenidModel()->getUserId($channel_id, $open_id);
- if ($user_id) {
- return $this->setData($user_id)->getReturn();
- }
- $user_id = Redis::instanceAuto()->incr('UID');
- return $this->setData($user_id)->getReturn();
- }
- /**
- * @param $channel_id
- * @param $open_id
- * @return ReturnObject
- */
- public function weChatInsertUser($channel_id, $open_id)
- {
- try {
- //获取基本信息
- $user_id = OfficialAccountsService::instance()->getOpenidModel()->getUserId($channel_id, $open_id);
- $user_info = null;
- if ($user_id) {
- $user_info = $this->getUserModel()->setConnect($user_id)->getUserInfo($user_id);
- }
- $time = time();
- //Redis 加锁
- $redis = Redis::instanceCache();
- $nxKey = 'L:' . $channel_id . ':' . $open_id;
- if (!$user_id || !$user_info) {
- if (!$nxRes = $redis->setnx($nxKey, 0)) { //已经存在
- return $this->setMsg('已存在')->getReturn();
- }
- $redis->expire($nxKey, 20); //20秒过期
- }
- //用户ID不存在时创建用户ID
- if (!$user_id) {
- if (!$user_id = $this->createUserID($channel_id, $open_id, $time)) {
- $redis->del($nxKey);
- return $this->setMsg('创建用户失败')->getReturn();
- }
- }
- //用户基本信息不存在时创建用户基本信息
- if (!$user_info) {
- if (!$info_id = $this->createUserInfo($channel_id, $open_id, $user_id, $time)) {
- $redis->del($nxKey);
- return $this->setMsg('用户基本信息添加失败')->getReturn();
- }
- //添加用户创建时间
- WhiteList::addUserCreatePayTime($user_id);
- }
- $redis->del($nxKey);
- return $this->setData($user_id)->getReturn();
- } catch (\Exception $e) {
- LogService::error('weChatInsertUser Error:' . $e->getMessage());
- return $this->setMsg('用户创建异常')->setCode(ErrorCodeConstants::EXCEPTION)->getReturn();
- }
- }
- /**
- * 创建用户基本信息
- * @param int $channel_id 渠道ID
- * @param string $open_id 微信OPEN_ID
- * @param int $user_id 用户ID
- * @param string $time 创建时间
- * @return null
- */
- public function createUserInfo($channel_id,$open_id,$user_id,$time){
- $weChatUser = [];
- try{
- $weChat = OpenPlatformService::instance()->officialAccount;
- $client = new Client(Config::get('wechat.http'));
- $weChat->http_client = $client;
- $weChatUser = $weChat->user->get($open_id);
- if(!empty($weChatUser) && !isset($weChatUser['errcode'])) {
- //获取注册赠送看点
- $ids = explode(',', Config::get('site.give_shubi_channel_id'));
- if (in_array($channel_id, $ids)) {
- $kandian_reg = 3000;
- } else {
- $kandian_reg = empty(Config::get('site.kandian_reg')) ? 0 : intval(Config::get('site.kandian_reg'));
- }
- $user = new UserObject();
- $user->id = $user_id;
- $user->openid = $open_id;
- $user->nickname = $weChatUser['nickname'] ?? '书友';
- $user->sex = $weChatUser['sex'] ?? 0;
- $user->first_cancel_pay = 2;
- $user->avatar = $weChatUser['headimgurl'] ?? cdnurl('/assets/img/frontend/icon/nav_icon_4.png');
- $user->is_subscribe = $weChatUser['subscribe'] ?? 0;
- $user->subscribe_time = $weChatUser['subscribe_time'] ?? 0;
- $user->operate_time = $time;
- $user->channel_id = $channel_id;
- $user->country = $weChatUser['country'] ?? '';
- $user->province = $weChatUser['province'] ?? '';
- $user->city = $weChatUser['city'] ?? '';
- $user->createtime = $time;
- $user->updatetime = $time;
- $user_info_id = $this->getUserModel()->setConnect($user->id)->insertGetId($user->toArray());
- if($user_info_id){
- //新增用户累计
- $cid = AdminService::instance()->getAdminExtendModel()->getChannelId($channel_id);
- $cacheKey = CacheConstants::getNewUserCacheKey($cid);
- Redis::instance()->incr($cacheKey);
- Redis::instance()->expire($cacheKey, 86400);
- LogService::debug('用户累计增加');
- //赠送用户免费看点
- $this->addFreeKanDian($user_id,$kandian_reg,$time);
- //新增用户打点
- $dotData = new DotObject();
- $dotData->user_id = $user_info_id;
- $dotData->channel_id = $channel_id;
- $dotData->sex = $user->sex;
- $dotData->action_type = MqConstants::ROUTING_KEY_SUBSCRIBE;
- $dotData->type = MqConstants::MSG_TYPE_INCREASE;
- $dotData->event_time = Request::instance()->server('REQUEST_TIME');
- MqService::instance()->sendMessage($dotData);
- //性别打点
- if ($user->sex) {
- $oSexAna = new AnalysisObject();
- $oSexAna->event_time = $dotData->event_time;
- $oSexAna->type = KafkaDotConstants::TYPE_SEX;
- $oSexAna->data['sex'] = $user->sex;
- $oSexAna->data['user_collect'] = 1;
- KafkaDotService::instance()->sendMsg($user_info_id, $oSexAna);
- }
- //新增打点
- $oAna = new AnalysisObject();
- $oAna->event_time = $dotData->event_time;
- $oAna->type = KafkaDotConstants::TYPE_NEW;
- $oAna->data['user_collect'] = 1;
- KafkaDotService::instance()->sendMsg($user_info_id, $oAna);
- BookService::instance()->insertShelfRecommendBooks($user_info_id, $user->sex,$channel_id);
- return $user_info_id;
- }
- LogService::error('创建用户基本信息失败,USER表写入失败 Data:' . $user->toJson());
- }
- }catch (\Exception $e){
- LogService::notice('创建用户基本信息失败,Error:' . $e->getMessage());
- } finally {
- LogService::notice(json_encode($weChatUser, JSON_UNESCAPED_UNICODE));
- }
- return null;
- }
- /**
- * 伪造用户信息 (手机号注册时伪造openID创造用户)
- * @param int $channel_id 渠道ID
- * @param string $open_id 微信OPEN_ID
- * @param string $time 创建时间
- * @return null
- */
- public function fakeUserInfo($channel_id, $open_id, $phone, $time, $business_line = '0')
- {
- $redisAuto = Redis::instanceAuto();
- $user_id = $redisAuto->incr('UID'); //redis自增返回新的user_id
- try {
- //获取注册赠送看点
- $kandian_reg = empty(Config::get('site.phone_bind_credit')) ? 0 : intval(Config::get('site.phone_bind_credit'));
- $user = new UserObject();
- $user->id = $user_id;
- $user->openid = $open_id;
- $user->nickname = '书友';
- $user->sex = 0;
- $user->mobile = $phone;
- $user->first_cancel_pay = 2;
- $user->avatar = cdnurl('/assets/img/frontend/icon/nav_icon_4.png');
- $user->is_subscribe = 0;
- $user->subscribe_time = 0;
- $user->operate_time = $time;
- $user->channel_id = $channel_id;
- $user->country = '';
- $user->province = '';
- $user->city = '';
- $user->createtime = $time;
- $user->updatetime = $time;
- $user->business_line = PayConstants::BUSINESS_APP;
- if ($user_info_id = $this->getUserModel()->setConnect($user->id)->insertGetId($user->toArray())) {
- //赠送用户免费看点
- $this->addFreeKanDian($user_id, $kandian_reg, $time, 'APP手机注册赠送书币', $business_line);
- //新增用户打点
- $dotData = new DotObject();
- $dotData->user_id = $user_info_id;
- $dotData->channel_id = $channel_id;
- $dotData->sex = $user->sex;
- $dotData->action_type = MqConstants::ROUTING_KEY_SUBSCRIBE;
- $dotData->type = MqConstants::MSG_TYPE_INCREASE;
- $dotData->event_time = Request::instance()->server('REQUEST_TIME');
- MqService::instance()->sendMessage($dotData);
- return $user_info_id;
- }
- Log::error('创建用户基本信息失败,USER表写入失败 Data:' . $user->toJson());
- } catch (\Exception $e) {
- Log::error('创建用户基本信息失败,Error:' . $e->getMessage());
- }
- return null;
- }
- /**
- * 添加用户免费看点
- * @param int $user_id 用户ID
- * @param int $kandian_reg 注册赠送看点
- * @param int $time 添加时间
- * @param string $notes 备注
- */
- public function addFreeKanDian($user_id,$kandian_reg,$time, $notes = '新用户注册赠送', $business_line = '0'){
- try{
- if (!$kandian_reg) {
- return;
- }
- //赠送用户免费书币
- $endTime = intval(Config::get('site.kandian_free_day')) * 86400;
- $rdata = [];
- $rdata['free_kandian'] = $kandian_reg;
- $rdata['remain_free_kandian'] = $kandian_reg;
- $rdata['type'] = 3;
- $rdata['user_id'] = $user_id;
- $rdata['free_endtime'] = $endTime + $time;
- $rdata['business_line'] = $business_line;
- $rdata['notes'] = $notes;
- $rdata['createtime'] = $time;
- $rdata['updatetime'] = $time;
- FinancialService::instance()->getRechargeModel()->setConnect($user_id)->insertGetId($rdata);
- //存入redis
- Redis::instance()->del('ZR:' . $user_id);
- }catch (\Exception $e){
- Log::error("添加注册用户免费看点记录失败,Error:".$e->getMessage());
- }
- }
- /**
- * 创建用户ID
- * @param int $channel_id 渠道ID
- * @param string $open_id 微信OPEN_ID
- * @param string $time 创建时间
- * @return int|null
- */
- public function createUserID($channel_id, $open_id, $time)
- {
- try {
- if (ApiService::instance()->checkApiOn()) {
- return \app\source\service\UserService::instance()->createUser($channel_id, $open_id)->id;
- } else {
- $redisAuto = Redis::instanceAuto();
- //redis自增返回新的user_id
- $userId = $redisAuto->incr('UID');
- $data = ['channel_openid' => $channel_id . '_' . $open_id, 'user_id' => $userId, 'createtime' => $time, 'updatetime' => $time];
- if ($autoId = OfficialAccountsService::instance()->getOpenidModel()->setConnect($channel_id, $open_id)->insertGetId($data)) {
- return $userId;
- }
- }
- Log::error('创建用户ID失败,OPENID表写入失败 Data:' . json_encode($data));
- } catch (\Exception $e) {
- Log::error('创建用户ID失败,Error:' . $e->getMessage());
- }
- return null;
- }
- /**
- * 微信登录
- * @return bool|RedirectResponse
- * @throws \Exception
- * @throws \think\Exception
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\ModelNotFoundException
- * @throws \think\exception\DbException
- */
- public function login()
- {
- $urlType = $this->getRunTimeObject()->urlType;
- switch ($urlType) {
- case OpenPlatformConstants::URL_TYPE_ADMIN: // 后台首页
- break;
- case OpenPlatformConstants::URL_TYPE_PAY: // 充值页
- return $this->loginPay();
- break;
- case OpenPlatformConstants::URL_TYPE_SPREAD: // 推广页
- return $this->loginAgent();
- break;
- }
- return false;
- }
- /**
- * 充值页 登录
- * @return ReturnObject|bool
- * @throws \Exception
- */
- private function loginPay()
- {
- if (Ua::isWeiXin()) {
- $officialAccount = OpenPlatformService::instance()->getOfficialAccount();
- if (Request::instance()->has('code')) { // 具有code,直接获取openid
- try {
- if (Request::instance()->has('tqwv')) {
- $startTime = floatval(Request::instance()->param('tqwv'));
- $endTime = microtime(true);
- $this->useTime = $this->useTime + ($endTime - $startTime);
- Log::info(sprintf('WeChat->LoginPay->Auth->Time StartTime:%f EndTime:%f RunTime:%f', $startTime, $endTime, $endTime - $startTime));
- }
- $getOpenIDSTime = microtime(true);
- $user = $officialAccount->oauth->user();
- $getOpenIDETime = microtime(true);
- Cookie::forever('app_id', Config::get('wechat.app_id'));
- Cookie::forever('openid', $user->getId());
- Cookie::forever('open_id', $user->getId());
- $this->useTime = $this->useTime + ($getOpenIDETime - $getOpenIDSTime);
- Log::info(sprintf('WeChat->LoginPay->OpenID->Time OpenID:%s StartTime:%f EndTime:%f RunTime:', $user->getId(), $getOpenIDSTime, $getOpenIDETime, $getOpenIDETime - $getOpenIDSTime));
- } catch (\Exception $e) {
- return $this->loginFail($officialAccount, $e, 'tqwv');
- }
- } else {
- $startTime = microtime(true);
- $url = get_url_no_port(true);
- if (stripos($url, '?') === false) {
- $url .= '?tqwv=' . $startTime;
- } else {
- $url .= '&tqwv=' . $startTime;
- }
- $url = del_url_params($url, 'code');
- $response = $officialAccount->oauth->scopes(['snsapi_base'])->redirect($url); //获取code
- return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($response->getTargetUrl())->getReturn();
- }
- } else {
- $redirect = '/index/login/login?redirect=' . get_url_no_port(true);
- return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($redirect)->getReturn();
- }
- return true;
- }
- /**
- * 推广页 登录
- * @return \app\main\model\object\ReturnObject|bool|RedirectResponse
- * @throws \Exception
- * @throws \think\Exception
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\ModelNotFoundException
- * @throws \think\exception\DbException
- */
- private function loginAgent()
- {
- $urlChannelId = $this->getRunTimeObject()->channelId;
- if (Ua::isWeiXin()) {
- $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($urlChannelId);
- $refreshToken = OpenPlatformService::instance()->getRefreshToken($adminConfig['admin_id']);
- $officialAccount = OpenPlatformService::instance()->getOfficialAccount($adminConfig['appid'], $refreshToken);
- if (Request::instance()->has('code')) { // 具有code,直接获取openid
- try {
- if (Request::instance()->has('asss')) {
- $getAuthSTime = floatval(Request::instance()->param('asss'));
- $getAuthETime = microtime(true);
- $this->useTime = $this->useTime + ($getAuthETime - $getAuthSTime);
- Log::info(sprintf('WeChat->LoginAgent->Auth->Time StartTime:%f EndTime:%f RunTime:%f', $getAuthSTime, $getAuthETime, $getAuthETime - $getAuthSTime));
- //异常访问抛出异常
- if ($getAuthETime - $getAuthSTime > 60) {
- throw new HttpException(500, '访问超时!');
- }
- }
- $getOpenIDStime = microtime(true);
- $oauth = $officialAccount->oauth;
- $oauth::setGuzzleOptions(Config::get('wechat.http'));
- $user = $oauth->user();
- $openid = $user->getId();
- $getOpenIDEtime = microtime(true);
- $this->useTime = $this->useTime + ($getOpenIDEtime - $getOpenIDStime);
- Log::info(sprintf('WeChat->LoginAgent->OpenID->Time OpenID:%s StartTime:%f EndTime:%f RunTime:%f', $user->getId(), $getOpenIDStime, $getOpenIDEtime, $getOpenIDEtime - $getOpenIDStime));
- if ($openid) {
- $nxKey = 'L:' . $urlChannelId . ':' . $openid; //用户openid_渠道商id ,唯一,用于防止重复注册
- $nxRes = Redis::instanceCache()->setnx($nxKey, 0);
- if (!$nxRes) { //已经存在
- throw new HttpException(500, '请刷新页面重新访问!'); //用户创建中
- }
- Redis::instanceCache()->expire($nxKey, 20); //20秒过期
- //通过openid获取用户id
- $userId = OfficialAccountsService::instance()->getOpenidModel()->getUserId($urlChannelId, $openid);
- if ($userId) {
- //通过userid获取用户信息
- $userInfo = $this->getUserModel()->setConnect($userId)->getUserInfo($userId);
- } else {
- $userInfo = false;
- }
- if ($userId && $userInfo) { //已经存在用户
- Redis::instanceCache()->del($nxKey);
- UserService::instance()->setUserCache($userId);
- } else {
- try {
- if (!$userId) { //存在 openid表插入成功,但user表插入失败的情况。所以单独做逻辑判断
- // 添加openid表信息
- $userId = $this->createUserID($urlChannelId, $openid, time());
- if (!$userId) {
- Log::error('创建用户失败!openid表插入数据失败!' . $urlChannelId . ':' . $openid);
- throw new HttpException(500, '创建用户失败!');
- }
- }
- $user = new UserObject();
- $user->id = $userId;
- $user->openid = $openid;
- $user->referral_id = (int)Request::instance()->get('referral_id');
- $user->referral_id_permanent = $user->referral_id;
- $user->agent_id = (int)Request::instance()->get('agent_id');
- $id = $this->insert($user);
- } catch (\Exception $exception) {
- Log::error('创建用户失败!' . $exception->getMessage());
- $id = null;
- }
- Redis::instanceCache()->del($nxKey);
- if (!$id) {
- Log::error('创建用户失败!user表插入数据失败!');
- throw new HttpException(500, '创建用户失败!');
- }
- $referral_id = UrlService::instance()->getUserReferralId()->data;
- if (isset($wechatUser) && !isset($wechatUser['errcode']) && !$wechatUser['subscribe'] && $referral_id) {
- Redis::instance()->setex('U-T:' . $id, 172800, $referral_id); //2天有效期
- }
- $result = UrlService::instance()->unlimitSecondaryDomain();
- if ($result->code != ErrorCodeConstants::SUCCESS) {
- return $result;
- }
- }
- }
- Log::info(sprintf('WeChat->CallInterface->Time UseTime:%f', $this->useTime));
- } catch (AuthorizeFailedException $e) {
- return $this->loginFail($officialAccount, $e, 'asss');
- }
- } else {
- $startTime = microtime(true);
- $url = get_url_no_port(true);
- //删掉多余参数
- $url = del_url_params($url, ['code', 'asss', 'state']);
- if (stripos($url, '?') === false) {
- $url .= '?asss=' . $startTime;
- } else {
- $url .= '&asss=' . $startTime;
- }
- //todo url跳转遗漏
- $response = $officialAccount->oauth->scopes(['snsapi_base'])->redirect($url); //获取code
- return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($response->getTargetUrl())->getReturn();
- }
- } else {
- $redirect = '/index/login/login?redirect=' . get_url_no_port(true);
- return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($redirect)->getReturn();
- }
- return $this->getReturn();
- }
- /**
- * @param \EasyWeChat\OfficialAccount\Application $officialAccount
- * @param \Exception $e
- * @param string $startQueryParamName
- * @return mixed
- */
- private function loginFail($officialAccount, $e, $startQueryParamName)
- {
- $errMsg = $e->getMessage();
- Log::notice('WeChat->Login->Error:' . $errMsg);
- $errMsg = str_replace('Authorize Failed:', '', $errMsg);
- $body = json_decode($errMsg, true);
- if (is_array($body) && in_array($body['errcode'], [40163, 40029, 41008])) { //code已被使用 或 code无效
- Log::notice('code 无效,重试一次 [ CODE ]: ' . $body['errcode']);
- $startTime = microtime(true);
- $url = UrlService::instance()->getUrlNoPort(true);
- if (stripos($url, '?') === false) {
- $url .= "?$startQueryParamName=$startTime";
- } else {
- $url .= "&$startQueryParamName=$startTime";
- }
- $url = UrlService::instance()->delUrlParams($url, 'code');
- if (!Request::instance()->has('jump_self')) {
- $url .= '&jump_self=1';
- $response = $officialAccount->oauth->scopes(['snsapi_base'])->redirect($url); //获取code
- return $this->setCode(ErrorCodeConstants::REDIRECT)->setData($response->getTargetUrl())->getReturn();
- }
- }
- }
- /**
- * 注册用户-推广页
- * @param $data
- * @return int|string
- * @throws \Exception
- */
- public function insert($data)
- {
- if (!($data instanceof BaseObject) && is_array($data)) {
- $data = (new UserObject())->bind($data);
- }
- $channelId = $this->getRunTimeObject()->channelId;
- $time = time();
- $ids = explode(',', Config::get('site.give_shubi_channel_id'));
- if (in_array($channelId, $ids)) {
- $kandian_reg = 3000;
- } else {
- $kandian_reg = empty(Config::get('site.kandian_reg')) ? 0 : intval(Config::get('site.kandian_reg'));
- }
- $default = new UserObject();
- $default->nickname = '书友';
- $default->avatar = cdnurl('/assets/img/frontend/icon/nav_icon_4.png');
- $default->channel_id = $channelId;
- $default->register_ip = Ip::ip() ?? null;
- $default->country = Ip::country();
- $default->area = Ip::area();
- $default->province = Ip::province();
- $default->first_cancel_pay = 2;
- $default->is_subscribe = 0;
- $default->subscribe_time = 0;
- $default->city = Ip::city();
- $default->sex = 0;
- $default->isp = substr(Ip::isp(), 0, 30); //数据库长度 30
- $default->createtime = $time;
- $default->updatetime = $time;
- $insert = array_merge($default->toArray(), $data->toArray());
- $id = $this->getUserModel()->setConnect($data->id)->insertGetId($insert);
- if ($id) { //注册成功
- //新增用户累计
- $cid = AdminService::instance()->getAdminExtendModel()->getChannelId($channelId);
- $cacheKey = CacheConstants::getNewUserCacheKey($cid);
- Redis::instance()->incr($cacheKey);
- Redis::instance()->expire($cacheKey, 86400);
- LogService::debug('用户累计增加');
- $data->id = $id;
- UserService::setUserCache($id);
- //赠送用户免费书币
- if ($kandian_reg) {
- $endTime = intval(Config::get('site.kandian_free_day')) * 86400;
- $rdata = [];
- $rdata['free_kandian'] = $kandian_reg;
- $rdata['remain_free_kandian'] = $kandian_reg;
- $rdata['type'] = 3;
- $rdata['user_id'] = $id;
- $rdata['free_endtime'] = $endTime + $time;
- $rdata['notes'] = '新用户注册赠送';
- $rdata['createtime'] = $time;
- $rdata['updatetime'] = $time;
- FinancialService::instance()->getRechargeModel()->setConnect($id)->insertGetId($rdata);
- Redis::instance()->del('ZR:' . $id);
- }
- if ($insert['sex']) {
- $oSexAna = new AnalysisObject();
- $oSexAna->event_time = UserService::instance()->getRunTimeObject()->requestTime;
- $oSexAna->type = KafkaDotConstants::TYPE_SEX;
- $oSexAna->data['sex'] = $insert['sex'];
- KafkaDotService::instance()->sendMsg($id, $oSexAna);
- }
- //新增用户打点
- $dotData = new DotObject();
- $dotData->channel_id = $channelId;
- $dotData->sex = $insert['sex'];
- $dotData->action_type = MqConstants::ROUTING_KEY_SUBSCRIBE;
- $dotData->type = MqConstants::MSG_TYPE_INCREASE;
- $dotData->event_time = UserService::instance()->getRunTimeObject()->requestTime;
- MqService::instance()->sendMessage($dotData);
- $oAna = new AnalysisObject();
- $oAna->event_time = UserService::instance()->getRunTimeObject()->requestTime;
- $oAna->type = KafkaDotConstants::TYPE_NEW;
- //推广id的创建用户
- if ($referral_id = UrlService::instance()->getUserReferralId()->data) {
- $oAna->user_from['referral_id'] = $referral_id;
- $dotData->referral_id = $referral_id;
- $dotData->action_type = MqConstants::ROUTING_KEY_SUBSCRIBE_REFERER;
- MqService::instance()->sendMessage($dotData);
- }
- $oAna->data['user_collect'] = 1;
- KafkaDotService::instance()->sendMsg($id, $oAna);
- //加入用户统计
- // $this->getUserCollectModel()->addSubscribeCache($channelId, $data->sex, true);
- //添加用户创建时间
- WhiteList::addUserCreatePayTime($id);
- BookService::instance()->insertShelfRecommendBooks($id, $insert['sex'],$channelId);
- } else {
- Log::error('创建用户失败!user表插入数据失败!data:' . json_encode($data));
- }
- return $id;
- }
- /**
- * 刷新cookie资料
- *
- * @param $userInfo
- */
- public function refreshCookie($userInfo)
- {
- if (IS_CLI) {
- return;
- }
- if($userInfo instanceof BaseObject){
- $userInfo = $userInfo->toArray();
- }
- $urlType = $this->getRunTimeObject()->urlType;
- if (in_array($urlType, [OpenPlatformConstants::URL_TYPE_SPREAD, OpenPlatformConstants::URL_TYPE_PAY]) && $userInfo && isset($userInfo['id'])) {
- Cookie::set('user_id', $userInfo['id']);
- Cookie::set('channel_id', $userInfo['channel_id']);
- if (OpenPlatformConstants::URL_TYPE_SPREAD == $urlType) {
- Cookie::set('openid', $userInfo['openid']);
- }
- if ($userInfo['referral_id']) {
- Cookie::set('referral_id', $userInfo['referral_id']);
- } else {
- Cookie::delete('referral_id');
- }
- if ($userInfo['agent_id']) {
- Cookie::set('agent_id', $userInfo['agent_id']);
- } else {
- Cookie::delete('agent_id');
- }
- $ext = $userInfo['ext']??'';
- if ($ext) {
- Cookie::set('ext', $ext);
- } else {
- Cookie::delete('ext');
- }
- }
- }
- /**
- * 检测是否登录
- * @return bool
- */
- public function isLogin()
- {
- $urlType = $this->getRunTimeObject()->urlType;
- switch ($urlType) {
- case OpenPlatformConstants::URL_TYPE_ADMIN: // 后台首页
- break;
- case OpenPlatformConstants::URL_TYPE_PAY: // 充值页
- if (Ua::isWeiXin()) {
- if (!Cookie::has('user_id')) {
- throw new HttpException(402, '账号错误');
- }
- if (request()->isAjax()) {
- if (Cookie::has('openid') && Cookie::has('app_id') && Cookie::get('app_id') == Config::get('wechat.app_id')) {
- return true;
- }
- } else {
- if (
- Cookie::has('openid')
- && Cookie::has('open_id')
- && Cookie::get('openid') == Cookie::get('open_id')
- && Cookie::has('app_id')
- && Cookie::get('app_id') == Config::get('wechat.app_id')
- ) {
- return true;
- }
- }
- } elseif (Cookie::has('user_id')) {
- return true;
- }
- break;
- case OpenPlatformConstants::URL_TYPE_SPREAD: // 推广页
- if ($this->getUserInfo()->id) {
- return true;
- }
- break;
- }
- return false;
- }
- /**
- * 更新用户资料
- * @param $data
- * @param $where
- * @return bool
- */
- public function update($data, $where = [])
- {
- if (!$where) {
- $where['id'] = UserService::instance()->getUserInfo()->id;
- }
- if (isset($where['id']) && $where['id']) {
- $userId = $where['id'];
- if (UserService::instance()->getUserInfo()->id) {
- $this->getRunTimeObject()->user->bind($data);
- }
- if (ApiService::instance()->checkApiOn()) {
- $userUpdate = new UserUpdate();
- $userUpdate->bind($data)->setId($where['id']);
- // $data['id'] = $where['id'];
- \app\source\service\UserService::instance()->updateUser($userUpdate)->id;
- return true;
- } else {
- $result = $this->getUserModel()->setConnect($userId)->update($data, $where);
- if ($result) {
- //加入redis
- $userKey = CacheConstants::getUserCacheKey($userId);
- if(Redis::instance()->exists($userKey)){ //更改
- Redis::instance()->hmset($userKey,$data);
- Redis::instance()->expire($userKey,86400);
- }else{ //新增
- $this->getUserModel()->getUserInfo($userId);
- }
- if (!Request::instance()->isAjax() && !IS_CLI) {
- $this->refreshCookie($this->getUserInfo());
- }
- }
- return true;
- }
- }
- return false;
- }
- /**
- * 获取用户资料
- *
- * @param bool $force 是否从数据库重新获取 默认false从缓存中获取 true从数据库重新获取
- * @return UserObject
- */
- public function getUserInfo($force = false)
- {
- $urlType = $this->getRunTimeObject()->urlType;
- $user = $this->getRunTimeObject()->user;
- if (!$user || !$user->id || $force) {
- switch ($urlType) {
- case OpenPlatformConstants::URL_TYPE_ADMIN: // 后台首页
- break;
- case OpenPlatformConstants::URL_TYPE_PAY: // 充值页
- if ($userId = Cookie::get('user_id')) {
- $user = $this->getUserModel()->getUserInfo($userId, $force);
- }
- break;
- case OpenPlatformConstants::URL_TYPE_SPREAD: // 推广页
- if ($userId = Cookie::get('user_id')) {
- $user = $this->getUserModel()->getUserInfo($userId, $force);
- if (isset($user['openid']) && ($user['openid'] == Cookie::get('openid'))) {
- $this->refreshCookie($user);
- }
- }
- break;
- default:
- if ($userId = Cookie::get('user_id')) {
- $user = $this->getUserModel()->getUserInfo($userId, $force);
- }
- break;
- }
- if ($user) {
- $this->getRunTimeObject()->user = (new UserObject())->bind($user);
- $this->refreshCookie($user);
- }else{
- $this->getRunTimeObject()->user = new UserObject();
- }
- }
- if(!$this->getRunTimeObject()->user->avatar){
- $this->getRunTimeObject()->user->avatar = '/assets/img/frontend/icon/nav_icon_4.png';
- }
- return $this->getRunTimeObject()->user;
- }
- /**
- * 获取visitor,先获取cookie,若无,自动生成一个
- *
- * @param bool $force 是否强制生成一个新的
- * @return mixed|string
- */
- public function visitor($force = false)
- {
- if (!$force && Cookie::has('visitor')) {
- return Cookie::get('visitor');
- } else {
- return date('YmdHis') . Random::uuid();
- }
- }
- /**
- * 程序运行参数汇总
- * @return RunTimeObject
- */
- public function getRunTimeObject()
- {
- if(!$this->runTimeObject){
- $this->runTimeObject = new RunTimeObject();
- }
- return $this->runTimeObject;
- }
- /**
- * 魔术方法获取(只支持单级属性获取,多级属性请使用getUserInfo)
- *
- * @param $name
- * @return mixed|null
- */
- public function __get($name)
- {
- if ($this->getUserInfo()) {
- return $this->getUserInfo()->get($name) ?? null;
- } else {
- return null;
- }
- }
- /**
- * 获取用户表库索引
- * @param $user_id
- * @return int
- */
- public function getUserDBIndex($user_id)
- {
- return $user_id % 512;
- }
- /**
- * 获取openid表的库索引
- * @param $channel_id
- * @param $open_id
- * @return int
- */
- public function getOpenIdDBIndex($channel_id, $open_id)
- {
- $channel_openid = $channel_id . '_' . $open_id;
- return hash_code($channel_openid) % 512;
- }
- /**
- * 获取用户admin_id
- * @return \app\main\model\object\ReturnObject
- */
- public function getAdminId()
- {
- if ($agentId = UrlService::instance()->getUserAgentId()->data) {
- return $this->setData($agentId)->getReturn();
- } else if ($channelId = $this->getUserInfo()->channel_id) {
- return $this->setData($channelId)->getReturn();
- }
- return $this->getReturn();
- }
- public function setUserCache($user_id)
- {
- if ($user_id) {
- Cookie::set('user_id', $user_id);
- UserService::instance()->getUserInfo(true);
- }
- }
- /**
- * 更新用户缓存
- * @param $user_id
- * @param $update
- */
- public function updateRedisUserCache($user_id, $update)
- {
- $userKey = CacheConstants::getUserCacheKey($user_id);
- $this->getRunTimeObject()->user = $this->getRunTimeObject()->user->bind($update);
- if (Redis::instance()->exists($userKey)) {
- Redis::instance()->hmset($userKey, $update);
- Redis::instance()->expire($userKey, 86400);
- }
- }
- /**
- * @return ReturnObject
- */
- public function getUserChannelId()
- {
- $channelAgentId = UserService::instance()->getUserInfo()->channel_id;
- $groupId = AdminService::instance()->getAuthGroupAccessModel()->getGroupId($channelAgentId);
- if ($groupId == AdminConstants::ADMIN_GROUP_ID_AGENT) {
- $adminExtend = AdminService::instance()->getAdminExtendModel()->getInfo($channelAgentId);
- return $this->setData($adminExtend['create_by'])->getReturn();
- }
- return $this->setData($channelAgentId)->getReturn();
- }
- /**
- * 设置用户额外信息
- * @param $user_id
- * @param array $data
- * @return bool
- */
- public function setOtherDataToRedis($user_id, $data = [])
- {
- $redisKey = self::USER_OTHER_DATA_KEY_PREFIX . $user_id;
- $redisData = $data;
- if (Redis::instance()->exists($redisKey)) {
- $redisData = Redis::instance()->hGetAll($redisKey);
- $redisData = array_merge($redisData, $data);
- }
- Redis::instance()->hMSet($redisKey, $redisData);
- return Redis::instance()->expire($redisKey, self::USER_OTHER_DATA_EXPIRE);
- }
- /**
- * 获取用户额外信息
- * @param $user_id
- * @return array
- */
- public function getOtherDataFromRedis($user_id)
- {
- $result = [];
- $redisKey = self::USER_OTHER_DATA_KEY_PREFIX . $user_id;
- if (Redis::instance()->exists($redisKey)) {
- $result = Redis::instance()->hGetAll($redisKey);
- }
- return $this->setData($result)->getReturn()->data;
- }
- public function getUserIdByPhone($phone){
- $json_data = $this->getUserPhoneModel()->setConnect($phone)->getInfoByPhone($phone);
- $data = [];
- if($json_data){
- $data = json_decode($json_data, true);
- }
- return $data;
- }
- }
|