LoginController.php 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562
  1. <?php
  2. namespace App\Http\Controllers\Game;
  3. use App\Game\AgentLinks;
  4. use App\Game\GlobalUserInfo;
  5. use App\Game\QuickAccountPass;
  6. use App\Game\QuickAccountPassStore;
  7. use App\Game\RePayConfig;
  8. use App\Game\Services\AgentService;
  9. use App\Game\Services\FacebookEventService;
  10. use App\Game\Services\OuroGameService;
  11. use App\Game\Services\RouteService;
  12. use App\Game\WebChannelConfig;
  13. use App\Http\Controllers\Controller;
  14. use App\Http\helper\NumConfig;
  15. use App\IpLocation;
  16. use App\Models\Account\AccountPhone;
  17. use App\Models\AccountsInfo;
  18. use App\Models\GamePhoneVerityCode;
  19. use App\Models\SystemStatusInfo;
  20. use App\Models\Treasure\GameScoreInfo;
  21. use App\Notification\TelegramBot;
  22. use App\Services\StoredProcedure;
  23. use App\Services\VipService;
  24. use App\Util;
  25. use App\Utility\SetNXLock;
  26. use Carbon\Carbon;
  27. use Illuminate\Http\Request;
  28. use Illuminate\Support\Facades\Cookie;
  29. use Illuminate\Support\Facades\Crypt;
  30. use Illuminate\Support\Facades\DB;
  31. use Illuminate\Support\Facades\Hash;
  32. use Illuminate\Support\Facades\Log;
  33. use Illuminate\Support\Facades\Redis;
  34. use Illuminate\Support\Facades\Validator;
  35. use PDO;
  36. // use Yansongda\Pay\Log;
  37. class LoginController extends Controller
  38. {
  39. public function __construct()
  40. {
  41. }
  42. public function LoginByCode(Request $request,$onlyVerify=false)
  43. {
  44. $RegisterLocation = $request->country ?? env('COUNTRY_CODE','1');
  45. $Phone = $request->phone;
  46. $PhoneCode = $request->code;
  47. $PhoneCode= preg_replace('/\D/s', '', $PhoneCode);
  48. if (empty($Phone)) {
  49. return apiReturnFail(['web.verify.num_empty', 'PhoneNum Empty']);
  50. }
  51. if (mb_strlen($PhoneCode) > 6) {
  52. return apiReturnFail(['web.verify.code_too_long', 'Phone code is too long']);
  53. }
  54. $Phone = $RegisterLocation.trim($Phone);
  55. Log::info('验证电话开始' . $Phone);
  56. $redisKey = 'LoginByCode_' . $Phone;
  57. if (!SetNXLock::getExclusiveLock($redisKey)) {
  58. return apiReturnFail(['web.withdraw.try_again_later', 'Tente novamente mais tarde']);
  59. }
  60. if (!is_numeric($PhoneCode)) {
  61. SetNXLock::release($redisKey);
  62. Log::info('web.verify.code_incorrect_or_expired LoginByCode is_numeric($PhoneCode)',[$Phone,$PhoneCode]);
  63. return apiReturnFail(['web.verify.code_incorrect_or_expired', 'O código está incorreto ou o tempo passou']);
  64. }
  65. $verifyCode = GamePhoneVerityCode::verifyCode($Phone, $PhoneCode);
  66. SetNXLock::release($redisKey);
  67. //TODO 上线前去掉测试
  68. if ($verifyCode != trim($PhoneCode)) {
  69. Log::info('web.verify.code_incorrect_or_expired LoginByCode $verifyCode',[$Phone,$PhoneCode]);
  70. return apiReturnFail(['web.verify.code_incorrect_or_expired', 'O código está incorreto ou o tempo passou']);
  71. }
  72. if($onlyVerify)return true;
  73. $config = RouteService::getChannelConfig($request);
  74. $user = GlobalUserInfo::query()->where('RegionID', $config->isRegionUnique())->where("Phone", $Phone)->first();
  75. if ($user) {
  76. $user = GlobalUserInfo::toWebData($user);
  77. return response()->json(apiReturnSuc($user, ['login.success', 'Login bem-sucedido, bem-vindo de volta!']));//->withCookie($this->setLoginCookie($user['sign']));
  78. } else {
  79. return apiReturnFail(['web.login.notfound', 'Sua conta não foi encontrada, registre-se ou tente novamente!']);
  80. }
  81. }
  82. public function BindPhone(Request $request)
  83. {
  84. $user = GlobalUserInfo::$me;
  85. $RegisterLocation = $request->country ?? env('COUNTRY_CODE','1');
  86. $Phone = $request->phone;
  87. $PhoneCode = $request->code;
  88. if (empty($Phone)) {
  89. Log::info('web.verify.num_empty',[$Phone,$PhoneCode]);
  90. return apiReturnFail(['web.verify.num_empty', 'PhoneNum Empty']);
  91. }
  92. if (mb_strlen($PhoneCode) > 6) {
  93. Log::info('web.verify.code_too_long',[$Phone,$PhoneCode]);
  94. return apiReturnFail(['web.verify.code_too_long', 'Phone code is too long']);
  95. }
  96. $Phone = $RegisterLocation.trim($Phone);
  97. Log::info('绑定电话开始' . $Phone);
  98. $redisKey = 'BindPhone_' . $Phone;
  99. if (!SetNXLock::getExclusiveLock($redisKey)) {
  100. Log::info('web.withdraw.try_again_later',[$Phone,$PhoneCode]);
  101. return apiReturnFail(['web.withdraw.try_again_later', 'Tente novamente mais tarde']);
  102. }
  103. if (!is_numeric($PhoneCode)) {
  104. SetNXLock::release($redisKey);
  105. Log::info('web.verify.code_incorrect_or_expired BindPhone nonum',[$Phone,$PhoneCode]);
  106. return apiReturnFail(['web.verify.code_incorrect_or_expired', 'O código está incorreto ou o tempo passou']);
  107. }
  108. $verifyCode = GamePhoneVerityCode::verifyCode($Phone, $PhoneCode);
  109. if ($verifyCode != trim($PhoneCode)) {
  110. SetNXLock::release($redisKey);
  111. Log::info("web.verify.code_incorrect_or_expired BindPhone $verifyCode",[$Phone,$PhoneCode]);
  112. return apiReturnFail(['web.verify.code_incorrect_or_expired', 'O código está incorreto ou o tempo passou']);
  113. }
  114. $config = RouteService::getChannelConfig($request);
  115. // 查看手机号是否已经绑定
  116. // $first = DB::connection('write')->table('QPAccountsDB.dbo.AccountPhone')
  117. // ->where('PhoneNum', $Phone)
  118. //// ->where('Channel', $user->Channel)
  119. // ->orWhere('UserID', $user->UserID)
  120. $first = GlobalUserInfo::query()->where(function ($query) use ($Phone, $user, $config) {
  121. $query->where(function ($q) use ($Phone, $user) {
  122. $q->where('RegionID', $user->RegionID??"")->where('Phone', $Phone);
  123. })->orWhere(function ($q) use ($user) {
  124. $q->where('UserID', $user->UserID)->where('Phone', '<>', '');
  125. });
  126. })->first();
  127. if ($first) {
  128. SetNXLock::release($redisKey);
  129. Log::info('web.verify.already_bound',[$Phone,$PhoneCode]);
  130. // return apiReturnFail(['web.verify.already_bound', 'O número de telefone foi vinculado']); // 电话号码已绑定
  131. return apiReturnFail(['web.verify.already_bound', 'O número de telefone foi vinculado'],GlobalUserInfo::getGameUserInfoToWeb('UserID',$first->UserID)); // 电话号码已绑定
  132. }
  133. // if (!isset($request->password) || !isset($request->repassword) || $request->password != $request->repassword) {
  134. // Log::info("web.reg.password_notsame",[$Phone,$PhoneCode]);
  135. // return apiReturnFail(['web.reg.password_notsame', 'As senhas digitadas duas vezes são inconsistentes, digite novamente!'], '', 2);
  136. // }
  137. $PhoneNum = $Phone;
  138. $Phone = $this->checkPhone($PhoneNum, $RegisterLocation, $request);
  139. //有错误返回
  140. if (is_array($Phone)){
  141. Log::info(json_encode($Phone),[$Phone,$PhoneCode]);
  142. return $Phone;
  143. }
  144. $UserID = $user->UserID;
  145. $BindDate = Carbon::now()->toDateTimeString();
  146. $LogonPass = $request->password??$PhoneCode;
  147. $Channel = $user->Channel;
  148. $RegionID = $user->RegionID;
  149. // 绑定手机号
  150. AccountPhone::insert(compact('UserID', 'PhoneNum', 'BindDate', 'Channel','RegionID'));
  151. GlobalUserInfo::where('GlobalUID', $user->GlobalUID)->update([ 'Phone' => $Phone, 'RegisterLocation' => $RegisterLocation]);
  152. Log::info('绑定手机号'.'-'.$user->GlobalUID.'-' . $Phone . '-' . $LogonPass . '-' . $UserID);
  153. // --绑定手机赠送金币
  154. $SendGold = SystemStatusInfo::OnlyGetCacheValue('BindPhoneReward') ?? 500;
  155. DB::table('QPRecordDB.dbo.LogProp')->insert(['UserID' => $UserID, 'PropID' => 30000, 'PropNum' => $SendGold, 'Source' => 11, 'Param' => null]);
  156. OuroGameService::AddScore($UserID, $SendGold, OuroGameService::REASON_BindPhone,false);
  157. $RecordPlatformDataModel = new \App\Models\RecordPlatformData();
  158. $RecordPlatformDataModel->BindToday($Channel,$user->RegisterDate);
  159. AgentService::recordPerformance($UserID, 0,1);
  160. SetNXLock::release($redisKey);
  161. return apiReturnSuc(GlobalUserInfo::getGameUserInfoToWeb('UserID', $UserID));
  162. /**
  163. *
  164. * INSERT INTO [QPAccountsDB].[dbo].[AccountPhone] ([UserID],[PhoneNum],[BindDate],[LogonPass],[Channel])values(@UserId,@szPhoneNum,GETDATE(),@strLogonPass,@Channel)
  165. *
  166. * --绑定手机赠送金币
  167. * DECLARE @SendGold int
  168. * select @SendGold = [StatusValue] from QPAccountsDB.dbo.SystemStatusInfo where [StatusName] = 'BindPhoneReward'
  169. * if @SendGold is null
  170. * begin
  171. * set @SendGold = 500;
  172. * end
  173. *
  174. * INSERT INTO QPRecordDB.dbo.LogProp(UserID,PropID,PropNum,Source,[Param],RecordData)
  175. * VALUES(@UserId,30000,@SendGold,11,NULL,GETDATE())
  176. *
  177. * EXEC QPRecordDB.dbo.GSP_YN_GR_RecordGameScore
  178. * @dwUserID=@UserId,
  179. * @lChangeScore=@SendGold,
  180. * @nReason = 21,--绑定手机赠送
  181. * @nServerID=0,
  182. * @strUniqueCode='',
  183. * @lRevenue=0,
  184. * @Type=0
  185. *
  186. * update QPTreasureDB.dbo.GameScoreInfo set Score = Score+@SendGold where @UserId = UserID
  187. */
  188. }
  189. // public function PwaInstalled(Request $request)
  190. // {
  191. // $FPID=$request->input("bfp","");
  192. // $user=$request->user();
  193. //
  194. // GlobalUserInfo::where('FPID',$FPID)->orWhere('UserID',$user->UserID)->update(['PwaInstalled'=>1]);
  195. // }
  196. function generateUUID($userId, $location = '1', $region = null,$Channel=99)
  197. {
  198. if(!$region)$region=env('REGION_24680','sa-east');
  199. // 从随机字节创建基础 UUID
  200. $randomBytes = bin2hex(random_bytes(3)); // 6个字符
  201. $randomBytes=str_pad(dechex($Channel),4,'0',STR_PAD_LEFT).$randomBytes;//补上4个channel
  202. // 缩短区域和语言码以适应 UUID 格式
  203. $locCode = substr(md5($location), 0, 4); // 4个字符
  204. $regionCode = substr(md5($region), 0, 4); // 4个字符
  205. // 确保 UserID 以十六进制形式适应最后部分
  206. $userIdHex = substr("000000000" . $userId, -10, 10); // 变长,确保适应
  207. // 构造 UUID
  208. $uuid = sprintf('%s-%s-%s-%s', $randomBytes, $locCode, $regionCode, $userIdHex);
  209. return $uuid;
  210. }
  211. /// 'PayTotal',
  212. // 'PayTimes',
  213. // 'WithdrawTotal',
  214. // 'LessThan',
  215. // 'Condition',
  216. // 'Price',
  217. // 'Amount',
  218. // 'Gift',
  219. // 'TimeLimit',
  220. // 'Status',
  221. public function GetUserInfo(Request $request)
  222. {
  223. $user = $request->globalUser;
  224. $user = GlobalUserInfo::toWebData($user);
  225. self::CheckTimeBonus($user);
  226. // 计算VIP等级
  227. //$user['vip'] = VipService::calculateVipLevel($user['UserID'] ?? 0);
  228. return apiReturnSuc($user);
  229. }
  230. public static function CheckTimeBonus(&$user)
  231. {
  232. return;
  233. if(!$user)return;
  234. $outdatas=null;
  235. if($user['Channel']==99)return ;
  236. try {
  237. $key='repay_temp_'.$user['UserID'];
  238. if(Redis::exists($key)){
  239. $lastData=json_decode(Redis::get($key),true);
  240. if(!isset($lastData['settime'])){
  241. $lastData['settime']=time();
  242. Redis::set($key, json_encode($lastData));
  243. }
  244. $lastData['timeleft']=$lastData['TimeLimit']-(time()-$lastData['settime']);
  245. unset($lastData['PayTotal'],$lastData['PayTimes'],$lastData['WithdrawTotal'],$lastData['LessThan'],$lastData['id'],$lastData['Condition']);
  246. $user['bonus_pack'] = $lastData;
  247. }else {
  248. //处理新逻辑
  249. $datas = RePayConfig::CacheDatas();
  250. if($user['UserID']=='50000005'){
  251. $user['Score']=10;
  252. }
  253. if (isset($datas) && is_array($datas) && count($datas)) {
  254. $datas = array_filter($datas, function ($v) use ($user) {
  255. return $user['Score'] < $v['LessThan'];
  256. });
  257. }
  258. if (isset($datas) && is_array($datas) && count($datas)) {
  259. // $userstat = DB::connection('write')->table('QPRecordDB.dbo.RecordUserTotalStatistics')
  260. // ->where('UserID', $user['UserID'])->first();
  261. $dbh = DB::connection()->getPdo();
  262. $stmt = $dbh->prepare( "EXEC [QPTreasureDB].[dbo].[GSP_GR_QueryUserRechargeInfo] @dwUserID = ".$user['UserID']);
  263. $stmt->execute();
  264. $userstat = $stmt->fetch(\PDO::FETCH_ASSOC);
  265. if($user['UserID']=='50000005'){
  266. $userstat['Recharge']=60000;
  267. $userstat['Withdraw']=0;
  268. }
  269. if ($userstat) {
  270. $datas = array_filter($datas, function ($v) use ($userstat) {
  271. return $userstat['Withdraw'] <= $v['WithdrawTotal'] * NumConfig::NUM_VALUE
  272. && $userstat['Recharge'] >= $v['PayTotal']* NumConfig::NUM_VALUE
  273. && $userstat['RechargeTimes'] <= $v['PayTimes'];
  274. });
  275. } else {
  276. $datas = [];
  277. }
  278. $outdatas = $datas;
  279. if (isset($datas) && is_array($datas) && count($datas)) {
  280. $datas = array_values($datas);
  281. $lastData = $datas[0];
  282. foreach ($datas as $k => $v) {
  283. if ($v['PayTotal'] > $lastData['PayTotal']) {
  284. $lastData = $v;
  285. }
  286. }
  287. if (!empty($lastData)) {
  288. $lastData['gear'] = DB::table('agent.dbo.recharge_gear')
  289. ->where('money', $lastData['Amount'])
  290. ->whereBetween('gift_id', [300, 400])
  291. ->where('status', 2)
  292. ->select('gift_id', 'money', 'give', 'favorable_price', 'second_give')
  293. ->first();
  294. if(empty($lastData['gear'])){
  295. $lastData['gear']=[
  296. 'money' => $lastData['Amount'],
  297. 'gear' => '[{"id":"2","status":1},{"id":"4","status":-1},{"id":"6","status":1},{"id":"11","status":1},{"id":"15","status":1},{"id":"19","status":1}]',
  298. 'status' => 2,
  299. 'created_at' => date('Y-m-d H:i:s.v'),
  300. 'favorable_price' => $lastData['Amount'],
  301. 'image' => '11',
  302. 'give' => $lastData['Gift'],
  303. 'first_pay' => 0,
  304. 'name' => '二次付费',
  305. 'gift_id' => DB::table('agent.dbo.recharge_gear')->where('gift_id','<',400)->max('gift_id')+1,
  306. 'channels' => '',
  307. 'second_give' => 0
  308. ];
  309. DB::table('agent.dbo.recharge_gear')->insert($lastData['gear']);
  310. $lastData['gear']=(object)$lastData['gear'];
  311. }
  312. $lastData['gear']->id = 28;
  313. $lastData['settime']=time();
  314. $lastData['timeleft']=$lastData['TimeLimit'];
  315. $lastData['gear'] = (array)$lastData['gear'];
  316. }
  317. unset($lastData['PayTotal'],$lastData['PayTimes'],$lastData['WithdrawTotal'],$lastData['LessThan'],$lastData['id'],$lastData['Condition']);
  318. Redis::setex($key, $lastData['TimeLimit'], json_encode($lastData));
  319. $user['bonus_pack'] = $lastData;
  320. }
  321. }
  322. }
  323. }catch (\Exception $e) {
  324. TelegramBot::getDefault()->sendMsgWithEnv($e->getMessage().json_encode($outdatas).$e->getTraceAsString());
  325. }
  326. }
  327. public function modiEmail(Request $request)
  328. {
  329. $user = $request->globalUser;
  330. // 自定义错误消息
  331. $messages = [
  332. 'Email.email' => 'O formato do email fornecido está incorreto. ',
  333. 'Email.unique' => 'Este endereço de e-mail foi registrado. ',
  334. ];
  335. // 验证规则
  336. $validator = Validator::make($request->all(), [
  337. 'Email' => 'required|email|unique:mysql.webgame.GlobalUserInfo,Email,' . $user->GlobalUID . ',GlobalUID',
  338. ], $messages);
  339. if ($validator->fails()) {
  340. // 返回具体的错误消息
  341. return apiReturnFail(['web.user.email_fail', $validator->errors()], '', 422);
  342. }
  343. $user->update($validator->validate());
  344. return response()->json(apiReturnSuc(GlobalUserInfo::toWebData($user), ['user.info.modi_success', 'Informação modificada']));
  345. }
  346. public function modiPhone(Request $request)
  347. {
  348. $user = $request->globalUser;
  349. // 自定义错误消息
  350. $messages = [
  351. 'Phone.string' => 'O número de telefone deve estar no formato string. ',
  352. 'Phone.max' => 'O número de telefone não pode exceder 20 caracteres. ',
  353. 'Phone.unique' => 'Este número de telefone já existe. ',
  354. ];
  355. // 验证规则
  356. $validator = Validator::make($request->all(), [
  357. 'Phone' => 'required|string|max:20|unique:mysql.webgame.GlobalUserInfo,Phone,' . $user->GlobalUID . ',GlobalUID',
  358. ], $messages);
  359. if ($validator->fails()) {
  360. // 返回具体的错误消息
  361. return apiReturnFail(['web.user.phone_fail', $validator->errors()], '', 422);
  362. }
  363. $user->update($validator->validate());
  364. return response()->json(apiReturnSuc(GlobalUserInfo::toWebData($user), ['user.info.modi_success', 'Informação modificada']));
  365. }
  366. public function modiUserInfo(Request $request)
  367. {
  368. $user = $request->globalUser;
  369. $validatedData = Validator::make($request->all(), [
  370. 'NickName' => 'nullable|string|max:32',
  371. 'FaceID' => 'nullable|integer|min:1',
  372. 'Gender' => 'nullable|integer|in:0,1,2',
  373. 'DefaultLanguage' => 'nullable|string|max:10',
  374. 'ThemeColor' => 'nullable|in:dark,light'
  375. ], [
  376. 'NickName.string' => 'O apelido deve ser uma string válida. ',
  377. 'NickName.max' => 'O apelido não pode exceder 32 caracteres. ',
  378. 'FaceID.integer' => 'O ID facial deve ser um número inteiro. ',
  379. 'FaceID.min' => 'O ID facial deve ser maior que 0. ',
  380. 'Gender.integer' => 'A seleção de gênero é inválida. ',
  381. 'Gender.in' => 'O gênero deve ser 0 (feminino), 1 (masculino) ou 2 (desconhecido). ',
  382. 'DefaultLanguage.string' => 'O idioma padrão deve ser uma string válida. ',
  383. 'DefaultLanguage.max' => 'O identificador de idioma padrão não pode exceder 10 caracteres. ',
  384. 'ThemeColor.in' => 'A cor do tema deve ser "escuro" ou "claro". '
  385. ]);
  386. if ($validatedData->fails()) {
  387. foreach ($validatedData->errors() as $key => $value) {
  388. return apiReturnFail(['web.modiUserInfo.fail_' . $key, $value[0]], '', 422);
  389. }
  390. }
  391. $validatedData = $validatedData->validate();
  392. foreach ($validatedData as $key => $value) {
  393. if (empty($validatedData[$key]) && $validatedData[$key] !== 0) unset($validatedData[$key]);
  394. }
  395. if (isset($validatedData['FaceID'])) $validatedData['FaceID'] = ($validatedData['FaceID'] - 1) % 16 + 1;
  396. if (isset($validatedData['NickName'])) $validatedData['NickName'] = Util::filterNickName($validatedData['NickName']);
  397. $user->update($validatedData);
  398. return response()->json(apiReturnSuc(GlobalUserInfo::toWebData($user,true), ['user.info.modi_success', 'Informação modificada']));
  399. }
  400. private function checkPhoneCode(Request $request)
  401. {
  402. $user=GlobalUserInfo::$me;
  403. $RegisterLocation = $request->country ?? env('COUNTRY_CODE','55');
  404. $userPhone="";
  405. if($user&&isset($user->Phone)&&substr($user->Phone,0,2)==$RegisterLocation){
  406. $userPhone = explode($RegisterLocation, $user->Phone)[1];
  407. }
  408. $Phone = $request->phone??$userPhone;
  409. // if($Phone!=$userPhone){
  410. // return apiReturnFail(['web.withdraw.try_again_later', 'Tente novamente mais tarde']);
  411. // }
  412. $PhoneCode = $request->code;
  413. if (empty($Phone)) {
  414. return apiReturnFail(['web.verify.num_empty', 'PhoneNum Empty']);
  415. }
  416. if (mb_strlen($PhoneCode) > 6) {
  417. return apiReturnFail(['web.verify.code_too_long', 'Phone code is too long']);
  418. }
  419. $Phone = $RegisterLocation.trim($Phone);
  420. Log::info('验证电话开始' . $Phone);
  421. $redisKey = 'checkPhoneCode_' . $Phone;
  422. if (!SetNXLock::getExclusiveLock($redisKey)) {
  423. return apiReturnFail(['web.withdraw.try_again_later', 'Tente novamente mais tarde']);
  424. }
  425. if (!is_numeric($PhoneCode)) {
  426. SetNXLock::release($redisKey);
  427. Log::info('web.verify.code_incorrect_or_expired checkPhoneCode nonum',[$Phone,$PhoneCode]);
  428. return apiReturnFail(['web.verify.code_incorrect_or_expired', 'O código está incorreto ou o tempo passou']);
  429. }
  430. $verifyCode = GamePhoneVerityCode::verifyCode($Phone, $PhoneCode);
  431. SetNXLock::release($redisKey);
  432. if ($verifyCode != trim($PhoneCode)) {
  433. Log::info('web.verify.code_incorrect_or_expired checkPhoneCode noveri',[$Phone,$PhoneCode]);
  434. return apiReturnFail(['web.verify.code_incorrect_or_expired', 'O código está incorreto ou o tempo passou']);
  435. }
  436. return 1;
  437. }
  438. public function forgetPassword(Request $request)
  439. {
  440. $check=$this->checkPhoneCode($request);
  441. if($check!==1){
  442. return $check;
  443. }
  444. $RegisterLocation = $request->country ?? env('COUNTRY_CODE','55');
  445. $user = GlobalUserInfo::getGameUserInfo("Phone", $RegisterLocation . $request->phone);
  446. if(!$user||empty($user)){
  447. return $this->registerUser($request);
  448. return apiReturnFail(['web.login.notfound', 'Erro de entrada, tente novamente!'], '', 2);
  449. }
  450. $request->globalUser=$user;
  451. return $this->modiPassword($request,false);
  452. }
  453. public function forgetInsurePassword(Request $request)
  454. {
  455. $check=$this->checkPhoneCode($request);
  456. if($check!==1){
  457. return $check;
  458. }
  459. return $this->modiInsurePassword($request,false);
  460. }
  461. public function modiPassword(Request $request,$checkOldpass=true)
  462. {
  463. $user = $request->globalUser;
  464. if($checkOldpass) {
  465. $oldpassword = $request->input('oldpassword');
  466. if (!Hash::check($oldpassword, $user->LogonPass)) {
  467. return apiReturnFail(['web.user.password_fail', 'A senha original está errada, digite-a novamente.'], '', 2);
  468. }
  469. }
  470. $newpassword = $request->input('newpassword');
  471. $renewpassword = $request->input('renewpassword');
  472. if (empty($newpassword) || empty($renewpassword)) {
  473. return apiReturnFail(['web.user.password_fail', 'A senha original está errada, digite-a novamente.'], '', 3);
  474. }
  475. if ($newpassword == $renewpassword) {
  476. $user->LogonPass = Hash::make($newpassword);
  477. $user->update(['LogonPass' => $user->LogonPass]);
  478. return response()->json(apiReturnSuc(GlobalUserInfo::toWebData($user), ['user.password.modi_success', 'Redefinição de senha concluída!']));//->withCookie($this->setLoginCookie($user['sign']));
  479. } else {
  480. return apiReturnFail(['web.reg.password_notsame', 'As senhas digitadas duas vezes são inconsistentes, digite novamente!'], '', 2);
  481. }
  482. }
  483. public function modiInsurePassword(Request $request,$checkOldpass=true)
  484. {
  485. $user = $request->globalUser;
  486. if($checkOldpass) {
  487. $oldpassword = $request->input('oldpassword');
  488. if (!empty($user->InsurePass) && !Hash::check($oldpassword, $user->InsurePass)) {
  489. return apiReturnFail(['web.user.paypass_fail', 'A senha original está errada, digite-a novamente.'], '', 2);
  490. }
  491. }
  492. $newpassword = $request->input('newpassword');
  493. $renewpassword = $request->input('renewpassword');
  494. if (empty($newpassword) || empty($renewpassword)) {
  495. return apiReturnFail(['web.user.password_fail', 'A senha original está errada, digite-a novamente.'], '', 3);
  496. }
  497. if ($newpassword == $renewpassword) {
  498. $user->InsurePass = Hash::make($newpassword);
  499. $user->update(['InsurePass' => $user->InsurePass]);
  500. return response()->json(apiReturnSuc(GlobalUserInfo::toWebData($user), ['user.password.modi_success', 'Redefinição de senha concluída!']));//->withCookie($this->setLoginCookie($user['sign']));
  501. } else {
  502. return apiReturnFail(['web.reg.paypass_notsame', 'As senhas digitadas duas vezes são inconsistentes, digite novamente!'], '', 2);
  503. }
  504. }
  505. public function Logout(Request $request)
  506. {
  507. return response()->json(apiReturnSuc('', ['logout.success', 'Você saiu com sucesso.']))->withCookie(self::clearLoginCookie());
  508. }
  509. public static function getPwaBonus(Request $request)
  510. {
  511. $user=$request->user();
  512. $haveBonus=Redis::get('pwa_bonus:'.$user->UserID);
  513. $config = RouteService::getChannelConfig($request);
  514. if($haveBonus&&$config->BONUS_PWA()>0){
  515. [$OrgScore,$NowScore]=OuroGameService::AddFreeScore($user->UserID,$config->BONUS_PWA(),OuroGameService::REASON_PwaBonus,false);
  516. $data=GlobalUserInfo::toWebData($user);
  517. $data['Score']=$NowScore;
  518. Redis::del('pwa_bonus:'.$user->UserID);
  519. if(date('Ymd',strtotime($user->RegisterDate)) == date('Ymd')){
  520. $RecordPlatformDataModel = new \App\Models\RecordPlatformData();
  521. $RecordPlatformDataModel->PwaToday($user->Channel);
  522. }
  523. return response()->json(apiReturnSuc($data, ['user.bonus.pwa_bonus_success', 'Bônus PWA recebido com sucesso!']));
  524. }else{
  525. return response()->json(apiReturnFail(['user.bonus.pwa_bonus_fail', 'Você já recebeu o bônus PWA.',$haveBonus,$config->BONUS_PWA()]));
  526. }
  527. }
  528. private function isSequentialOrRepetitive($phoneNumber)
  529. {
  530. // 移除国家代码和非数字字符
  531. $digits = $phoneNumber;//substr($phoneNumber, 2);
  532. // 检查连号
  533. if (preg_match('/(\d)\1{5,}/', $digits)) { // 改为检测6个或更多连续相同的数字
  534. return true;
  535. }
  536. // 检查顺子,增加检测递增和递减顺子
  537. $ascending = true;
  538. $descending = true;
  539. for ($i = 0; $i < strlen($digits) - 1; $i++) {
  540. if (ord($digits[$i + 1]) - ord($digits[$i]) != 1) {
  541. $ascending = false;
  542. }
  543. if (ord($digits[$i]) - ord($digits[$i + 1]) != 1) {
  544. $descending = false;
  545. }
  546. }
  547. if ($ascending || $descending) {
  548. return true;
  549. }
  550. return false;
  551. }
  552. /**
  553. * @param Request $request
  554. * @return GlobalUserInfo|false
  555. */
  556. public static function checkLogin(Request $request)
  557. {
  558. // $sign=$request->cookie('guuid')??$request->sign;
  559. $sign = $request->sign;
  560. if ($sign) {
  561. try {
  562. $arr = explode('|', Crypt::decryptString($sign));
  563. $globalUID = $arr[0];
  564. $timestamp = intval($arr[1]);
  565. if (time() > $timestamp) return false;
  566. $user = GlobalUserInfo::getGameUserInfo('GlobalUID', $globalUID);
  567. if ($user) {
  568. if ($arr[2] == substr(md5($user->LogonPass), 0, 6)) {
  569. $FPID = $request->input("bfp", "");
  570. if (!empty($FPID)) {
  571. if (empty($user->FPID)) $user->update(['FPID' => $FPID]);
  572. if ($user->LastFPID != $FPID) $user->update(['LastFPID' => $FPID]);
  573. }
  574. if (empty($user->ShortHashID)) {
  575. $ShortHashID = explode('-', $globalUID)[0];
  576. $user->update(['ShortHashID' => $ShortHashID]);
  577. }
  578. GlobalUserInfo::$me = $user;
  579. if (intval($request->input('pwa', 0)) == 1) {
  580. if (intval($user->PwaInstalled) == 0) {
  581. $user->update(['PwaInstalled' => 1]);
  582. $config = RouteService::getChannelConfig($request);
  583. if($config->BONUS_PWA()>0){
  584. Redis::setex('pwa_bonus:'.$user->UserID,86400,1);
  585. }
  586. }
  587. }
  588. return $user;
  589. }
  590. }
  591. } catch (\Exception $e) {
  592. }
  593. }
  594. return false;
  595. }
  596. private function guestLogin($user,$isRegister=false)
  597. {
  598. $qp=QuickAccountPass::query()->where('UserID',$user->UserID)->first();
  599. if(!$qp){
  600. $qp=$this->getGustAccount($user->UserID);
  601. $user->Accounts=$qp['account'];
  602. $user->LogonPass=Hash::make($qp['password']);
  603. $user->save();
  604. }
  605. $user = GlobalUserInfo::toWebData($user,true);
  606. if($isRegister)$user['reg'] = 1;
  607. if($qp){
  608. if(!is_array($qp))$qp=$qp->toArray();
  609. $user['account']=$qp['account'];
  610. $user['password']=$qp['password'];
  611. }
  612. return response()->json(apiReturnSuc($user, ['login.success', 'Login bem-sucedido, bem-vindo de volta!']));
  613. }
  614. public function login(Request $request)
  615. {
  616. $type=$request->input('type','id');
  617. $FPID = $request->input("bfp", "");
  618. $user=null;
  619. $config = RouteService::getChannelConfig($request);
  620. if($type=='guest'){
  621. //游客模式打开,随时可以登录
  622. //$user=GlobalUserInfo::where('FPID',$FPID)->where('Phone','')->where('Email','')->first();
  623. $user=GlobalUserInfo::where('FPID',$FPID)->where('RegionID',$config->isRegionUnique())->first();
  624. if(!$user){
  625. return $this->registerUser($request);
  626. }else{
  627. return $this->guestLogin($user);
  628. }
  629. }
  630. if (!isset($request->account)) {
  631. return apiReturnFail(["web.login.account_empty", 'Por favor insira o nome de usuário!']);
  632. }
  633. if (!isset($request->password)) {
  634. return apiReturnFail(['web.login.password_empty', 'Por favor insira a senha!'], '', 302);
  635. }
  636. $RegisterLocation = $request->country ?? env('COUNTRY_CODE','55');
  637. if (strstr($request->account, '@')) {
  638. $user = GlobalUserInfo::query()->where('RegionID', $config->isRegionUnique())->where("Email", $request->account)->first();
  639. } else if (is_numeric($request->account)) {
  640. $user = GlobalUserInfo::query()->where('RegionID', $config->isRegionUnique())->where("Phone", $RegisterLocation . $request->account)->first();
  641. } else {
  642. $user = GlobalUserInfo::query()->where('RegionID', $config->isRegionUnique())->where("Accounts", $request->account)->first();
  643. }
  644. if ($user) {
  645. if (Hash::check($request->password, $user->LogonPass)) {
  646. $user = GlobalUserInfo::toWebData($user,true);
  647. return response()->json(apiReturnSuc($user, ['login.success', 'Login bem-sucedido, bem-vindo de volta!']));//->withCookie($this->setLoginCookie($user['sign']));
  648. } else {
  649. return apiReturnFail(['web.login.notfound', 'Erro de entrada, tente novamente!'], '', 2);
  650. }
  651. } else {
  652. return apiReturnFail(['web.login.notfound', 'Sua conta não foi encontrada, registre-se ou tente novamente!']);
  653. }
  654. }
  655. private function checkPhone($Phone, $RegisterLocation = '1',Request $request=null)
  656. {
  657. $OrgPhone=$Phone;
  658. // dd($RegisterLocation,$Phone,str_starts_with($Phone,$RegisterLocation),$Phone=explode($RegisterLocation,$Phone));
  659. if(!empty($RegisterLocation)&&str_starts_with($Phone,$RegisterLocation)){
  660. $Phone=$OrgPhone;
  661. }
  662. if (!empty($Phone)) {
  663. // 验证规则
  664. // Remove spaces and dashes from the input
  665. $Phone = str_replace(['-', ' '], '', $Phone);
  666. // Check if the number has 11 digits and the third character is 9
  667. if ($RegisterLocation == env('COUNTRY_CODE','1')) {
  668. // if (!preg_match('/^\d{2}9\d{8}$/', $Phone)) {
  669. // return apiReturnFail(['web.user.phone_fail', 'Not correct phone number'], '', 422);
  670. // }
  671. }
  672. if ($this->isSequentialOrRepetitive($Phone)) {
  673. return apiReturnFail(['web.user.phone_fail', 'Not correct phone number'], '', 422);
  674. }
  675. // if(!str_starts_with($Phone,$RegisterLocation)) {
  676. // $Phone = $RegisterLocation . $Phone;
  677. // }
  678. }
  679. if (!empty($Phone)) {
  680. $config = RouteService::getChannelConfig($request);
  681. $isExist = GlobalUserInfo::query()
  682. ->where('RegionID', $config->isRegionUnique())
  683. ->where(function ($query) use ($Phone, $OrgPhone) {
  684. $query->where("Phone", $Phone)->orWhere('Accounts', $OrgPhone);
  685. })
  686. ->first();
  687. //账户查重
  688. if ($isExist) {
  689. if ($request&&Hash::check($request->password, $isExist->LogonPass)) {
  690. return $isExist;
  691. }
  692. return apiReturnFail(['web.reg.fail_phone_exist', 'O número de telefone já existe, altere-o e tente se cadastrar novamente!']);
  693. }
  694. }
  695. return $Phone;
  696. }
  697. public function createGuestAccounts()
  698. {
  699. $accs=[];
  700. for($i=0;$i<100;$i++) {
  701. $acc = $this->makeGuestAccount();
  702. while(QuickAccountPassStore::where("account", $acc['account'])->exists()) {
  703. $acc = $this->makeGuestAccount();
  704. }
  705. QuickAccountPassStore::create($acc);
  706. $accs[]=$acc;
  707. }
  708. return ['accs'=>$accs];
  709. }
  710. public function getGustAccount($UserID)
  711. {
  712. $acc=QuickAccountPass::whereNull('UserID')->first();
  713. if(!$acc){
  714. $res=$this->createGuestAccounts();
  715. $accs=$res['accs'];
  716. if($accs){
  717. QuickAccountPass::insert($accs);
  718. }
  719. $acc=QuickAccountPass::query()->whereNull('UserID')->first();
  720. }
  721. if($acc){
  722. $acc->update(['UserID' => $UserID]);
  723. }
  724. return $acc->toArray();
  725. }
  726. public function makeGuestAccount()
  727. {
  728. // 词库
  729. $words = ["sun", "moon", "star", "sky", "wind", "fire", "water", "earth","apple","banana","cherry","date","elderberry","fig","grape","honeydew","kiwi","lemon","mango","nectarine","orange","peach","pear","plum","quince","raspberry","strawberry","tangerine","ugli","vanilla","watermelon","xylophone","yam","zucchini","airplane","balloon","camera","drum","eagle","flag","guitar","hat","iceberg","jacket","kite","lamp","mountain","notebook","octopus","penguin","quilt","robot","sunflower","train","umbrella","vase","whale","yacht","zebra","actor","bicycle","carrot","dolphin","elephant","fountain","grape","honey","internet","jungle","koala","lemonade","moose","ninja","octopus","puzzle","quasar","rocket","sunset","trampoline","unicorn","violin","whale","xylophone","yellow","zebra","adventure","bubble","cactus","daisy","envelope","feather","gorilla","horizon","jellyfish","kitchen","lighthouse","mushroom","notebook","orchestra","penguin","quilt","river","snowflake","telescope","universe","vortex","whisper","xenon","yoga","zebra","airport","beach","cucumber","dolphin","eggplant","fishing","grapevine","hiking","jelly","keyboard","lunar","monkey","northern","ocean","pebble","question","robot","scarf","thunder","underwear","vivid","windmill","xylophone","yogurt","zoo","amethyst","butterfly","cloud","dream","emerald","frost","garden","harmony","island","jigsaw","kaleidoscope","lily","melody","nectar","obsidian","parrot","quilt","rainbow","storm","twilight","vortex","whistle","xenon","yarn","zeppelin","antelope","bridge","cobweb","diamond","energy","feather","giraffe","horizon","icicle","jungle","kettle","lemonade","morning","nightfall","octagon","peacock","quasar","riddle","snowman","tulip","unicorn","violet","wonder","xenon","yellow","zodiac","albatross","bamboo","carpet","dandelion","echo","flamingo","galaxy","honeycomb","illusion","jellybean","knight","lighthouse","moonlight","ninja","orchestra","penguin","quill","robot","sunrise","tiger","umbrella","vampire","wisteria","xylophone","yawn","zebra","acrobat","beetle","coral","dusk","elm","frost","grace","horizon","igloo","jacket","kite","lamb","meadow","nail","owl","prism","quince","raven","sand","telescope","universe","vacuum","waterfall","xylophone","yacht","zenith","alphabet","breeze","crystal","dawn","eagle","festival","glow","horizon","ivory","jewel","knob","lemon","magnet","noon","oak","path","quest","rose","skyline","trail","umbrella","vortex","wave","xylophone","yellow","zephyr","abstract","beetle","cherry","dolphin","enigma","flame","giraffe","horizon","ink","jewel","kaleidoscope","lily","matrix","neptune","oasis","puzzle","quartz","rain","snowflake","tulip","ufo","vortex","whale","xylophone","yarn","zeppelin","apple","amazon","google","microsoft","facebook","twitter","netflix","sony","samsung","intel","nike","adidas","coca-cola","pepsi","oracle","ibm","hp","dell","nvidia","twitter","afghanistan","brazil","canada","denmark","egypt","france","germany","hungary","india","japan","kenya","luxembourg","morocco","nigeria","oman","portugal","qatar","russia","spain","turkey","ukraine","vietnam","albert","isaac","marie","charles","nelson","martin","george","abraham","leo","vincent","john","michael","james","robert","david","mary","jennifer","linda","patricia","susan"];
  730. $numbers = range(0, 999);
  731. // 生成账号和密码
  732. $word1 = $words[array_rand($words)];
  733. // $word2 = $words[array_rand($words)];
  734. $number = str_pad($numbers[array_rand($numbers)], 2, '0', STR_PAD_LEFT);
  735. $account= $word1 . $number ;
  736. $word = $words[array_rand($words)];
  737. $number = str_pad($numbers[array_rand($numbers)], 2, '0', STR_PAD_LEFT);
  738. $password= $word . $number;
  739. return compact('account', 'password');
  740. }
  741. public function getUserByFPID($FPID)
  742. {
  743. $user=GlobalUserInfo::getGameUserInfo('FPID', $FPID);
  744. return $user;
  745. }
  746. private $maxFpsidLimit=2;
  747. public function registerUser(Request $request, $regByGuest = false)
  748. {
  749. //type=id,phone,sms,mail,guest
  750. $type=$request->input('type',"id");
  751. if (!$regByGuest&&$type!='guest') {
  752. if (!isset($request->email) && !isset($request->phone)&&!isset($request->account)) {
  753. return apiReturnFail(["web.reg.account_empty", 'Por favor insira o nome de usuário!']);
  754. }
  755. if (!isset($request->password) || !isset($request->repassword) || $request->password != $request->repassword) {
  756. return apiReturnFail(['web.reg.password_notsame', 'As senhas digitadas duas vezes são inconsistentes, digite novamente!'], '', 2);
  757. }
  758. }
  759. $FPID = $request->input("bfp", "");
  760. if($type=='sms'){
  761. $verifyRes=$this->LoginByCode($request,true);
  762. //报错
  763. if(is_array($verifyRes))return $verifyRes;
  764. }else{
  765. //把数据卡限制住
  766. // if (GlobalUserInfo::where('FPID',$FPID)->count() > $this->maxFpsidLimit) {
  767. // $allAcc=GlobalUserInfo::where('FPID',$FPID)->get()->toArray();
  768. // $reqs=$request->all();
  769. // Util::WriteLog('maxreg',compact('allAcc','reqs'));
  770. // return apiReturnFail(['web.reg.fail_ipmax', 'Too many register requests!']);
  771. // }
  772. }
  773. if (empty($FPID)) {
  774. return apiReturnFail(['web.reg.fail_phone_exist', 'O número de telefone já existe, altere-o e tente se cadastrar novamente!']);
  775. }
  776. //获取默认配置
  777. $config = RouteService::getChannelConfig($request);
  778. //游客注册检查是否已经注册
  779. if($type=='guest'){
  780. $where = [];
  781. $where[] = ['FPID', $FPID];
  782. $where[] = ['Phone', ''];
  783. $where[] = ['Email', ''];
  784. $where[] = ['RegionID', $config->isRegionUnique()];
  785. $guestUser=GlobalUserInfo::where($where)->first();
  786. if($guestUser){
  787. //存在,直接返回去
  788. return $this->guestLogin($guestUser);
  789. }
  790. }
  791. $login_ip = IpLocation::getRealIp();
  792. $RegisterLocation = $request->country ?? env('COUNTRY_CODE',55);
  793. $ServerRegion = env('REGION_24680','sa-east');
  794. $Language = $request->lang ?? $request->getLocale();
  795. $Phone = $request->phone ?? "";
  796. $Phone = $this->checkPhone($Phone, $RegisterLocation,$request);
  797. //有错误返回
  798. if (is_array($Phone)) {
  799. return $Phone;
  800. }else if(is_object($Phone)&&isset($Phone->GlobalUID)){
  801. //原来就存在,直接返回
  802. $guser = GlobalUserInfo::toWebData($Phone,true);
  803. $guser['reg'] = 1;
  804. return response()->json(apiReturnSuc($guser, ['reg.success', 'Registro realizado com sucesso!']));
  805. }
  806. if (isset($request->email) && strstr($request->email, '@')) {
  807. $isExist = GlobalUserInfo::query()->where("Email", $request->email)->exists();
  808. //账户查重
  809. if ($isExist) {
  810. return apiReturnFail(['web.reg.fail_email_exist', 'O e-mail já existe, altere-o e tente se cadastrar novamente!']);
  811. }
  812. }
  813. $redisKey = 'register_' . $FPID;
  814. if (!SetNXLock::getExclusiveLock($redisKey)) {
  815. return apiReturnFail(['web.withdraw.try_again_later', 'Tente novamente mais tarde']);
  816. }
  817. $Channel = 0;
  818. //保持邀请和被邀请的渠道序列统一
  819. $ActCode = $request->input('act');
  820. if(strstr($ActCode,'http')){
  821. $ActCode=explode('http',$ActCode)[0];
  822. }
  823. $ReferrType = 0;
  824. if ($ActCode) {
  825. //使用邀请的Code来保持邀请被邀请的用户注册渠道一致性
  826. $link = AgentLinks::getByCode($ActCode);
  827. if ($link) {
  828. $inviter = AccountsInfo::where('UserID', $link->UserID)->first();
  829. if($inviter&&is_object($inviter)) {
  830. $Channel = $inviter->Channel;
  831. $ReferrType = 2;
  832. }
  833. }
  834. }
  835. if(!$Channel){
  836. //非游客注册
  837. while($config->isGuestOpen()&&!$regByGuest){
  838. RouteService::clearChannelConfig();
  839. $config = RouteService::getChannelConfig($request);
  840. }
  841. $Channel = $config->Channel;
  842. if($Channel!=env('REGION_24680_DEFAULT_CHANNEL',100))$ReferrType = 1;
  843. }else{
  844. //先搜索本地配置
  845. $config = WebChannelConfig::getByChannel($Channel);
  846. }
  847. $Package = $config->PackageName;
  848. if ($config) {
  849. //每小时对齐两个表的包名
  850. if(!Redis::exists('ChannelPackageName'.$Channel)) {
  851. $pack = DB::table('QPPlatformDB.dbo.ChannelPackageName')->where('Channel', $Channel)->select('PackageName')->first();
  852. if ($pack) {
  853. Redis::setex('ChannelPackageName' . $Channel, 3600, $Package);
  854. if ($Package != $pack->PackageName) {
  855. DB::table('QPPlatformDB.dbo.ChannelPackageName')->where('Channel', $Channel)->update(['PackageName' => $Package]);
  856. }
  857. }
  858. }
  859. }
  860. $account= $request->account??$request->email ?? $request->phone ?? $FPID;
  861. //注册到游戏服务器
  862. $user = $this->registerAccountInfo($request, $Package, $Channel,$account);
  863. //返回错误
  864. if (is_array($user) && !isset($user['UserID'])) {
  865. SetNXLock::release($redisKey);
  866. return $user;
  867. }
  868. if (!$user) {
  869. SetNXLock::release($redisKey);
  870. return apiReturnFail(['web.withdraw.try_again_later', 'Pausa de login']);
  871. }
  872. //代理注册,保留号段10000-100000
  873. if($request->input('isagent',0)=='24680'){
  874. $oldid=$user['UserID'];
  875. $newid=AccountsInfo::whereBetween('UserID',[10000,100000])->max('UserID')??10000;
  876. $newid++;
  877. $acc=AccountsInfo::find($oldid);
  878. $newacc=$acc->toArray();
  879. $acc->delete();
  880. $newacc['UserID']=$newid;
  881. $pdo = DB::connection('write')->getPdo();
  882. $pdo->setAttribute(PDO::SQLSRV_ATTR_DIRECT_QUERY, true);
  883. DB::connection('write')->unprepared("set identity_insert QPAccountsDB.dbo.AccountsInfo on;");
  884. DB::connection('write')->table('QPAccountsDB.dbo.AccountsInfo')->insert($newacc);
  885. DB::connection('write')->unprepared("set identity_insert QPAccountsDB.dbo.AccountsInfo off;");
  886. $pdo->setAttribute(PDO::SQLSRV_ATTR_DIRECT_QUERY, false);
  887. $old=['UserID'=>$oldid];$new=['UserID'=>$newid];
  888. DB::connection('write')->table('QPAccountsDB.dbo.UserAgent')->where($old)->update($new);
  889. DB::connection('write')->table('QPTreasureDB.dbo.GameScoreInfo')->where($old)->update($new);
  890. $user['UserID']=$newid;
  891. }
  892. $UserID = $user['UserID'];
  893. $GameID = $user['GameID'];
  894. $password=$request->password;
  895. $globalUserInfo = GlobalUserInfo::getGameUserInfo('UserID', $UserID);
  896. if ($globalUserInfo) {
  897. $GlobalUID = $globalUserInfo->GlobalUID;
  898. } else {
  899. if($type=='guest'){
  900. //改成从中心区获取idpass
  901. $idps=$this->getGustAccount($UserID);
  902. $account=$idps['account'];
  903. $password=$idps['password'];
  904. }
  905. $GlobalUID = $this->generateUUID($UserID, $RegisterLocation, $ServerRegion,$Channel??99);
  906. $ShortHashID = explode('-', $GlobalUID)[0];
  907. //先搞定userid
  908. $globalUserInfo = new GlobalUserInfo([
  909. 'UserID' => $UserID,
  910. 'GameID' => $GameID,
  911. 'FF' => $request->input('ff', ''),
  912. 'FPID' => $FPID,
  913. 'LastFPID' => $FPID,
  914. 'ShortHashID' => $ShortHashID,
  915. 'GlobalUID' => $GlobalUID,
  916. 'Accounts' => $account, // Assuming email is received from request
  917. 'Email' => $request->email ?? '', // Assuming email is received from request
  918. 'Phone' => $Phone, // Assuming email is received from request
  919. 'LogonPass' => Hash::make($password),
  920. 'LogonIP' => $login_ip,
  921. 'Gender' => 1,
  922. 'RegisterIP' => $login_ip,
  923. 'RegisterLocation' => $RegisterLocation,
  924. 'ServerRegion' => $ServerRegion,
  925. 'DefaultLanguage' => $Language,
  926. 'Channel' => $Channel??99,
  927. 'RegionID' => $config->isRegionUnique(),
  928. 'ReferrType' => $ReferrType,
  929. 'RegisterDate' => date('Y-m-d H:i:s'),
  930. 'InsurePass' => '',
  931. 'UserRight' => 0,
  932. 'Level' => 0,
  933. 'Exp' => 0,
  934. 'FaceID' => $user['FaceID'],
  935. 'NickName' => $user['NickName'],
  936. 'Registed' =>1,
  937. // 'InsurePass' => Hash::make($request->insurePassword),
  938. // Add other fields as needed
  939. ]);
  940. try {
  941. $globalUserInfo->save();
  942. } catch (\Exception $exception) {
  943. Log::error($exception->getMessage());
  944. }
  945. }
  946. GlobalUserInfo::$me=$globalUserInfo;
  947. if($Channel==env('REGION_24680_DEFAULT_CHANNEL',100)){
  948. Util::WriteLog('c99',json_encode($_SERVER));
  949. }
  950. //注册钱数要归0
  951. // $newRegGolds=$config->isRegZeroMoneyOpen()?0:$config->BONUS_REG();
  952. // GameScoreInfo::query()->where('UserID', $UserID)->update(['Score'=>$newRegGolds]);
  953. $agentUser = AgentService::SetUserAgent($GlobalUID, $UserID, $ActCode);
  954. SetNXLock::release($redisKey);
  955. if ($regByGuest) {
  956. return GlobalUserInfo::getGameUserInfo("UserID", $UserID);
  957. }
  958. $guser = GlobalUserInfo::toWebData($globalUserInfo,true);
  959. // if($agentUser->Higher1ID){
  960. // //获取邀请者信息
  961. // $inviter=AccountsInfo::where('UserID',$agentUser->Higher1ID)->first();
  962. // }
  963. $guser['reg'] = 1;
  964. if($type=='guest'){
  965. $guser['account'] = $account;
  966. $guser['password'] = $password;
  967. }
  968. $defaultGameId = 931;
  969. $recommendGame = '/game/' . $defaultGameId;
  970. // 如果用户信息存在,根据GameID的最后一位数字查询映射关系
  971. if ($guser && isset($guser['GameID'])) {
  972. $gameId = (string)$guser['GameID'];
  973. $lastDigit = (int)substr($gameId, -1); // 获取最后一位数字
  974. // 查询映射关系(带缓存)
  975. $cacheKey = 'game_number_mapping:' . $lastDigit;
  976. $mapping = null;
  977. // 尝试从缓存获取
  978. $cached = Redis::get($cacheKey);
  979. if ($cached !== null) {
  980. $decoded = json_decode($cached, true);
  981. if (is_array($decoded) && !empty($decoded)) {
  982. $mapping = (object)$decoded;
  983. }
  984. }
  985. if(!$mapping){
  986. $mapping = DB::table('agent.dbo.game_number_mapping')
  987. ->where('number', $lastDigit)
  988. ->first();
  989. Redis::setex($cacheKey, $mapping ? 86400 : 300, json_encode($mapping ?: []));
  990. }
  991. if ($mapping && isset($mapping->game_id) && $mapping->game_id) {
  992. $defaultGameId = $mapping->game_id;
  993. $recommendGame = '/game/' . $mapping->game_id;
  994. }
  995. }
  996. $guser['recommendGame'] = $recommendGame;
  997. AccountsInfo::where('UserID', $UserID)->update(['UserMedal' => $defaultGameId ]);
  998. Util::WriteLog('register_params',[$request,$guser]);
  999. return response()->json(apiReturnSuc($guser, ['reg.success', 'Registro realizado com sucesso!']));//->withCookie($this->setLoginCookie($guser['sign']));
  1000. }
  1001. public function registerUserNew(Request $request, $regByGuest = true)
  1002. {
  1003. //type=id,phone,sms,mail,guest
  1004. $type=$request->input('type',"id");
  1005. $FPID = $request->input("bfp", "");
  1006. if (empty($FPID)) {
  1007. return apiReturnFail(['web.reg.fail_phone_exist', 'O número de telefone já existe, altere-o e tente se cadastrar novamente!']);
  1008. }
  1009. // $guestUser=GlobalUserInfo::where('FPID',$FPID)->first();
  1010. $config = RouteService::getChannelConfig($request);
  1011. $where = [];
  1012. $where[] = ['FPID', $FPID];
  1013. // $where[] = ['Phone', ''];
  1014. // $where[] = ['Email', ''];
  1015. $where[] = ['RegionID', $config->isRegionUnique()];
  1016. $guestUser=GlobalUserInfo::where($where)->first();
  1017. if($guestUser){
  1018. //存在,直接返回去
  1019. return $this->guestLogin($guestUser);
  1020. }
  1021. $login_ip = IpLocation::getRealIp();
  1022. $RegisterLocation = $request->country ?? env('COUNTRY_CODE',1);
  1023. $ServerRegion = env('REGION_24680','sa-east');
  1024. $Language = $request->lang ?? $request->getLocale();
  1025. $redisKey = 'register_' . $FPID;
  1026. if (!SetNXLock::getExclusiveLock($redisKey)) {
  1027. return apiReturnFail(['web.withdraw.try_again_later', 'Tente novamente mais tarde']);
  1028. }
  1029. $Channel = 0;
  1030. //保持邀请和被邀请的渠道序列统一
  1031. $ActCode = $request->input('act');
  1032. if(strstr($ActCode,'http')){
  1033. $ActCode=explode('http',$ActCode)[0];
  1034. }
  1035. $ReferrType = 0;
  1036. if ($ActCode) {
  1037. //使用邀请的Code来保持邀请被邀请的用户注册渠道一致性
  1038. $link = AgentLinks::getByCode($ActCode);
  1039. if ($link) {
  1040. $inviter = AccountsInfo::where('UserID', $link->UserID)->first();
  1041. if($inviter&&is_object($inviter)) {
  1042. $Channel = $inviter->Channel;
  1043. $ReferrType = 2;
  1044. }
  1045. }
  1046. }
  1047. if(!$Channel){
  1048. //获取默认配置
  1049. // $config = RouteService::getChannelConfig($request);
  1050. //非游客注册
  1051. // while($config->isGuestOpen()&&!$regByGuest){
  1052. // RouteService::clearChannelConfig();
  1053. // $config = RouteService::getChannelConfig($request);
  1054. // }
  1055. $Channel = $config->Channel;
  1056. if($Channel!=env('REGION_24680_DEFAULT_CHANNEL',100))$ReferrType = 1;
  1057. }else{
  1058. //先搜索本地配置
  1059. $config = WebChannelConfig::getByChannel($Channel);
  1060. }
  1061. $Package = $config->PackageName;
  1062. if ($config) {
  1063. //每小时对齐两个表的包名
  1064. if(!Redis::exists('ChannelPackageName'.$Channel)) {
  1065. $pack = DB::table('QPPlatformDB.dbo.ChannelPackageName')->where('Channel', $Channel)->select('PackageName')->first();
  1066. if ($pack) {
  1067. Redis::setex('ChannelPackageName' . $Channel, 3600, $Package);
  1068. if ($Package != $pack->PackageName) {
  1069. DB::table('QPPlatformDB.dbo.ChannelPackageName')->where('Channel', $Channel)->update(['PackageName' => $Package]);
  1070. }
  1071. }
  1072. }
  1073. }
  1074. $account= $request->account??$request->email ?? $request->phone ?? $FPID;
  1075. //注册到游戏服务器
  1076. $user = $this->registerAccountInfo($request, $Package, $Channel,$account);
  1077. //返回错误
  1078. if (is_array($user) && !isset($user['UserID'])) {
  1079. SetNXLock::release($redisKey);
  1080. return $user;
  1081. }
  1082. if (!$user) {
  1083. SetNXLock::release($redisKey);
  1084. return apiReturnFail(['web.withdraw.try_again_later', 'Pausa de login']);
  1085. }
  1086. //代理注册,保留号段10000-100000
  1087. $UserID = $user['UserID'];
  1088. $GameID = $user['GameID'];
  1089. $password=$request->password;
  1090. $globalUserInfo = GlobalUserInfo::getGameUserInfo('UserID', $UserID);
  1091. if ($globalUserInfo) {
  1092. $GlobalUID = $globalUserInfo->GlobalUID;
  1093. } else {
  1094. // if($type=='guest'){
  1095. // //改成从中心区获取idpass
  1096. // $idps=$this->getGustAccount($UserID);
  1097. // $account=$idps['account'];
  1098. // $password=$idps['password'];
  1099. // }
  1100. $GlobalUID = $this->generateUUID($UserID, $RegisterLocation, $ServerRegion,$Channel??99);
  1101. $ShortHashID = explode('-', $GlobalUID)[0];
  1102. //先搞定userid
  1103. $globalUserInfo = new GlobalUserInfo([
  1104. 'UserID' => $UserID,
  1105. 'GameID' => $GameID,
  1106. 'FF' => $request->input('ff', ''),
  1107. 'FPID' => $FPID,
  1108. 'LastFPID' => $FPID,
  1109. 'ShortHashID' => $ShortHashID,
  1110. 'GlobalUID' => $GlobalUID,
  1111. 'Accounts' => $account, // Assuming email is received from request
  1112. 'Email' => $request->email ?? '', // Assuming email is received from request
  1113. 'Phone' => '', // Assuming email is received from request
  1114. 'LogonPass' => Hash::make($password),
  1115. 'LogonIP' => $login_ip,
  1116. 'Gender' => 1,
  1117. 'RegisterIP' => $login_ip,
  1118. 'RegisterLocation' => $RegisterLocation,
  1119. 'ServerRegion' => $ServerRegion,
  1120. 'DefaultLanguage' => $Language,
  1121. 'Channel' => $Channel??100,
  1122. 'RegionID' => $config->isRegionUnique(),
  1123. 'ReferrType' => $ReferrType,
  1124. 'RegisterDate' => date('Y-m-d H:i:s'),
  1125. 'InsurePass' => '',
  1126. 'UserRight' => 0,
  1127. 'Level' => 0,
  1128. 'Exp' => 0,
  1129. 'FaceID' => $user['FaceID'],
  1130. 'NickName' => $user['NickName'],
  1131. 'Registed' =>1,
  1132. // 'InsurePass' => Hash::make($request->insurePassword),
  1133. // Add other fields as needed
  1134. ]);
  1135. try {
  1136. $globalUserInfo->save();
  1137. } catch (\Exception $exception) {
  1138. Log::error($exception->getMessage());
  1139. }
  1140. }
  1141. GlobalUserInfo::$me=$globalUserInfo;
  1142. if($Channel==env('REGION_24680_DEFAULT_CHANNEL',100)){
  1143. Util::WriteLog('c99',json_encode($_SERVER));
  1144. }
  1145. //注册钱数要归0
  1146. // $newRegGolds=$config->isRegZeroMoneyOpen()?0:$config->BONUS_REG();
  1147. // GameScoreInfo::query()->where('UserID', $UserID)->update(['Score'=>$newRegGolds]);
  1148. $agentUser = AgentService::SetUserAgent($GlobalUID, $UserID, $ActCode);
  1149. SetNXLock::release($redisKey);
  1150. $guser = GlobalUserInfo::toWebData($globalUserInfo,true);
  1151. $guser['reg'] = 1;
  1152. $defaultGameId = 931;
  1153. $recommendGame = '/game/' . $defaultGameId;
  1154. $guser['recommendGame'] = $recommendGame;
  1155. // 如果用户信息存在,根据GameID的最后一位数字查询映射关系
  1156. if ($guser && isset($guser['GameID'])) {
  1157. $gameId = (string)$guser['GameID'];
  1158. $lastDigit = (int)substr($gameId, -1); // 获取最后一位数字
  1159. // 查询映射关系(带缓存)
  1160. $cacheKey = 'game_number_mapping:' . $lastDigit;
  1161. $mapping = null;
  1162. $cacheHit = false;
  1163. // 尝试从缓存获取
  1164. $cached = Redis::get($cacheKey);
  1165. if ($cached !== null) {
  1166. $decoded = json_decode($cached, true);
  1167. // 如果解码成功且不是空数组,说明有数据
  1168. if (is_array($decoded) && !empty($decoded)) {
  1169. $mapping = (object)$decoded; // 转换为对象以保持兼容性
  1170. $cacheHit = true;
  1171. } elseif ($decoded === []) {
  1172. // 空数组表示数据库中没有记录,已缓存,直接跳过查询
  1173. $cacheHit = true;
  1174. $mapping = null;
  1175. }
  1176. }
  1177. // 缓存未命中,查询数据库
  1178. if (!$cacheHit) {
  1179. $mapping = DB::connection('write')
  1180. ->table('agent.dbo.game_number_mapping')
  1181. ->where('number', $lastDigit)
  1182. ->first();
  1183. // 存入缓存,24小时过期
  1184. if ($mapping) {
  1185. Redis::setex($cacheKey, 86400, json_encode($mapping));
  1186. } else {
  1187. // 即使不存在也缓存,避免频繁查询,缓存5分钟
  1188. Redis::setex($cacheKey, 300, json_encode([]));
  1189. }
  1190. }
  1191. if ($mapping && !empty($mapping) && isset($mapping->game_id) && $mapping->game_id) {
  1192. $defaultGameId = $mapping->game_id;
  1193. $recommendGame = '/game/' . $mapping->game_id;
  1194. }
  1195. $guser['recommendGame'] = $recommendGame;
  1196. }
  1197. AccountsInfo::where('UserID', $UserID)->update(['UserMedal' => $defaultGameId ]);
  1198. try {
  1199. FacebookEventService::trackCompleteRegistration($globalUserInfo,$config);
  1200. }catch (\Exception $e){
  1201. }
  1202. Util::WriteLog('register_params',[$request,$guser]);
  1203. return response()->json(apiReturnSuc($guser, ['reg.success', 'Registro realizado com sucesso!']));//->withCookie($this->setLoginCookie($guser['sign']));
  1204. }
  1205. public function registerAccountInfo(Request $request, $PackageName = 'com.uswin.game777', $Channel = 0,$account=null)
  1206. {
  1207. if (empty($Channel) || !$Channel) $Channel = env('REGION_24680_DEFAULT_CHANNEL',100);
  1208. //防止串行
  1209. $app=DB::connection('write')->table('QPPlatformDB.dbo.ChannelPackageName')->where('Channel', $Channel)->first();
  1210. if($app)$PackageName=$app->PackageName;
  1211. $FPID = $request->input("bfp", "");
  1212. $Accounts = $account??$FPID ?? $request->adid ?? $request->gaaid ?? md5(random_bytes(30));
  1213. $SpreadID = 0;
  1214. $Password = $request->password ?? md5(random_bytes(30));
  1215. $FaceI = mt_rand(1, 16);
  1216. $Gender = $request->gender ?? 0;
  1217. $InsurePass = "";
  1218. $Phone = $request->phone ?? "";
  1219. $ip = $request->header("X_REAL_IP") ?? $request->ip();
  1220. $MachineID = $Accounts;
  1221. $cbType = 1;
  1222. if (!empty($Phone)) {
  1223. $cbType = 2;
  1224. }
  1225. $res = StoredProcedure::ALLRegisterAccounts(
  1226. $Accounts,
  1227. '1',
  1228. $SpreadID,
  1229. $Password,
  1230. $InsurePass,
  1231. $FaceI,
  1232. $Gender,
  1233. 1,
  1234. $Phone,
  1235. $ip,
  1236. $MachineID,
  1237. $cbType,
  1238. $Channel,
  1239. $PackageName
  1240. );
  1241. Log::info('注册结果 ' . json_encode($res));
  1242. $ReturnValue = $res['ReturnValue'] ?? 0;
  1243. if (is_bool($res)) {
  1244. $ReturnValue = 3;
  1245. }
  1246. $message = '';
  1247. if ($ReturnValue > 0) {
  1248. switch ($ReturnValue) {
  1249. case 1: # 注册暂停
  1250. return apiReturnFail(['web.reg.fail_suspend', 'Registro suspenso']);
  1251. break;
  1252. case 2: # 登录暂停
  1253. return apiReturnFail(['web.reg.fail_stoplogin', 'Pausa de login']);
  1254. break;
  1255. case 3: # 登录暂停
  1256. return apiReturnFail(['web.withdraw.try_again_later', 'Pausa de login']);
  1257. break;
  1258. case 201: # accounts已经存在
  1259. case 301:
  1260. case 8: # 帐号已存在,请换另一帐号名字尝试再次注册!
  1261. $exist_user = AccountsInfo::where('Accounts', $Accounts . $Channel)->first();
  1262. if ($exist_user) {
  1263. $isexitGuser = GlobalUserInfo::getGameUserInfo('UserID', $exist_user->UserID);
  1264. if ($isexitGuser) {
  1265. return apiReturnFail(['web.reg.fail_account_exist', 'A conta já existe, altere outro nome de conta e tente se registrar novamente!'],compact('res','Accounts'));
  1266. } else {
  1267. $res = $exist_user;
  1268. }
  1269. } else {
  1270. return apiReturnFail(['web.withdraw.try_again_later', 'Pausa de login']);
  1271. }
  1272. break;
  1273. case 10: # IP最大注册数量
  1274. return apiReturnFail(['web.reg.fail_ipmax', 'Mesmo IP não pode registrar várias contas']);
  1275. break;
  1276. }
  1277. }
  1278. Util::WriteLog('login', $res);
  1279. // $user=AccountsInfo::query()->where("Accounts",$Accounts)->first();
  1280. // Util::WriteLog('login',$user);
  1281. return $res;
  1282. }
  1283. protected function setLoginCookie($encryptedGlobalUID)
  1284. {
  1285. // $encryptedGlobalUID = Crypt::encryptString($GlobalUID);
  1286. $cookie = Cookie::make('guuid', $encryptedGlobalUID, 60 * 24 * 365, "/", null, true, false, false, 'None');
  1287. return $cookie;
  1288. }
  1289. static public function clearLoginCookie()
  1290. {
  1291. $cookie = Cookie::make('guuid', "", -60, "/", null, true, false, false, 'None');
  1292. return $cookie;
  1293. }
  1294. }