manghe/app/api/controller/Login.php
2025-04-19 16:17:04 +08:00

942 lines
34 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace app\api\controller;
use app\api\controller\Base;
use app\common\model\User;
use app\common\model\UserAccount;
use app\common\server\RedisHelper;
use \think\Request;
use think\facade\Db;
use app\common\model\ProfitDraw;
use app\common\model\UserLoginIp;
use app\common\model\UserLoginLog;
use think\facade\Log;
use app\common\server\TencentCosUploader;
use app\common\model\ProfitMoney;
class Login extends Base
{
private $uploader;
public function initialize()
{
parent::initialize(); // 确保调用父类初始化方法
$config = getConfig('uploads');
if (!$config) {
$config = []; // 确保config是一个数组
}
$this->uploader = new TencentCosUploader($config);
}
/**
* 处理用户的UID
*
* @param User $user 用户对象
*/
private function processUid($user)
{
// 如果用户已有uid不处理
if (!empty($user['uid'])) {
return;
}
// 生成uid
$uid = $this->generateUid($user['id']);
if ($uid) {
// 更新用户uid
User::where('id', $user['id'])->update(['uid' => $uid]);
}
}
/**
* 生成用户UID
*
* @param int $user_id 用户ID
* @return string 生成的UID
*/
private function generateUid($user_id)
{
// 获取用户uid配置
$user_config = getConfig('user_config');
if (empty($user_config) || !isset($user_config['uid_type'])) {
return (string) $user_id; // 默认使用真实ID
}
$uid_type = (int) $user_config['uid_type'];
$uid_length = isset($user_config['uid_length']) ? (int) $user_config['uid_length'] : 6;
// 限制长度范围
if ($uid_length < 4) {
$uid_length = 4;
} elseif ($uid_length > 16) {
$uid_length = 16;
}
// 根据不同类型生成UID
switch ($uid_type) {
case 0: // 真实ID
return (string) $user_id;
case 1: // 数字ID
// 生成不以0开头的随机数字
$max_attempts = 10;
$attempt = 0;
while ($attempt < $max_attempts) {
// 生成随机数字
$min = pow(10, $uid_length - 1);
$max = pow(10, $uid_length) - 1;
$uid = (string) mt_rand($min, $max);
// 检查是否唯一
$exists = User::where('uid', $uid)->count();
if ($exists == 0) {
return $uid;
}
$attempt++;
}
// 如果多次尝试后仍无法生成唯一ID则使用更可靠的方法
return $this->generateUniqueNumericId($uid_length);
case 2: // 随机字符和数字
$length = max(8, $uid_length); // 字母数字混合至少8位
$max_attempts = 10;
$attempt = 0;
while ($attempt < $max_attempts) {
// 生成随机字母数字
$characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // 排除容易混淆的字符
$uid = '';
// 确保第一个字符不是数字
$uid .= $characters[mt_rand(8, strlen($characters) - 1)]; // 从字母开始
// 生成剩余字符
for ($i = 1; $i < $length; $i++) {
$uid .= $characters[mt_rand(0, strlen($characters) - 1)];
}
// 检查是否唯一
$exists = User::where('uid', $uid)->count();
if ($exists == 0) {
return $uid;
}
$attempt++;
}
// 如果多次尝试后仍无法生成唯一ID使用时间戳+随机数确保唯一性
return $this->generateUniqueAlphaNumId($length);
default:
return (string) $user_id;
}
}
/**
* 生成唯一的数字ID备用方法
*/
private function generateUniqueNumericId($length)
{
// 使用时间微秒 + 随机数的方式保证唯一性
$base = microtime(true) * 10000 . mt_rand(1000, 9999);
$uid = substr(preg_replace('/[^0-9]/', '', $base), 0, $length);
// 确保不以0开头且长度正确
while (strlen($uid) < $length || $uid[0] == '0') {
$uid = mt_rand(1, 9) . substr($uid, 1);
$uid = substr($uid, 0, $length);
}
return $uid;
}
/**
* 生成唯一的字母数字ID备用方法
*/
private function generateUniqueAlphaNumId($length)
{
// 使用时间戳 + 随机字符
$base = time() . mt_rand(1000, 9999);
$hash = md5($base);
// 转换为字母数字混合
$uid = '';
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // 排除容易混淆的字符
// 确保第一个字符是字母
$uid .= $chars[mt_rand(0, 25)]; // 前26个是字母
// 生成剩余字符
for ($i = 1; $i < $length; $i++) {
$uid .= $chars[mt_rand(0, strlen($chars) - 1)];
}
return $uid;
}
/**
* 微信授权,登录接口
*/
public function login()
{
// 初始化日志收集变量
$logMessages = [];
try {
$code = request()->param("code", '');
if (empty($code)) {
$logMessages[] = '用户未获取到code:' . $code;
Log::error(end($logMessages));
return $this->renderError('请求参数错误');
}
$logMessages[] = '用户开始登录: ' . $code;
$click_id = request()->header('clickid');
$wxServer = new \app\common\server\Wx($this->app);
$user_base = $wxServer->getOpenid($code);
$openid = $user_base['openid'];
$user = null;
$wx_unionid = null;
if ($user_base['unionid'] != null && $user_base['unionid'] != '') {
$wx_unionid = $user_base['unionid'];
$user = User::getInfo(['unionid' => $wx_unionid]);
}
if ($user == null) {
$user = User::getInfo(['openid' => $openid]);
}
// return $this->renderSuccess("登录成功", $user);
if ($user) {
if ($user['click_id'] != $click_id) {
$res[] = User::where(['id' => $user['id']])->update(['click_id' => $click_id]);
}
//设置unionId
if ($wx_unionid && !empty($wx_unionid)) {
$unionid = $user['unionid'];
if ($unionid == null || empty($unionid)) {
$user['unionid'] = $wx_unionid;
// User::update($user);
$user->save();
}
}
// 检查并生成uid
$this->processUid($user);
#token时间戳
$time = time();
#token字符串
$token_num = getRandStr(10);
#加密token
$account_token = user_md5($user['id'] . $token_num . $time);
#更新账号信息
$last_login_ip1 = $this->getRealIp();
$result = $this->ip_location($last_login_ip1);
$ip_province = '';
$ip_city = '';
$ip_adcode = '';
if ($result) {
$ip_province = $result['province'];
$ip_city = $result['city'];
$ip_adcode = $result['adcode'];
} else {
}
// 检查UserAccount是否存在
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
if ($userAccount) {
// 存在则更新
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
'account_token' => $account_token,
'token_num' => $token_num,
'token_time' => $time,
'last_login_time' => $time,
'last_login_ip' => ip2long($last_login_ip1),
'last_login_ip1' => $last_login_ip1,
'ip_adcode' => $ip_adcode,
'ip_province' => $ip_province,
'ip_city' => $ip_city,
]);
} else {
// 不存在则新增
$res[] = UserAccount::insert([
'user_id' => $user['id'],
'account_token' => $account_token,
'token_num' => $token_num,
'token_time' => $time,
'last_login_time' => $time,
'last_login_ip' => ip2long($last_login_ip1),
'last_login_ip1' => $last_login_ip1,
'ip_adcode' => $ip_adcode,
'ip_province' => $ip_province,
'ip_city' => $ip_city,
]);
}
// 记录用户登录日志(每天只记录一次)
UserLoginLog::recordLogin(
$user['id'],
'wechat',
$last_login_ip1,
''//$ip_province . $ip_city
);
$logMessages[] = '用户登录成功: ' . $code . ' 用户ID: ' . $user['id'] . '用户手机号' . $user['mobile'];
// 输出收集的所有日志
Log::info(implode("==》", $logMessages));
return $this->renderSuccess("登录成功", $account_token);
} else {
$nickname = request()->param('nickname', '');
$headimg = request()->param('headimg', '');
// if (!$nickname) {
// return $this->renderError('请求参数错误!');
// }
$pid = 0;
$pid_pid = request()->param('pid', 0);
$randx = rand(1000, 9999);
$nickname = "微信用户" . $randx;
$logMessages[] = $nickname;
$randx = rand(10000, 99999);
$identicon = new \Identicon\Identicon();
$imageData = $identicon->getImageData($openid . $nickname);
$uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png");
$headimg = $uploadResult['full_url'];
if ($pid_pid) {
$logMessages[] = "尝试获取推荐人ID: " . $pid_pid;
$pid_info = User::where('id', '=', $pid_pid)->value("id");
if ($pid_info) {
$logMessages[] = "获取推荐人ID成功: " . $pid_info;
$pid = $pid_info;
}
}
Db::startTrans();
$res[] = $user_id = User::insertGetId([
'openid' => $openid,
'nickname' => $nickname,
'headimg' => $headimg,
'pid' => $pid,
'addtime' => time(),
'click_id' => $click_id,
'unionid' => $wx_unionid,
'uid' => '',
]);
// 生成用户uid
$uid = $this->generateUid($user_id);
if ($uid) {
User::where('id', $user_id)->update(['uid' => $uid]);
}
$isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
if ($isTest == "1") {
$userCount = ProfitMoney::where('user_id', $user_id)
->where('type', 8)
->where('content', '=', '内测免费送')
->count();
if ($userCount == 0) {
// 使用Redis锁防止重复获取
$redis = (new RedisHelper())->getRedis();
$lockKey = 'user:beta_reward:' . $user_id;
if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
$logMessages[] = '赠送钻石: 50000';
// 释放锁
$redis->del($lockKey);
}
}
}
$time = time();
#token字符串
$token_num = getRandStr(10);
#加密token
$account_token = user_md5($user_id . $token_num . $time);
#更新账号信息
$last_login_ip1 = $this->getRealIp();
$result = $this->ip_location($last_login_ip1);
$ip_province = '';
$ip_city = '';
$ip_adcode = '';
if ($result) {
$ip_province = $result['province'];
$ip_city = $result['city'];
$ip_adcode = $result['adcode'];
} else {
}
$res[] = UserAccount::insert([
'user_id' => $user_id,
'account_token' => $account_token,
'token_num' => $token_num,
'token_time' => $time,
'last_login_time' => $time,
'last_login_ip' => ip2long($last_login_ip1),
'last_login_ip1' => $last_login_ip1,
'ip_adcode' => $ip_adcode,
'ip_province' => $ip_province,
'ip_city' => $ip_city,
]);
#记录登录日志
#推荐成功之后获取一张抽奖券
#配置
$rule = getConfig('base');
$draw_people_num = $rule['draw_people_num'];
if (!empty($pid)) {
$num = 0;
$num = ProfitDraw::where(['type' => 5, 'user_id' => $pid, 'share_uid' => $user_id])->count();
if (bccomp("$num", "$draw_people_num") < 0) {
#可以获得一张抽奖券
$res[] = User::changeDraw($pid, 1, 5, '获得一张抽奖券', $user_id);
}
}
if (resCheck($res)) {
// 新用户注册也要记录登录日志
UserLoginLog::recordLogin(
$user_id,
'wechat:v1.0.0',
$last_login_ip1,
''//$ip_province . $ip_city
);
$logMessages[] = '==》用户注册成功: ' . $code . ' 用户ID: ' . $user_id;
// 输出收集的所有日志
Log::info(implode("==>", $logMessages));
Db::commit();
return $this->renderSuccess("登录成功", $account_token);
} else {
Db::rollback();
$logMessages[] = '==》用户注册失败: ' . $code . ' 用户ID: ' . $user_id;
// 输出收集的所有日志
Log::info(implode("==>", $logMessages));
return $this->renderError("登录失败");
}
}
} catch (\Exception $e) {
$logMessages[] = '登录失败->错误信息: ' . $e->getMessage();
$logMessages[] = '登录失败->错误行数: ' . $e->getLine();
// 输出收集的错误日志
Log::error(implode("==>", $logMessages));
return $this->renderError("登录失败");
}
}
/**
* 微信授权
*/
public function h5login()
{
// 获取请求参数
$code = request()->param("code", '');
if (empty($code)) {
return $this->renderError('请求参数错误');
}
$click_id = request()->header('clickid');
// 使用Redis全局锁防止并发请求
$redis = (new RedisHelper())->getRedis();
$lockKey = 'global:h5login:lock:' . md5($code . $click_id);
// 尝试获取锁设置过期时间为30秒
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 30])) {
// 如果获取锁失败,表示有并发请求正在处理
return $this->renderError('登录请求处理中,请稍后再试');
}
try {
$wxServer = new \app\common\server\WechatOfficialAccount($this->app);
$user_base = $wxServer->getAccessToken($code);
// $user_base_info = $wxServer->getUserInfo($user_base);
$retrieved_openid = $user_base['openid'];
$openid = $retrieved_openid;
$user = null;
if ($user_base['unionid'] != null && $user_base['unionid'] != '') {
$unionid = $user_base['unionid'];
$user = User::getInfo(['unionid' => $unionid]);
if ($user != null) {
// $user
if ($user['gzh_openid'] == null || $user['gzh_openid'] != $retrieved_openid) {
$user['gzh_openid'] = $retrieved_openid;
$user->save();
}
}
}
if ($user == null) {
$user = User::getInfo(['openid' => $openid]);
}
// return $this->renderSuccess("登录成功", $user);
if ($user) {
if ($user['click_id'] != $click_id) {
$res[] = User::where(['id' => $user['id']])->update(['click_id' => $click_id]);
}
#token时间戳
$time = time();
#token字符串
$token_num = getRandStr(10);
#加密token
$account_token = user_md5($user['id'] . $token_num . $time);
#更新账号信息
$last_login_ip1 = $this->getRealIp();
$result = $this->ip_location($last_login_ip1);
$ip_province = '';
$ip_city = '';
$ip_adcode = '';
if ($result) {
$ip_province = $result['province'];
$ip_city = $result['city'];
$ip_adcode = $result['adcode'];
} else {
}
// 检查UserAccount是否存在
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
if ($userAccount) {
// 存在则更新
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
'account_token' => $account_token,
'token_num' => $token_num,
'token_time' => $time,
'last_login_time' => $time,
'last_login_ip' => ip2long($last_login_ip1),
'last_login_ip1' => $last_login_ip1,
'ip_adcode' => $ip_adcode,
'ip_province' => $ip_province,
'ip_city' => $ip_city,
]);
} else {
// 不存在则新增
$res[] = UserAccount::insert([
'user_id' => $user['id'],
'account_token' => $account_token,
'token_num' => $token_num,
'token_time' => $time,
'last_login_time' => $time,
'last_login_ip' => ip2long($last_login_ip1),
'last_login_ip1' => $last_login_ip1,
'ip_adcode' => $ip_adcode,
'ip_province' => $ip_province,
'ip_city' => $ip_city,
]);
}
// 记录用户登录日志(每天只记录一次)
UserLoginLog::recordLogin(
$user['id'],
'wechat_h5',
$last_login_ip1,
$ip_province . $ip_city
);
return $this->renderSuccess("登录成功", $account_token);
} else {
$userinfo = $wxServer->getUserInfo($user_base);
$nickname = $userinfo['nickname'];
$headimg = $userinfo['headimgurl'];
if (!$nickname || !$headimg) {
return $this->renderError('请求参数错误!');
}
$pid = 0;
$pid_pid = request()->param('pid', 0);
if ($pid_pid > 0) {
log::info("获取推荐人id" . $pid_pid);
}
if ($pid_pid) {
$pid_info = User::where('id', '=', $pid_pid)->value("id");
if ($pid_info) {
log::info("获取推荐人id" . $pid_info);
$pid = $pid_info;
}
}
Db::startTrans();
$res[] = $user_id = User::insertGetId([
'openid' => $openid,
'nickname' => $nickname,
'headimg' => $headimg,
'pid' => $pid,
'addtime' => time(),
'click_id' => $click_id,
'uid' => '',
]);
// 生成用户uid
$uid = $this->generateUid($user_id);
if ($uid) {
User::where('id', $user_id)->update(['uid' => $uid]);
}
$time = time();
#token字符串
$token_num = getRandStr(10);
#加密token
$account_token = user_md5($user_id . $token_num . $time);
#更新账号信息
$last_login_ip1 = $this->getRealIp();
$result = $this->ip_location($last_login_ip1);
$ip_province = '';
$ip_city = '';
$ip_adcode = '';
if ($result) {
$ip_province = $result['province'];
$ip_city = $result['city'];
$ip_adcode = $result['adcode'];
} else {
}
$res[] = UserAccount::insert([
'user_id' => $user_id,
'account_token' => $account_token,
'token_num' => $token_num,
'token_time' => $time,
'last_login_time' => $time,
'last_login_ip' => ip2long($last_login_ip1),
'last_login_ip1' => $last_login_ip1,
'ip_adcode' => $ip_adcode,
'ip_province' => $ip_province,
'ip_city' => $ip_city,
]);
#记录登录日志
#推荐成功之后获取一张抽奖券
#配置
$rule = getConfig('base');
$draw_people_num = $rule['draw_people_num'];
if (!empty($pid)) {
$num = 0;
$num = ProfitDraw::where(['type' => 5, 'user_id' => $pid, 'share_uid' => $user_id])->count();
if (bccomp("$num", "$draw_people_num") < 0) {
#可以获得一张抽奖券
$res[] = User::changeDraw($pid, 1, 5, '获得一张抽奖券', $user_id);
}
}
if (resCheck($res)) {
// 新用户注册也要记录登录日志
UserLoginLog::recordLogin(
$user_id,
'wechat_h5',
$last_login_ip1,
$ip_province . $ip_city
);
Db::commit();
return $this->renderSuccess("登录成功", $account_token);
} else {
Db::rollback();
return $this->renderError("登录失败");
}
}
} catch (\Exception $e) {
Log::error('错误信息' . $e->getMessage());
Log::error('错误行数' . $e->getLine());
return $this->renderError('非法请求');
} finally {
// 确保释放锁
$redis->del($lockKey);
}
}
public function ip_location($last_login_ip)
{
if ($last_login_ip) {
$url = "https://restapi.amap.com/v3/ip?key=2bf9bdfeb03a8835ce324443eb18e4da&ip=" . "$last_login_ip" . "";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result, true);
if ($result['status'] == '1') {
return $result;
} else {
return false;
}
} else {
return false;
}
}
/**
* 绑定手机号
*/
public function login_bind_mobile()
{
$user = $this->getUser();
if (empty($user)) {
return $this->renderError('用户不存在');
}
$user_id = $user['id'];
$code = request()->param("code", '');
if (empty($code)) {
return $this->renderError('参数错误缺少code');
}
// 使用Redis全局锁防止并发绑定请求
$redis = (new RedisHelper())->getRedis();
$lockKey = 'global:bind_mobile:lock:' . $user_id;
// 尝试获取锁设置过期时间为20秒
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 20])) {
// 如果获取锁失败,表示有并发请求正在处理
return $this->renderError('绑定请求处理中,请稍后再试');
}
try {
$wxServer = new \app\common\server\Wx($this->app);
$mobile = $wxServer->getMobile($code);
// return $this->renderError($mobile,[$mobile,$code]);
Db::startTrans();
$res = [];
// $res[] = User::where(['id' => $user['id']])->update([
// 'mobile' => $mobile,
// 'update_time' => time(),
// ]);
$data = [];
$user_mobile = User::where(['mobile' => $mobile])->find();
if ($user_mobile) {
$old_user_account = UserAccount::where(['user_id' => $user_id])->find();
#修改openid
$res[] = User::where(['id' => $user_mobile['id']])
->update([
'openid' => $user['openid'],
// 'nickname' => $user['nickname'],
// 'headimg' => $user['headimg'],
]);
$time = time();
#token字符串
$token_num = getRandStr(10);
#加密token
$account_token = user_md5($user_mobile['id'] . $token_num . $time);
#修改token
$res[] = UserAccount::where(['user_id' => $user_mobile['id']])->update([
'account_token' => $account_token,
'token_num' => $token_num,
'token_time' => $time,
'last_login_time' => $old_user_account['last_login_time'],
'last_login_ip' => $old_user_account['last_login_ip'],
]);
#修改
$res[] = User::where(['id' => $user['id']])->delete();
$res[] = UserAccount::where(['user_id' => $user_id])->delete();
$data['token'] = $account_token;
// $res[] = UserAccount::where(['user_id' => $user['id']])->update([
// 'token_time' => time(),
// ]);
} else {
$res[] = User::where(['id' => $user['id']])->update([
'mobile' => $mobile,
'update_time' => time(),
]);
}
if (resCheck($res)) {
Db::commit();
return $this->renderSuccess("绑定成功", $data);
} else {
Db::rollback();
return $this->renderError("绑定失败");
}
} catch (\Exception $e) {
Db::rollback();
Log::error('绑定手机号错误: ' . $e->getMessage());
Log::error('错误行数: ' . $e->getLine());
return $this->renderError('绑定失败: ' . $e->getMessage());
} finally {
// 确保释放锁
$redis->del($lockKey);
}
}
/**
* 绑定手机号
*/
public function login_bind_mobile_h5()
{
$user = $this->getUser();
if (empty($user)) {
return $this->renderError('用户不存在');
}
$user_id = $user['id'];
$mobile = request()->param("mobile", '');
if (empty($mobile)) {
return $this->renderError('请输入手机号');
}
// 使用Redis全局锁防止并发绑定请求
$redis = (new RedisHelper())->getRedis();
$lockKey = 'global:bind_mobile_h5:lock:' . $user_id;
// 尝试获取锁设置过期时间为10秒
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 10])) {
// 如果获取锁失败,表示有并发请求正在处理
return $this->renderError('绑定请求处理中,请稍后再试');
}
try {
Db::startTrans();
$res = [];
$res[] = User::where(['id' => $user_id])->update([
'mobile' => $mobile,
'update_time' => time(),
]);
if (resCheck($res)) {
Db::commit();
return $this->renderSuccess("绑定成功");
} else {
Db::rollback();
return $this->renderError("绑定失败");
}
} catch (\Exception $e) {
Db::rollback();
Log::error('绑定手机号H5错误: ' . $e->getMessage());
Log::error('错误行数: ' . $e->getLine());
return $this->renderError('绑定失败: ' . $e->getMessage());
} finally {
// 确保释放锁
$redis->del($lockKey);
}
}
/**
*
*
* @return mixed
*/
public function getAccessTokenOffiaccountSign()
{
$wxServer = new \app\common\server\WechatOfficialAccount($this->app);
$url = request()->param("url", '');
$data = $wxServer->getAccessTokenOffiaccountSign($url);
return $this->renderSuccess('', $data);
}
/**
* 记录用户登录
* 小程序每次打开时调用此方法记录登录信息
*/
public function recordLogin()
{
try {
// 获取用户信息
$user = $this->getUser();
if (empty($user)) {
return $this->renderError('用户不存在');
}
$user_id = $user['id'];
// 使用Redis全局锁防止并发请求
$redis = (new RedisHelper())->getRedis();
$lockKey = 'global:record_login:lock:' . $user_id;
// 尝试获取锁设置过期时间为10秒
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 10])) {
// 如果获取锁失败,直接返回成功,避免用户等待
return $this->renderSuccess('登录成功', [
'uid' => $user['uid'] ?: $user['id'],
'nickname' => $user['nickname'],
'headimg' => imageUrl($user['headimg'])
]);
}
try {
// 获取设备信息
$device = request()->param('device', ''); // 设备类型
$device_info = request()->param('device_info', ''); // 设备详细信息
// 获取IP和地理位置信息
$ip = $this->getRealIp();
$location = '';
$ip_province = '';
$ip_city = '';
$ip_adcode = '';
$result = $this->ip_location($ip);
if ($result) {
$ip_province = $result['province'];
$ip_city = $result['city'];
$ip_adcode = $result['adcode'];
$location = $ip_province . $ip_city;
}
$isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
if ($isTest == "1") {
// 使用全局 Redis 锁防止重复获取内测奖励
$bonusLockKey = 'global:bonus:lock:' . $user_id;
if ($redis->set($bonusLockKey, 1, ['nx', 'ex' => 60])) {
try {
$userCount = ProfitMoney::where('user_id', $user_id)
->where('type', 8)
->where('content', '=', '内测免费送')
->count();
if ($userCount == 0) {
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
}
} finally {
// 释放内测奖励锁
$redis->del($bonusLockKey);
}
}
}
// 记录登录日志
UserLoginLog::recordLogin(
$user['id'],
$device,
$ip,
$location
);
return $this->renderSuccess('登录成功', [
'uid' => $user['uid'] ?: $user['id'],
'nickname' => $user['nickname'],
'headimg' => imageUrl($user['headimg'])
]);
} finally {
// 确保释放锁
$redis->del($lockKey);
}
} catch (\Exception $e) {
Log::error('记录登录错误: ' . $e->getMessage());
Log::error('错误行数: ' . $e->getLine());
return $this->renderError('网络故障,请稍后再试');
}
}
}