jsonResult('', 0, '禁止登录'); // } $ip = $_SERVER['REMOTE_ADDR']; $imeil = trim($this->input('imeil')); $memberModel = new Members; $frozenModel = new ChannelFrozen; $channelModel = new Channel; $settingModel = new Setting(); $type = $this->input('type'); //注册类型,为mobile时表示手机号注册 $code = $this->input('sms_code'); //短信验证码 $password = trim($this->input('password','')); //明文密码 $gameid = $this->input('gameid'); $dy_channel_id = $this->input('dy_channel_id',0); $channel_id = $this->input('channel_id'); $oaid = $this->input('oaid',''); $androidid = $this->input('androidid',''); $imei = $this->input('imei',''); //海外游戏ip限制 if(in_array($gameid,config('haiwai_game_ids'))){ $res = (new IpLimit())->validateIp(request()->ip(),strtolower(trim($this->input('username','')))); if($res != 1){ $this->jsonResult('', -110, '国内用户禁止登录'); } } $data = [ 'username' => strtolower(trim($this->input('username',''))), 'password' => $password, 'device' => $this->input('device'), 'gameid' => $gameid, 'imeil' => $imeil, 'channel_id' => $channel_id, 'deviceinfo' => $this->input('deviceinfo'), 'mobile' => '', ]; // file_put_contents(ROOT_PATH.'3.txt',var_export($data,true)."\n",FILE_APPEND); log_message(var_export($data,true)."\n",'log',LOG_PATH . 'register/'); $result = $this->validate($data, [ ['username', 'require|length:6,11|alphaNum', '请输入用户名| 用户名长度为 6 - 11|用户名只能是字母或者数字'], ['password', 'require|length:6,15', '请输入密码|密码长度为 6 - 15'], ['device', 'require|integer', '获取不到设置信息|设备信息必须为整型'], ['gameid', 'require|integer|gt:0', '游戏ID不能为空|游戏ID必须为整型|游戏ID必须大于0'], ['channel_id', 'require|integer', '渠道不能为空|渠道错误'], ['imeil', 'require', '设备imeil不能为空'] ]); if (true !== $result) { $this->jsonResult('', -100, $result); } $channelInfo = $channelModel->where(['status'=>1,'id'=>$channel_id])->find(); if(!$channelInfo && intval($channel_id)<>config('EMPTY_CHANNEL_ID')) { $this->jsonResult('',-120,'渠道信息不存在'); } else if($channelInfo['level'] <> 3){ $this->jsonResult('', -120, '非推广员渠道,不能进行推广,请联系客服'); } if (!$game = model('Common/Game')->where(['id' => $gameid])->find()) { $this->jsonResult('', -120, '游戏信息不存在'); } if ($game['cooperation_status'] == 3) { $this->jsonResult('', -120, '游戏已下架不存在'); } if ($game['is_register'] == 1) { $gameInfo = Db::table('cy_gameinfo')->where(['game_id' => $gameid])->field('ban_register_msg, ban_channel_ids')->find(); // 判断当前渠道是否在封禁渠道列表中 $banChannelIds = $gameInfo['ban_channel_ids'] ?? ''; if (!empty($banChannelIds)) { $isBanChannel = false; if ($banChannelIds === 'all') { // 所有渠道都封禁 $isBanChannel = true; } else { $banIds = explode(',', $banChannelIds); $banIds = array_filter(array_map('intval', $banIds)); // 判断当前渠道是否直接在封禁列表中 if (in_array(intval($channel_id), $banIds)) { $isBanChannel = true; } else { // 判断当前渠道的上级渠道是否在封禁列表中 $channelInfo = Db::name('nw_channel')->where(['id' => $channel_id])->field('parent_id, level')->find(); if (!empty($channelInfo)) { // 获取所有上级渠道ID $parentIds = []; $parentId = $channelInfo['parent_id']; while ($parentId > 0) { $parentIds[] = $parentId; $parent = Db::name('nw_channel')->where(['id' => $parentId])->field('parent_id')->find(); $parentId = $parent ? $parent['parent_id'] : 0; } // 判断上级渠道是否在封禁列表中 if (!empty(array_intersect($parentIds, $banIds))) { $isBanChannel = true; } } } } // 如果当前渠道在封禁列表中,返回封禁提示 if ($isBanChannel) { $ban_register_msg = '目前游戏禁止注册!'; if (!empty($gameInfo['ban_register_msg'])) { $ban_register_msg = $gameInfo['ban_register_msg']; } $this->jsonResultUnescape('', -120, $ban_register_msg); } } else { // 没有设置封禁渠道,走原来的逻辑(全部封禁) $ban_register_msg = '目前游戏禁止注册!'; if (!empty($gameInfo['ban_register_msg'])) { $ban_register_msg = $gameInfo['ban_register_msg']; } $this->jsonResultUnescape('', -120, $ban_register_msg); } } // ## 指定游戏限制只能手机号注册 ## if(in_array($data['gameid'], ['344', '345']) && 'mobile' != $type){ $this->jsonResultUnescape('', -120, '当前注册方式已关闭,请使用手机号注册!'); } // 游客注册时 if ('visitor' == $type) { $this->jsonResult('', -120, '已关闭游客模式,请注册账号!客服QQ:' . CUSTOMER_SERVICE_QQ); // 判断是否已有注册游客(imeil为限制条件) $memberInfo = Db::table('cy_memberstwo a,cy_members b') ->field('a.userid, b.username') ->where('a.userid=b.id') ->where([ 'b.imeil' => $imeil, 'a.realname'=> '-1', 'a.idcard' => '-1' ]) ->find(); // 游客账号已存在,直接登录 if ($memberInfo) { //判断游戏是否冻结IP或者IMEI $LoginIp = request()->ip(); $BannedInfo = model('GameBanned')->where(['game_id'=>array('in',[0,$gameid]), 'banned_type'=>'ip','banned_device'=> $LoginIp])->find(); if(!empty($BannedInfo)){ $template = '【封禁提示】IP禁止注册:' .' ip:'.$LoginIp; curlDD($template, Env::get('notice_weelfar_url'), true); $this->jsonResult('',-120,'您的IP已被禁止登录此游戏! '); } if($imeil){ $BannedInfo = model('GameBanned')->where(['game_id'=>array('in',[0,$gameid]), 'banned_type'=>'imeil','banned_device'=> $imeil])->find(); if(!empty($BannedInfo)){ $template = '【封禁提示】设备禁止注册:' .' imeil:'.$imeil; curlDD($template, Env::get('notice_weelfar_url'), true); $this->jsonResult('',-120,'该设备已被禁止登录此游戏! '); } } // 渠道禁止判断 if (isFrozenOption($data['channel_id'],$gameid,'member_login')) { $this->jsonResult('',-120,'您所在渠道已经被禁止登录此游戏! '); } //密码加密,用于生成旧SDK的memkey $data['password'] = auth_code($data['password'],"ENCODE", Env::get($this->aesKey)); // 登录处理 $returnData = $this->loginProcess(array_merge($data, [ 'userid' => $memberInfo['userid'], 'username' => $memberInfo['username'], 'gameid' => $gameid]) ); $this->jsonResultUnescape($returnData, 200, '注册成功!'); } } //手机注册时,短信验证 if('mobile' == $type) { $sms = new Sms; $codeResult = $sms->checkCode($data['username'], $code); if(!$codeResult['status']) { $this->jsonResult('', -120, $codeResult['msg']); } $data['mobile'] = $data['username']; } if(!empty($memberModel->field('id')->where(['username' => $data['username']])->find())) { $this->jsonResult('', -120, '用户已经存在'); } //空渠道游戏不可注册开关开启,渠道ID=100做为默认渠道(空渠道) if($data['channel_id']==config('EMPTY_CHANNEL_ID')){ $empty_register_switch = $settingModel::getSetting('EMPTY_REGISTER_SWITCH'); if($empty_register_switch){ $this->jsonResult('', -120, '渠道号为空,无法注册'); } } else { //未分包渠道的游戏不可注册开关开启 $channel_register_switch = $settingModel::getSetting('CHANNEL_REGISTER_SWITCH'); if($channel_register_switch){ $conditions = array(); $conditions['gameid'] = $gameid; $conditions['channel_id'] = $data['channel_id']; // $conditions['status'] = 1; $conditions['upload_status'] = 1; $conditions['filename'] = array("neq",""); $subPackageCnt = model('SdkGameList')->where($conditions)->count(); if(!$subPackageCnt){ $this->jsonResult('', -120, '渠道暂未分包,无法注册用户'); } } } //判断游戏是否冻结IP或者IMEI $LoginIp = request()->ip(); $BannedInfo = model('GameBanned')->where(['game_id'=>array('in',[0,$gameid]), 'banned_type'=>'ip','banned_device'=> $LoginIp])->find(); if(!empty($BannedInfo)){ $template = '【封禁提示】IP禁止注册:' .' ip:'.$LoginIp; curlDD($template, Env::get('notice_weelfar_url'), true); $this->jsonResult('',-120,'您的IP已被禁止注册此游戏! '); } if($imeil){ $BannedInfo = model('GameBanned')->where(['game_id'=>array('in',[0,$gameid]), 'banned_type'=>'imeil','banned_device'=> $imeil])->find(); if(!empty($BannedInfo)){ $template = '【封禁提示】设备禁止注册:' .' imeil:'.$imeil; curlDD($template, Env::get('notice_weelfar_url'), true); $this->jsonResult('',-120,'该设备已被禁止注册此游戏! '); } } //是否禁止注册 if (isFrozenOption($data['channel_id'],$data['gameid'],'register')) { $this->jsonResult('', -120, '您所在渠道已经被禁止注册此游戏'); } //渠道注册限制检查 $this->chkChannelConfig($data['channel_id'],$data['gameid']); //当前时间 $now_time = NOW_TIMESTAMP; //密码加密 $data['password'] = auth_code($data['password'],"ENCODE", Env::get($this->authKey)); $data['reg_time'] = $now_time; $data['login_time'] = $now_time; $data['ip'] = request()->ip(); $data['dy_channel_id'] = $dy_channel_id; // ## 注册管控 ## if($ip && regidterHandle($ip, $imeil) == false){ $this->jsonResult('', -120, '当前注册已达上限!'); } // 启动事务 Db::startTrans(); try{ $member_id = $memberModel->insertGetId($data); if ($member_id) { // 插入玩家历史记录 Db::table('cy_member_history')->insert([ 'userid' => $member_id, 'password' => $data['password'], 'mobile' => $data['mobile'], 'ip' => request()->ip(), 'create_time' => $now_time ]); $realname = ''; $idcard = ''; // 游客注册 增加组合标识 认证字段双-1 if ( 'visitor' == $type ) { $realname = -1; $idcard = -1; } //插入用户扩展记录 Db::table('cy_memberstwo')->insert([ 'userid' => $member_id, 'username' => $data['username'], 'realname' => $realname, 'idcard' => $idcard, 'create_time' => $now_time ]); //绑定抖音channel 和 平台内的channel $dy_channel_info = Db::table("mw_dy_channel_rel") ->where("channel_id",$data['channel_id']) ->where("dy_channel_id",$data['dy_channel_id'])->find(); if(empty($dy_channel_info)){ $dy_channel_rel = [ 'channel_id'=>$data['channel_id'], 'dy_channel_id'=>$data['dy_channel_id'], 'create_time'=>NOW_TIMESTAMP, 'update_time'=>NOW_TIMESTAMP, ]; Db::table("mw_dy_channel_rel")->insert($dy_channel_rel); } // 登录处理 $returnData = $this->loginProcess(array_merge($data, ['userid' => $member_id, 'gameid' => $gameid,'oaid'=>$oaid])); } else{ throw new Exception("注册失败!"); } // 提交事务 Db::commit(); } catch (\Exception $e) { // 回滚事务 Db::rollback(); $this->jsonResult('', -130, '注册失败!' . $e->getMessage()); } if ($game['is_login'] == 1) { $this->jsonResultUnescape('', -120, '注册成功,目前禁止登录!'); } // ## 风控 $fkData = [ 'user_name' => $data['username'], // username 'ip' => request()->ip(), // ip 'imei' => $imeil, // imei ]; $fkResult = (new FkStrategiesService())->handleBlackList($fkData); // 注册 if ($fkResult['status']) { $this->jsonResult('', -120, "异常注册!当前账户已被禁用!请联系客服处理!客服QQ: " . CUSTOMER_SERVICE_QQ); } //return数据时,不能放在事物里面 $this->jsonResultUnescape($returnData, 200, '注册成功!'); } /** * 随机生成唯一用户名 * */ public function createUsername() { $memberModel = new Members(); $username = strtolower(random(11)); while ($memberModel->field('id')->where(['username' => $username])->find()) { $username = strtolower(random(11)); } $this->jsonResult(['username' => $username], 1, '用户名生成成功'); } /** * 根据类型生成不同格式的用户名 * * @return void * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function createChexkUsername() { $memberModel = new Members(); $type = input('type', 1); // 获取类型参数,默认为1 $username = ''; // 根据类型生成不同格式的用户名 switch ($type) { case 1: // 三个字母(不含i、o) + 五个数字 $username = $this->generateUsername(3, 5); break; case 2: // 四个字母(不含i、o) + 三个数字 $username = $this->generateUsername(4, 3); break; default: // 默认使用类型1的规则 $username = $this->generateUsername(3, 5); } // 如果不是空字符串,检查数据库唯一性 if ($username !== '') { while ($memberModel->field('id')->where(['username' => $username])->find()) { // 重新生成用户名 if ($type == 2) { $username = $this->generateUsername(4, 3); } else { $username = $this->generateUsername(3, 5); } } } $this->jsonResult(['username' => $username], 1, '用户名生成成功'); } /** * 生成指定格式的用户名 * @param int $letterCount 字母数量 * @param int $numberCount 数字数量 * @return string */ private function generateUsername($letterCount, $numberCount) { // 可用字母(排除i和o) $letters = 'abcdefghjklmnpqrstuvwxyz'; $numbers = '0123456789'; $username = ''; // 生成字母部分 for ($i = 0; $i < $letterCount; $i++) { $username .= $letters[rand(0, strlen($letters) - 1)]; } // 生成数字部分 for ($i = 0; $i < $numberCount; $i++) { $username .= $numbers[rand(0, strlen($numbers) - 1)]; } return $username; } /** * 登录处理 * * @param $data array 玩家信息 * */ private function loginProcess($data) { $logininfoModel = new Logininfo; $memberModel = new Members(); $subaccountModel = new Subaccount(); $cy_member_channel_game_rel = Db::name('cy_member_channel_game_rel'); // 登录时 绑定该游戏的归属渠道 $info = $cy_member_channel_game_rel->where(['member_id' => $data['userid'], 'game_id' => $data['gameid']])->find(); //子账号用户名 $gameAccountInfo = $subaccountModel->where(['game_id' => $data['gameid'], 'member_id' => $data['userid']])->find(); $sub_username = $gameAccountInfo['sub_username'] ?? ''; // 首次登录 if (empty($info)) { $userId = $data['userid']; $channelId = $data['channel_id']; $gameId = $data['gameid']; $cy_member_channel_game_rel->insert([ 'member_id' => $userId, 'channel_id' => $channelId, 'game_id' => $gameId, 'mcgr_createtime' => time(), 'update_time' => time(), 'mcgr_imeil' => $data['imeil'], 'mcgr_ip' => request()->ip() ]); // 插入玩家游戏渠道绑定记录 $channelName = model('Channel')->where(['id'=>$channelId])->value('name'); $gameName = model('Common/Game')->where(['id'=>$gameId])->value('name'); Db::table('cy_member_history')->insert([ 'userid' => $userId, 'channel' => $gameName.",".$channelName, 'ip' => request()->ip(), 'create_time' => time() ]); // 用于首充发放 (用于首次登录) // (new Coin())->autoSend($gameId, $channelId, $userId); } else{ //更新游戏最后登录时间 $userId = $data['userid']; $channelId = $data['channel_id']; $gameId = $data['gameid']; if($userId && $channelId && $gameId){ $cy_member_channel_game_rel->where(['member_id'=>$userId,'game_id'=>$gameId])->update(['update_time'=> time()]); } } //为了兼容旧SDK保存memkey,新SDK没有用到这个值,旧SDK关闭后可以删除该代码 $userNickName = random(3).$data['userid']; $memberModel->where(['id'=>$data['userid']])->update(['memkey'=>md5($data['username'].$data['password'].rand(0,1000)),'nickname'=>$userNickName]); //子账号信息没有时 if(empty($sub_username)){ // 指定的几款游戏 不需要注册,账号从cy_members 取 // $settingModel = new Setting(); // $accountArr = explode(',',$settingModel->getSetting('ANDROID_IOS_ACCOUNT')); // // if (in_array($data['gameid'],$accountArr)){ // $sub_username = $data['username']; // }elseif( $data['gameid'] > 220 ){ // $sub_username = $data['userid']; // } else{ // $sub_username = strtolower(random(20)); // // //保证子账号名唯一性 // while ($subaccountModel->field('id')->where(['sub_username' => $sub_username])->find()) { // $sub_username = strtolower(random(20)); // } // } $sub_username = $data['userid'].'_'.APP_STATUS; if(in_array($data['gameid'], [652, 653, 654, 655])){ $sub_username = $data['userid']; } $gameAccountInfo = $subaccountModel->create([ 'member_id' => $data['userid'], 'game_id' => $data['gameid'], 'channel_id' => $data['channel_id'], 'sub_username' => $sub_username, 'create_time' => time(), 'update_time' => time(), 'last_imeil' => $data['imeil'], ]); } //插入登录记录 $logininfoModel->limitInsert([ "sub_id"=> $gameAccountInfo['id'], "userid" => $data['userid'], "gameid" => $data['gameid'], "imeil"=> $data['imeil'], "device" => $data['device'], "reg_time" => NOW_TIMESTAMP, "fromflag" => 1, "channel_id" => $data['channel_id'], "login_time" => NOW_TIMESTAMP, "ip" => request()->ip(), ]); // $memberLogic = new MemberLogic; //同步用户信息到账户中心 // $openid = $memberLogic->syncMember($data['username'], $password, $data['mobile'], $now_time); // $signStr = "username=".$openid."&appkey=".$this->appInfo['appkey']."&logintime=".$now_time; // $returnData['sign'] = md5($signStr); // $returnData['memkey'] = md5($openid.$password.rand(0,1000)); //登录生成用户key // $returnData['login_time'] = $logData['login_time']; // $returnData['openid'] = $openid; // $memberModel->update(['memkey' => $returnData['memkey']], ['id' => $member_id]); // 更新常用设备列表 try { $memberDevice = new MemberDevice(); $memberDevice->addDevice($data['userid'], $data['gameid'], $data['imeil'], $data['device'], true); } catch (\Exception $e) { // 设备记录更新失败不影响登录流程 trace('设备记录更新失败:' . $e->getMessage(), 'error'); } $platform = ($data['device']==3 ? 1 : 0); //收集设备信息 $this->saveDevices($data['gameid'],$data['imeil'],$platform); //token最后的随机码 $token_random = random(8); $token = auth_code($data['userid'] . '|' . $data['username'] . '|' . $data['gameid'].'|' .$sub_username.'|'.$token_random.'|sdk|v3',"ENCODE", Env::get($this->authKey)); \think\Cache::store('redis')->set($token, $data['imeil'], 60 * 60 * 24 * 30); \think\Cache::store('redis')->set('token|sdk|'.$data['userid'].'|'.$data['gameid'], $token_random, 60 * 60 * 24 * 30); // 用户推广信息保存 // setChannelId($data['userid'],$channelId); // if(isset($data['oaid'])){ // //2022-10-13 抖音推送 // $extend = [ // 'Oaid' => $data['oaid'], // 'Idfa' => '', // 'Androidid' => '', // 'Imei' => $data['imeil'], // 'PayAmount' => 0, // 'Ip'=>request()->ip() // ]; // $tiktokService = new TiktokService(); // $tiktokService->push('tiktok.active_register', $userId, $gameId, $channelId, $extend); // } // 风控: 记录注册时间(记录60s) \think\Cache::store('redis')->set('fk_register_time:'.$data['username'], time(), 60); $returnData['token'] = $token; $returnData['username'] = $data['username']; //主账号名 $returnData['sub_username'] = $sub_username; //子账号名 // ## JWT:仅版本号大于 v3.6.6 的客户端返回 ## if (!empty($this->version) && version_compare($this->version, '3.6.8', '>')) { $jwtKey = trim((string) Env::get('jwt.jwt_key', '')); $jwtExpTime = (int) Env::get('jwt.exp_time', 0); $returnData['jwt_token'] = ''; if ($jwtKey === '' || $jwtExpTime <= 0) { trace('JWT配置缺失或错误,请检查jwt.jwt_key和jwt.exp_time', 'error'); } else { $jwtIssuedAt = time(); $jwtUserData = [ 'member_id' => $data['userid'], 'username' => $data['username'], 'game_id' => $data['gameid'], 'sub_id' => $gameAccountInfo['id'], 'channel_id' => $gameAccountInfo['channel_id'], 'iat' => $jwtIssuedAt, 'exp' => $jwtIssuedAt + $jwtExpTime, ]; $returnData['jwt_token'] = JwtToken::encode($jwtUserData, $jwtKey); } } //$demo_token['productdesc'] = $token; // Db::name('cy_demo')->insertGetId($demo_token); return $returnData; } /** * 检查渠道登录注册限制 */ public function chkChannelConfig($channel_id,$gameid) { //该配置表暂时默认只有一笔记录,直接写定 $id = 1; $ChannelConfig = model('channelConfig')->where(['id' => $id])->find(); if($channel_id && $ChannelConfig && intval($ChannelConfig['status'])){ //存在且开启验证 if(trim($ChannelConfig['free_channel'])){ //白名单渠道不做验证 $FreeChannelArr = explode(',',trim($ChannelConfig['free_channel'])); if(in_array($channel_id,$FreeChannelArr)){ return true; } } // 判断渠道注册是否超过阈值,有配置值时验证 $register_most = intval($ChannelConfig['register_most']); $time_warning_registered = intval($ChannelConfig['register_period']); if($register_most && $time_warning_registered){ $key = 'aoyousdk_register_most:gameid:'. $gameid. 'channel_id:'. $channel_id; $is_register = $this->register_times_limited($key,$register_most,$time_warning_registered*60); if(false === $is_register){ $mobiles = str_replace('|',',',trim($ChannelConfig['mobile'])); $WarningContent = 'SMS_199793630'; // $WarningContent = '游戏:[%s],渠道:[%s],当前注册量已上限,请及时跟进。'; $GameName = model("Game")->where(array('id'=>$gameid))->value('name'); $ChannelName = model("Channel")->where(array('id'=>$channel_id))->value('name'); // $WarningContent = sprintf($WarningContent, $GameName, $ChannelName); $params = array('name'=>$GameName,'channel'=>$ChannelName); $sms = new Sms(); $send = @$sms->sendNotify($mobiles, $WarningContent,$params); /* if ( $send['status'] ) { } else { } */ $template = '游戏:'.$GameName.',渠道:'.$ChannelName.',当前注册量已上限,请及时跟进,时间:'.date('Y-m-d H:i:s'); $ddurl = Env::get('dingtalk.warning_url'); $result = curlDD($template, $ddurl,true); return false; } } } return true; } /** * 渠道注册次数控制 * * @param string $key 键值 * @param int $times 个数上限 * @param int $expire 过期时间 * @return string */ private function register_times_limited($key,$times=60,$expire=60) { if(!empty($key)){ $times = is_numeric($times) ? (int)$times : 60; $expire = is_numeric($expire) ? (int)$expire : 60; $redis = Cache::store('redis'); $handler = $redis->handler(); $value = $handler->incr($key); if ($times < $value) { $handler->del($key); return false; } else if ( '1' == $value) { $handler->expire($key, $expire); } } return true; } }