manghe/app/api/controller/Login.php
2025-05-22 13:24:18 +08:00

1125 lines
42 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;
use app\common\helper\EnvHelper;
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');
$wxPlatform = \app\common\server\platform\PlatformFactory::create();
$openInfo = $wxPlatform->getOpenid($code);
if ($openInfo['status'] == 0) {
return $this->renderError($openInfo['msg']);
}
$openid = $openInfo['data']['openid'];
$wx_unionid = null;
if (isset($openInfo['data']['unionid'])) {
$wx_unionid = $openInfo['data']['unionid'];
}
// 添加Redis防抖锁
$redis = (new RedisHelper())->getRedis();
$lockKey = 'login:debounce:' . $openid;
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 3])) {
$logMessages[] = '用户登录请求过于频繁: ' . $openid;
Log::warning(end($logMessages));
return $this->renderError('请勿频繁登录,请稍后再试');
}
$user = null;
if ($wx_unionid != null && $wx_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) {
Log::error('登录失败->错误信息' . $e->getMessage());
Log::error('登录失败->错误行数' . $e->getLine());
return $this->renderError("登录失败");
}
}
/**
* 微信授权-公众号登录
*/
public function h5login()
{
try {
$code = request()->param("code", '');
if (empty($code)) {
return $this->renderError('请求参数错误');
}
$click_id = request()->header('clickid');
$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;
// 添加Redis防抖锁
$redis = (new RedisHelper())->getRedis();
$lockKey = 'login:h5:debounce:' . $openid;
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 3])) {
Log::warning('用户公众号登录请求过于频繁: ' . $openid);
return $this->renderError('请勿频繁登录,请稍后再试');
}
$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 {
}
$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,
]);
// 记录用户登录日志(每天只记录一次)
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' => '',
]);
$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('非法请求');
}
}
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();
$user_id = $user['id'];
$code = request()->param("code", '');
$wxPlatform = \app\common\server\platform\PlatformFactory::create();
$mobileRes = $wxPlatform->getMobile($code);
if ($mobileRes['status'] == 0) {
return $this->renderError($mobileRes['msg']);
}
if (!isset($mobileRes['data']['phoneNumber'])) {
return $this->renderError('获取手机号失败');
}
$mobile = $mobileRes['data']['phoneNumber'];
Db::startTrans();
$res = [];
$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;
} else {
$res[] = User::where(['id' => $user['id']])->update([
'mobile' => $mobile,
'update_time' => time(),
]);
}
if (resCheck($res)) {
Db::commit();
return $this->renderSuccess("绑定成功2", $data);
} else {
Db::rollback();
return $this->renderSuccess("绑定成功3");
}
}
/**
* 绑定手机号
*/
public function login_bind_mobile_h5()
{
$user = $this->getUser();
$user_id = $user['id'];
$mobile = request()->param("mobile", '');
Db::startTrans();
$res = [];
$res[] = User::where(['id' => $user_id])->update([
'mobile' => $mobile,
'update_time' => time(),
]);
if (resCheck($res)) {
Db::commit();
return $this->renderSuccess("绑定成功2");
} else {
Db::rollback();
return $this->renderSuccess("绑定成功3");
}
}
/**
*
*
* @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_id = $this->getUserid1();
// //去redis中查询一下如果存在今日的数据则不在往下执行
// $redis = (new RedisHelper())->getRedis();
// $today = date('Y-m-d');
// $redis_key = "login_record:" . $today . ":" . $user_id;
// $redis_data = $redis->get($redis_key);
// if ($redis_data) {
// return $this->renderSuccess('登录记录成功');
// }
$user = $this->getUser();
if (empty($user)) {
return $this->renderError('用户不存在');
}
// 获取设备信息
$device = request()->param('device', ''); // 设备类型
$device_info = request()->param('device_info', ''); // 设备详细信息
if ($device == "") {
$device = request()->header('client');
}
// 获取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;
}
$user_id = $user['id'];
// $isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
// if ($isTest == "1") {
// // 使用Redis锁防止重复获取
// $redis = (new RedisHelper())->getRedis();
// $lockKey = 'user:beta_reward:' . $user_id;
// if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
// $userCount = ProfitMoney::where('user_id', $user_id)
// ->where('type', 8)
// ->where('content', '=', '内测免费送')
// ->count();
// if ($userCount == 0) {
// try {
// $res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
// } finally {
// // 释放锁
// $redis->del($lockKey);
// }
// }
// }
// }
// 记录登录日志
UserLoginLog::recordLogin(
$user['id'],
$device,
$ip,
$location
);
// //将数据写入redis,过期时间为当天剩余的时间
// $redis->set($redis_key, json_encode($user), 86400 - time() % 86400);
return $this->renderSuccess('登录成功', [
'uid' => $user['uid'] ?: $user['id'],
'nickname' => $user['nickname'],
'headimg' => imageUrl($user['headimg'])
]);
} catch (\Exception $e) {
Log::error('记录登录错误: ' . $e->getMessage());
Log::error('错误行数: ' . $e->getLine());
return $this->renderError('网络故障,请稍后再试');
}
}
/**
* 手机号登录接口
*/
public function mobileLogin()
{
// 初始化日志收集变量
$logMessages = [];
try {
// 获取请求参数
$mobile = request()->param("mobile", '');
$code = request()->param("code", '');
$pid_pid = request()->param('pid', 0);
// 验证必要参数
if (empty($mobile) || empty($code)) {
$logMessages[] = '手机号或验证码为空: ' . $mobile;
Log::error(end($logMessages));
return $this->renderError('请求参数错误');
}
$logMessages[] = '用户开始手机号登录: ' . $mobile;
$click_id = request()->header('clickid');
// 验证手机验证码
$redis = (new RedisHelper())->getRedis();
$redisKey = "VerificationCode:{$mobile}";
$redisCode = $redis->get($redisKey);
$is_test = EnvHelper::getIsTest();
if (!$is_test) {
if (empty($redisCode) || $redisCode != $code) {
$logMessages[] = '验证码错误: ' . $code . ',正确验证码: ' . $redisCode . '==>' . $mobile;
Log::error(end($logMessages));
return $this->renderError('验证码错误');
}
}
// 验证通过后删除Redis中的验证码
$redis->del($redisKey);
// 添加Redis防抖锁
$lockKey = 'login:mobile:debounce:' . $mobile;
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 3])) {
$logMessages[] = '用户手机号登录请求过于频繁: ' . $mobile;
Log::warning(end($logMessages));
return $this->renderError('请勿频繁登录,请稍后再试');
}
// 检查用户是否已存在
$user = User::getInfo(['mobile' => $mobile]);
// 如果用户已存在
if ($user) {
if ($user['click_id'] != $click_id) {
$res[] = User::where(['id' => $user['id']])->update(['click_id' => $click_id]);
}
// 检查并生成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'];
}
// 检查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'],
'mobile',
$last_login_ip1,
''
);
$logMessages[] = '用户手机号登录成功: ' . $mobile . ' 用户ID: ' . $user['id'];
// 输出收集的所有日志
Log::info(implode("==》", $logMessages));
return $this->renderSuccess("登录成功", $account_token);
} else {
// 用户不存在,创建新用户
$pid = 0;
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();
// 生成随机昵称和头像
$randx = rand(1000, 9999);
$nickname = "手机用户" . $randx;
$logMessages[] = $nickname;
// 使用Identicon生成默认头像
$randx = rand(10000, 99999);
$identicon = new \Identicon\Identicon();
$imageData = $identicon->getImageData($mobile . $nickname);
$uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png");
$headimg = $uploadResult['full_url'];
// 插入用户记录
$res[] = $user_id = User::insertGetId([
'openid' => '', // 手机号注册无openid
'mobile' => $mobile,
'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]);
}
// 如果是测试环境,给新用户赠送钻石
// $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);
// }
// }
// }
// 生成账号token
$time = time();
$token_num = getRandStr(10);
$account_token = user_md5($user_id . $token_num . $time);
// 获取IP和地理位置信息
$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'];
}
// 插入用户账号信息
$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,
'mobile:v1.0.0',
$last_login_ip1,
''
);
$logMessages[] = '==》用户手机号注册成功: ' . $mobile . ' 用户ID: ' . $user_id;
// 输出收集的所有日志
Log::info(implode("==>", $logMessages));
Db::commit();
return $this->renderSuccess("登录成功", $account_token);
} else {
Db::rollback();
$logMessages[] = '==》用户手机号注册失败: ' . $mobile . ' 用户ID: ' . $user_id;
// 输出收集的所有日志
Log::info(implode("==>", $logMessages));
return $this->renderError("登录失败");
}
}
} catch (\Exception $e) {
Log::error('手机号登录失败->错误信息' . $e->getMessage());
Log::error('手机号登录失败->错误行数' . $e->getLine());
return $this->renderError("登录失败");
}
}
}